Register now for Android Dev Summit 2019!

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

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

このレッスンでは、TV でアプリが正常に動作するかどうかチェックする方法と、サポートされていないハードウェア機能を処理する方法について説明します。入力方法の種類については、TV コントローラの管理をご覧ください。

TV デバイスをチェックする

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

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

Kotlin

    const val TAG = "DeviceTypeRuntimeCheck"

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

Java

    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 デバイスで提供されることの多いハードウェア機能がない場合があります。このため、TV デバイス向け Android システムでは次の機能をサポートしていません。

ハードウェア 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) メソッドを使用します。このメソッドは、チェック対象の機能を指定する因数を 1 つ使用します。

次のコードサンプルでは、実行時にハードウェア機能が利用できるかどうかを検出する方法を示しています。

Kotlin

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

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

Java

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

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

タッチ スクリーン

TV には通常タッチ スクリーンがないため、TV デバイス向けタッチ スクリーン操作は Android ではサポートされません。そもそも、ユーザーが 3 メートルほど離れた場所から視聴するという TV 特有の使用環境にタッチ スクリーン操作は適していません。UI 要素とテキストがタッチスクリーンの使用を必要としないこと、または暗黙的に示さないことを確認してください。

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

カメラ

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

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

カメラ機能を除いてアプリを動作させる場合は、コードをアプリに追加してカメラ機能が使用可能かどうかを検出し、そのアプリの動作を調整します。次のコードサンプルでは、カメラの存在を検出する方法を示しています。

Kotlin

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

Java

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

GPS

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

Kotlin

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

    // Attempt to get postal or zip code from the static location object
    val geocoder = Geocoder(this)
    val address: Address? =
            try {
                geocoder.getFromLocation(location.latitude, location.longitude, 1)[0]
                        .apply {
                            Log.d(TAG, postalCode)
                        }
            } catch (e: IOException) {
                Log.e(TAG, "Geocoder error", e)
                null
            }
    

Java

    // 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 デバイスの中には、ユーザーがデバイスをオフにしたときに省電力モードに切り替わるものがあります。このようなデバイスでは、Android TV はシャットダウンされません。表示は無効になりますが、バックグラウンドでは実行されたままです。省電力モードでも音声出力は引き続き有効なので、省電力モードのときはアプリで現在再生されているコンテンツを停止する必要があります。

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

Kotlin

    override fun onStop() {
        // App-specific method to stop playback
        stopPlayback()
        super.onStop()
    }
    

Java

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

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