TV ハードウェアに対応する

TV のハードウェアは、他の Android 端末とは大きく異なります。TV には、タッチスクリーン、カメラ、GPS 受信機など、他の Android 端末でよく使われるハードウェア機能がありません。そして TV は、2 次ハードウェア端末に完全に依存しています。つまり、ユーザーはリモコンやゲーム機のコントローラで TV アプリを操作する必要があります。TV アプリをビルドする際は、ハードウェア上の制限や TV 向けハードウェアの操作要件を慎重に考慮する必要があります。

このレッスンでは、TV でアプリが正常に動作するかどうかチェックする方法や、サポートされていないハードウェア機能を処理する方法、そして TV 端末用のコントローラを処理するための要件について説明します。

TV 端末をチェックする

TV 端末とその他の端末の両方で動作するアプリを作成している場合、アプリを実行する端末の種類をチェックし、アプリの動作を調整する必要があります。たとえば、Intent で起動するアプリの場合、テレビ向けのアクティビティを起動するか、スマートフォン向けのアクティビティを起動するかを判断するために、アプリ側で端末のプロパティをチェックする必要があります。

TV 端末でアプリが正常に動作するかどうかを判断するには、UiModeManager.getCurrentModeType() メソッドを使用して、その端末がアプリの TV モードで正常に動作するかどうかをチェックすることをお勧めします。次のコード例では、TV 端末でアプリが正常に動作するかどうかチェックする方法を示します。

public static final String TAG = "DeviceTypeRuntimeCheck";

UiModeManager uiModeManager = (UiModeManager) getSystemService(UI_MODE_SERVICE);
if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
    Log.d(TAG, "Running on a TV Device")
} else {
    Log.d(TAG, "Running on a non-TV Device")
}

サポートされていないハードウェア機能を処理する

アプリのデザインと機能によっては、特定のハードウェア機能を利用できないという事態を回避できる場合があります。このセクションでは、一般的に TV で使用できないハードウェア機能や、それらを検出する方法、そしてそれらの機能の代替案について説明します。

サポートされていない TV ハードウェア機能

TV には他の端末と異なる用途がありますので、他の Android 端末で提供されることの多いハードウェア機能がない場合があります。このため、Android システムは TV 端末では次の機能をサポートしていません。

ハードウェア Android の機能記述子
タッチスクリーン android.hardware.touchscreen
タッチスクリーン エミュレータ android.hardware.faketouch
電話 android.hardware.telephony
カメラ android.hardware.camera
近距離無線通信(NFC) android.hardware.nfc
GPS android.hardware.location.gps
マイク [1] android.hardware.microphone
センサー android.hardware.sensor
縦向きの画面 android.hardware.screen.portrait

[1] 一部の TV コントローラにはマイクがありますが、ここで説明するマイクのハードウェア機能と同じものではありません。コントローラのマイクは完全にサポートされます。

機能、サブ機能、それらの記述子の完全なリストについては、機能リファレンスをご覧ください。

TV のハードウェア要件を宣言する

Android アプリでは、機能提供がない端末にインストールされてしまわないように、アプリのマニフェストでハードウェア機能の要件を宣言できます。TV 向けに既存のアプリを拡張している場合は、TV 端末へのインストールを阻害する可能性のあるハードウェア要件を宣言しているかどうかについて、アプリのマニフェストを詳細に見直す必要があります。

アプリでは TV で使用できないハードウェア機能(タッチスクリーンやカメラなど)を使用しているが、TV 向けにはそれらの機能がなくても構わない場合、アプリのマニフェストを編集して、それが不要な機能であることを示します。次のマニフェストのコード スニペットでは、TV 端末で使用できないハードウェア機能を(TV 以外の端末には提供する可能性がある場合でも)不要と宣言する方法を示します。

<uses-feature android:name="android.hardware.touchscreen"
        android:required="false"/>
<uses-feature android:name="android.hardware.faketouch"
        android:required="false"/>
<uses-feature android:name="android.hardware.telephony"
        android:required="false"/>
<uses-feature android:name="android.hardware.camera"
        android:required="false"/>
<uses-feature android:name="android.hardware.nfc"
        android:required="false"/>
<uses-feature android:name="android.hardware.location.gps"
        android:required="false"/>
<uses-feature android:name="android.hardware.microphone"
        android:required="false"/>
<uses-feature android:name="android.hardware.sensor"
        android:required="false"/>

注: 機能リファレンスで説明されているように、一部の機能には android.hardware.camera.front のようなサブ機能があります。アプリで使用されるサブ機能も required="false" としてマークしてください。

TV 端末向けのすべてのアプリは、TV アプリのビルドを開始するで説明したように、タッチスクリーン機能が不要であることを宣言する必要があります。アプリで上記の機能を 1 つ以上使用している場合は、マニフェストで該当する機能の android:required 属性の設定を false に変更します。

警告: この値を true に設定してハードウェア機能を必要と宣言すると、TV 端末にインストールされず、Android TV のホーム画面ランチャーにもアプリが表示されなくなります。

アプリのハードウェア機能をオプションにする場合は、実行時にこれらの機能が利用できるかをチェックしてから、アプリの動作を調整する必要があります。次のセクションでは、ハードウェア機能をチェックする方法と、アプリの動作を変更するためのいくつかのアプローチについて説明します。

マニフェスト内でのフィルタリングと機能の宣言については、uses-feature ガイドを参照してください。

ハードウェア機能を暗示するパーミッションを宣言する

uses-permission のマニフェストにおける宣言には、ハードウェア機能を暗示するものがあります。これは、アプリのマニフェストでいくつかのパーミッションを要求すると、アプリが TV 端末にインストールされず、使用されなくなることを意味します。次の一般によく要求されるパーミッションにより、暗黙的なハードウェア機能の要件が作成されます。

パーミッション 暗黙的なハードウェア機能
RECORD_AUDIO android.hardware.microphone
CAMERA android.hardware.camera
android.hardware.camera.autofocus
ACCESS_COARSE_LOCATION

android.hardware.location

android.hardware.location.network(ターゲット API レベル 20 以前のみ)

ACCESS_FINE_LOCATION

android.hardware.location

android.hardware.location.gps(ターゲット API レベル 20 以前のみ)

ハードウェア機能の要件を暗示するパーミッション要求を網羅したリストについては、uses-feature ガイドを参照してください。アプリが上記の機能のいずれかを要求する場合、暗示されたハードウェア機能についてマニフェストに uses-feature 宣言を含めて、不要であることを示します(android:required="false")。

注: アプリが Android 5.0(API レベル 21)以降をターゲットにしていて、ACCESS_COARSE_LOCATION または ACCESS_FINE_LOCATION パーミションを使用している場合、ユーザーは、TV 端末にネットワーク カードまたは GPS 受信機がなくても TV 端末にアプリをインストールできます。

ハードウェア機能をチェックする

Android のフレームワークでは、アプリを実行している端末でハードウェア機能が使用できない場合を判別できます。hasSystemFeature(String) メソッドを使用して、実行時に特定の機能をチェックできます。この場合、チェック対象の機能を指定する単一の文字列の引数を使用します。

次のコード例では、アプリの実行時にハードウェア機能の利用可能性を検出する方法を示します。

// Check if the telephony hardware feature is available.
if (getPackageManager().hasSystemFeature("android.hardware.telephony")) {
    Log.d("HardwareFeatureTest", "Device can make phone calls");
}

// Check if android.hardware.touchscreen feature is available.
if (getPackageManager().hasSystemFeature("android.hardware.touchscreen")) {
    Log.d("HardwareFeatureTest", "Device has a touch screen.");
}

タッチスクリーン

TV には通常タッチスクリーンがないので、Android は TV 端末向けにはタッチスクリーン操作をサポートしていません。そもそも、タッチスクリーン操作は、ユーザーが 10 フィート離れた場所から視聴するという TV 特有の使用環境にそぐわないものです。UI 要素とテキストがタッチスクリーンの使用を必要としない、または暗示しないことを確認してください。

TV 端末ではリモコンの矢印ボタンによるナビゲーションをサポートして、TV 特有のインタラクション モデルに適したアプリをデザインする必要があります。TV 向けのコントロールを使用してナビゲーションを適切にサポートする方法については、TV 用のナビゲーションを作成するを参照してください。

カメラ

TV にはカメラがないことが一般的ですが、カメラ関連アプリを提供することは可能です。たとえば、写真の撮影、表示、編集の機能があるアプリの場合、TV 向けに撮影機能を無効にしながら、写真の表示や編集は可能にすることができます。カメラ関連アプリをTV 向けにする場合、アプリのマニフェストには次の機能の宣言を追加します。

<uses-feature android:name="android.hardware.camera" android:required="false" />

カメラ機能を除いてアプリを動作させる場合、カメラ機能の存在を検出し、アプリの動作を調整するためのコードを追加します。次のコードサンプルは、カメラ機能の存在を検出する方法を示しています。

// Check if the camera hardware feature is available.
if (getPackageManager().hasSystemFeature("android.hardware.camera")) {
    Log.d("Camera test", "Camera available!");
} else {
    Log.d("Camera test", "No camera available. View and edit features only.");
}

GPS

TV は据え付けタイプの室内用端末であり、全地球測位システム(GPS)の受信機を内蔵していません。アプリが位置情報を使用している場合、TV 端末のセットアップ時に郵便番号などの静的なロケーション プロバイダを構成して、ユーザーが位置を調べたり、それらを使用できるようにすることが可能です。

// Request a static location from the location manager
LocationManager locationManager = (LocationManager) this.getSystemService(
        Context.LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation("static");

// Attempt to get postal or zip code from the static location object
Geocoder geocoder = new Geocoder(this);
Address address = null;
try {
  address = geocoder.getFromLocation(location.getLatitude(),
          location.getLongitude(), 1).get(0);
  Log.d("Zip code", address.getPostalCode());

} catch (IOException e) {
  Log.e(TAG, "Geocoder error", e);
}

コントローラを処理する

TV 端末ではベーシックなタイプのリモコン、ゲーム機のコントローラといった、アプリを操作するための 2 次ハードウェア端末が必要となります。これは、アプリで矢印ボタンによる入力をサポートする必要がある、ということです。そして、コントローラのオフライン操作と複数のタイプのコントローラによる入力を処理することも必要です。

矢印ボタンによる最小限のコントロール

TV 端末のデフォルト コントローラはリモコン端末の矢印ボタンです。すなわち、上下、左右、[選択]、[戻る]、[ホーム] ボタンのみを使用して、アプリを操作できるようにする必要があります。ゲーム アプリの場合、通常は追加のコントロール機能のあるゲーム機のコントローラが必要ですが、TV ではリモコン端末の矢印ボタンでプレイできるようにする必要があります。この場合、コントローラが必要な旨をユーザーに警告した上で、リモコン端末の矢印ボタンでゲームを終了できるようにする必要があります。TV のリモコン端末の矢印ボタンによるナビゲーションを処理する方法については、TV 用のナビゲーションを作成するを参照してください。

コントローラの接続の切断を処理する

TV 用コントローラは Bluetooth 端末であることが多く、定期的にスリープモードに入って TV との接続を切断し、消費電力を節約しようとする場合があります。この場合、アプリ側で再接続イベントの処理を構成していないと、アプリが中断したり再起動する可能性が生じます。これらのイベントは、次のいずれかの場合に発生する可能性があります。

  • 動画(数分程度)を見ている間にリモコン端末かゲーム機のコントローラがスリープモードになり、TV 端末との接続が失われ、その後再び接続される場合。
  • ゲームプレイ中に、新しいプレイヤーがオフライン状態のゲーム機のコントローラを使用してゲームに参加した場合。
  • ゲームプレイ中に、プレイヤーがゲームを中断し、ゲーム機のントローラとの接続が失われた場合。

接続の切断や再接続の対象となる TV アプリのアクティビティはすべて、アプリのマニフェストで再接続イベントを処理できるように構成する必要があります。次のコード サンプルでは、キーボードやナビゲーション端末の接続、切断、再接続などを含む構成の変更を処理するアクティビティの記述方法を示します。

<activity
  android:name="com.example.android.TvActivity"
  android:label="@string/app_name"
  android:configChanges="keyboard|keyboardHidden|navigation"
  android:theme="@style/Theme.Leanback">

  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
  </intent-filter>
  ...
</activity>

この構成の変更により、Android のフレームワークによる再起動(ユーザー エクスペリエンスの観点から望ましくない)ではなく、再接続イベントを介してアプリの中断を回避することが可能です。

リモコンの矢印ボタンによる入力のバリエーションを処理する

TV 端末のユーザーは、複数のタイプのコントローラを使用して TV を操作する場合があります。たとえば、ベーシックなタイプのリモコンの矢印ボタンと(ゲーム)コントローラを使用している場合があります。TV リモコンの矢印ボタンの機能をゲーム機のコントローラで実行する場合、送信されるキーコードはリモコン本体が送信するキーコードとは異なる場合があります。

ユーザーがアプリ操作のためにコントローラとリモコンを持ち替える必要がないよう、アプリでは、(ゲーム)コントローラからの矢印ボタンによる入力のバリエーションを処理する必要があります。入力のバリエーションの処理については、コントローラのアクションを処理するを参照してください。

省電力モードのときに再生を一時停止する

一部の TV 端末は、ユーザーが端末をオフにしたときに省電力モードをサポートします。これらの端末は、Android TV をシャットダウンする代わりに、表示を無効にして、Android TV をバックグラウンドで実行します。省電力モードに移行しても音声出力は有効であるため、端末が省電力モードになった際に、アプリで現在再生されているコンテンツを停止する必要があります。

省電力モード中の再生を防止するには、onStop() をオーバーライドして、現在再生されているコンテンツを停止します。

@Override
public void onStop() {
  // App-specific method to stop playback
  stopPlayback();
  super.onStop();
}

ユーザーが電源を再度オンにしたときにアプリがフォアグラウンドでアクティブになっている場合、onStart() が呼び出されます。アクティビティの起動と停止に関する詳細については、アクティビティのライフサイクルをご覧ください。