ホーム画面のチャンネル

Android TV のホーム画面(または単純にホーム画面)には、おすすめのコンテンツをチャンネルと番組の表として表示する UI が用意されています。各行がチャンネルです。チャンネルには、そのチャンネルで利用可能なすべてのプログラムのカードが含まれています。

TV のホーム画面

このドキュメントでは、ユーザーに最高のエクスペリエンスを提供できるように、ホーム画面へのチャンネルとプログラムの追加、コンテンツの更新、ユーザー アクションの処理をする方法を示します。(API の詳細については、ホーム画面の CodelabI/O 2017 Android TV セッションをご覧ください)。

注: おすすめチャンネルは Android 8.0(API レベル 26)以降でのみ使用できます。Android 8.0(API レベル 26)以降で実行されているアプリにおすすめを提供する場合は、これらを使用する必要があります。以前のバージョンの Android で実行されているアプリにおすすめを表示するには、代わりにおすすめの行を使用する必要があります。

ホーム画面の UI

アプリでは、新しいチャンネルの作成、チャンネル内の番組の追加、削除、更新、チャンネル内の番組の順序の制御を行うことができます。 たとえば、「新作」というチャンネルを作成して、新たに利用可能になったプログラムのカードを表示できます。

アプリでは、ホーム画面に表示されるチャンネルの順序を制御できません。アプリが新しいチャンネルを作成すると、それをホーム画面がチャンネル リストの下部に追加します。ユーザーは、チャンネルの並べ替えと、表示非表示の切り替えができます。

Watch Next チャンネル

Watch Next チャンネルは、ホーム画面でアプリの行の 2 番目の行に表示されます。このチャンネルはシステムが作成し管理します。アプリは、Watch Next チャンネルにプログラムを追加できます。詳細については、プログラムを Watch Next チャンネルに追加するをご覧ください。

アプリ チャンネル

アプリが作成するチャンネルは、すべて次のライフサイクルに従います。

  1. ユーザーがアプリでチャンネルを発見し、それをホーム画面に追加するよう要求する。
  2. アプリがチャンネルを作成し、TvProvider に追加する(この時点ではチャンネルは表示されない)。
  3. アプリがシステムにチャンネルを表示するよう要求する。
  4. システムが、新しいチャンネルを承認するようユーザーに要求する。
  5. ホーム画面の最後の行に新しいチャンネルが表示される。

デフォルト チャンネル

アプリは、ユーザーがホーム画面に追加するチャンネルをいくつでも提供できます。通常、ホーム画面に表示される前に、ユーザーが各チャンネルを選択して承認する必要があります。すべてのアプリで、デフォルト チャンネルを 1 つ作成できます。デフォルト チャンネルは特別で、自動的にホーム画面に表示されます。ユーザーが明示的にリクエストする必要はありません。

前提条件

Android TV のホーム画面は、Android の TvProvider API を使用して、アプリが作成するチャンネルとプログラムを管理します。プロバイダのデータにアクセスするには、アプリのマニフェストに次の権限を追加します。

<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />

TvProvider サポート ライブラリの使用により、プロバイダの使用が簡単になります。次のように、build.gradle ファイルの依存関係に追加してください。

Groovy

implementation 'androidx.tvprovider:tvprovider:1.0.0'

Kotlin

implementation("androidx.tvprovider:tvprovider:1.0.0")

チャンネルとプログラムを操作するには、次に示すサポート ライブラリのインポートをソースコードに含めます。

Kotlin

import android.support.media.tv.Channel
import android.support.media.tv.TvContractCompat
import android.support.media.tv.ChannelLogoUtils
import android.support.media.tv.PreviewProgram
import android.support.media.tv.WatchNextProgram

Java

import android.support.media.tv.Channel;
import android.support.media.tv.TvContractCompat;
import android.support.media.tv.ChannelLogoUtils;
import android.support.media.tv.PreviewProgram;
import android.support.media.tv.WatchNextProgram;

チャンネル

アプリが作成した最初のチャンネルが、デフォルト チャンネルになります。デフォルト チャンネルは、ホーム画面に自動的に表示されます。作成した他のすべてのチャンネルは、ユーザーが選択し承認するまでホーム画面に表示されません。

チャンネルを作成する

アプリが新しく追加されたチャンネルの表示をシステムに要求するのは、フォアグラウンドで動作している場合だけにする必要があります。こうすることで、ユーザーが別のアプリを実行しているときに、チャンネルを追加するための承認を要求するダイアログをアプリが表示することがなくなります。バックグラウンドでの動作中にチャンネルを追加しようとすると、アクティビティの onActivityResult() メソッドがステータス コード RESULT_CANCELED を返します。

チャンネルを作成する手順は次のとおりです。

  1. チャンネル ビルダーを作成し、その属性を設定します。チャンネル タイプは TYPE_PREVIEW にする必要があります。必要に応じて、さらに属性を追加します。

    Kotlin

    val builder = Channel.Builder()
    // Every channel you create must have the type TYPE_PREVIEW
    builder.setType(TvContractCompat.Channels.TYPE_PREVIEW)
            .setDisplayName("Channel Name")
            .setAppLinkIntentUri(uri)
    

    Java

    Channel.Builder builder = new Channel.Builder();
    // Every channel you create must have the type TYPE_PREVIEW
    builder.setType(TvContractCompat.Channels.TYPE_PREVIEW)
            .setDisplayName("Channel Name")
            .setAppLinkIntentUri(uri);
    
  2. チャンネルをプロバイダに挿入します。

    Kotlin

    var channelUri = context.contentResolver.insert(
            TvContractCompat.Channels.CONTENT_URI, builder.build().toContentValues())
    

    Java

    Uri channelUri = context.getContentResolver().insert(
            TvContractCompat.Channels.CONTENT_URI, builder.build().toContentValues());
    
  3. 後で番組をチャンネルに追加するために、チャンネル ID を保存する必要があります。返された URI からチャンネル ID を抽出します。

    Kotlin

    var channelId = ContentUris.parseId(channelUri)
    

    Java

    long channelId = ContentUris.parseId(channelUri);
    
  4. チャンネルのロゴを追加する必要があります。Uri または Bitmap を使用します。ロゴアイコンは 80 dp x 80 dp とし、不透明にする必要があります。円形のマスクで表示されます。

    TV ホーム画面アイコンマスク

    Kotlin

    // Choose one or the other
    storeChannelLogo(context: Context, channelId: Long, logoUri: Uri) // also works if logoUri is a URL
    storeChannelLogo(context: Context, channelId: Long, logo: Bitmap)
    

    Java

    // Choose one or the other
    storeChannelLogo(Context context, long channelId, Uri logoUri); // also works if logoUri is a URL
    storeChannelLogo(Context context, long channelId, Bitmap logo);
    
  5. デフォルト チャンネルを作成する(省略可): アプリで最初のチャンネルを作成するときに、デフォルト チャンネルを指定すると、ユーザーが操作しなくてもホーム画面にすぐに表示されます。作成した他のチャンネルは、ユーザーが明示的に選択するまで表示されません。

    Kotlin

    TvContractCompat.requestChannelBrowsable(context, channelId)
    

    Java

    TvContractCompat.requestChannelBrowsable(context, channelId);
    

  6. アプリを開く前にデフォルト チャンネルを表示します。この動作を実現するには、アプリのインストール後にホーム画面から送信される android.media.tv.action.INITIALIZE_PROGRAMS アクションをリッスンする BroadcastReceiver を追加します。
    <receiver
      android:name=".RunOnInstallReceiver"
      android:exported="true">
        <intent-filter>
          <action android:name="android.media.tv.action.INITIALIZE_PROGRAMS" />
          <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </receiver>
    
    開発中にアプリをサイドローディングする場合は、adb でインテントをトリガーすることで、このステップをテストできます。ここで、your.package.name/.YourReceiverName はアプリの BroadcastReceiver です。

    adb shell am broadcast -a android.media.tv.action.INITIALIZE_PROGRAMS -n \
        your.package.name/.YourReceiverName
    

    まれに、ユーザーがアプリを起動するのと同時にブロードキャストを受信することがあります。コード内でデフォルト チャンネルを複数回追加しないようにしてください。

チャンネルを更新する

チャンネルの更新は、チャンネルの作成とよく似ています。

別の Channel.Builder を使用して、変更する必要がある属性を設定します。

ContentResolver を使用して、チャンネルを更新します。最初にチャンネルを追加したときに保存したチャンネル ID を使用します。

Kotlin

context.contentResolver.update(
        TvContractCompat.buildChannelUri(channelId),
        builder.build().toContentValues(),
        null,
        null
)

Java

context.getContentResolver().update(TvContractCompat.buildChannelUri(channelId),
    builder.build().toContentValues(), null, null);

チャンネルのロゴを更新するには、storeChannelLogo() を使用します。

チャンネルを削除する

Kotlin

context.contentResolver.delete(TvContractCompat.buildChannelUri(channelId), null, null)

Java

context.getContentResolver().delete(TvContractCompat.buildChannelUri(channelId), null, null);

プログラム

アプリ チャンネルにプログラムを追加する

PreviewProgram.Builder を作成し、その属性を設定します。

Kotlin

val builder = PreviewProgram.Builder()
builder.setChannelId(channelId)
        .setType(TvContractCompat.PreviewPrograms.TYPE_CLIP)
        .setTitle("Title")
        .setDescription("Program description")
        .setPosterArtUri(uri)
        .setIntentUri(uri)
        .setInternalProviderId(appProgramId)

Java

PreviewProgram.Builder builder = new PreviewProgram.Builder();
builder.setChannelId(channelId)
        .setType(TvContractCompat.PreviewPrograms.TYPE_CLIP)
        .setTitle("Title")
        .setDescription("Program description")
        .setPosterArtUri(uri)
        .setIntentUri(uri)
        .setInternalProviderId(appProgramId);

プログラムのタイプに応じて、さらに属性を追加します(各タイプのプログラムで使用可能な属性については、下記のをご覧ください)。

プログラムをプロバイダに挿入します。

Kotlin

var programUri = context.contentResolver.insert(TvContractCompat.PreviewPrograms.CONTENT_URI,
        builder.build().toContentValues())

Java

Uri programUri = context.getContentResolver().insert(TvContractCompat.PreviewPrograms.CONTENT_URI,
      builder.build().toContentValues());

後で参照できるようにプログラム ID を取得します。

Kotlin

val programId = ContentUris.parseId(programUri)

Java

long programId = ContentUris.parseId(programUri);

プログラムを Watch Next チャンネルに追加する

プログラムを Watch Next チャンネルに挿入するには、プログラムを Watch Next チャンネルに追加するをご覧ください。

プログラムを更新する

プログラムの情報は変更できます。たとえば、映画のレンタル価格を更新したい場合や、ユーザーが視聴したプログラムの量を示す進行状況バーを更新したい場合があります。

PreviewProgram.Builder を使用して変更する必要がある属性を設定し、getContentResolver().update を呼び出してプログラムを更新します。プログラムが最初に追加されたときに保存したプログラム ID を指定します。

Kotlin

context.contentResolver.update(
        TvContractCompat.buildPreviewProgramUri(programId),
                builder.build().toContentValues(), null, null
)

Java

context.getContentResolver().update(TvContractCompat.buildPreviewProgramUri(programId),
    builder.build().toContentValues(), null, null);

プログラムを削除する

Kotlin

context.contentResolver
        .delete(TvContractCompat.buildPreviewProgramUri(programId), null, null)

Java

context.getContentResolver().delete(TvContractCompat.buildPreviewProgramUri(programId), null, null);

ユーザー操作の処理

アプリでチャンネルを表示および追加する UI を提供することで、ユーザーがコンテンツを見つけやすくできます。また、チャンネルがホーム画面に表示された後、アプリでチャンネルに対する操作を処理する必要があります。

チャンネルの発見と追加

アプリでは、ユーザーがチャンネルの選択と追加を行える UI 要素(たとえば、チャンネルの追加を要求するボタン)を提供できます。

ユーザーが特定のチャンネルを要求した後、次のコードを実行して、ホーム画面 UI に追加する許可をユーザーから得ます。

Kotlin

val intent = Intent(TvContractCompat.ACTION_REQUEST_CHANNEL_BROWSABLE)
intent.putExtra(TvContractCompat.EXTRA_CHANNEL_ID, channelId)
try {
  activity.startActivityForResult(intent, 0)
} catch (e: ActivityNotFoundException) {
  // handle error
}

Java

Intent intent = new Intent(TvContractCompat.ACTION_REQUEST_CHANNEL_BROWSABLE);
intent.putExtra(TvContractCompat.EXTRA_CHANNEL_ID, channelId);
try {
   activity.startActivityForResult(intent, 0);
} catch (ActivityNotFoundException e) {
  // handle error
}

ユーザーにチャンネルの承認を求めるダイアログが表示されます。 次のアクティビティの onActivityResult メソッド内でこの要求の結果を処理します: Activity.RESULT_CANCELED あるいは Activity.RESULT_OK

Android TV ホーム画面イベント

ユーザーがアプリによって公開されたプログラム / チャンネルを操作すると、ホーム画面はアプリにインテントを送信します。

  • ユーザーがチャンネルのロゴを選択すると、ホーム画面はチャンネルの APP_LINK_INTENT_URI 属性に保存されている Uri をアプリに送信します。アプリは、メイン UI または選択したチャンネルに関連するビューを起動します。
  • ユーザーがプログラムを選択すると、ホーム画面はプログラムの INTENT_URI 属性に保存されている Uri をアプリに送信します。アプリは、選択されたコンテンツを再生しなければなりません。
  • 番組に興味がなくなったため、ホーム画面の UI から削除することを希望していることをユーザーが示すことができます。システムは UI からプログラムを削除し、そのプログラムを所有するアプリに、プログラムの ID を含むインテント(android.media.tv.ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED または android.media.tv.ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED)を送信します。アプリはプロバイダからプログラムを削除し、再挿入しないでください。

ホーム画面がユーザーの操作に対して送信する Uris すべてにインテント フィルタを作成してください。

<receiver
   android:name=".WatchNextProgramRemoved"
   android:enabled="true"
   android:exported="true">
   <intent-filter>
       <action android:name="android.media.tv.ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED" />
   </intent-filter>
</receiver>

ベスト プラクティス

  • 多くの TV アプリがユーザーのログインを必要とします。この場合、android.media.tv.action.INITIALIZE_PROGRAMS をリッスンする BroadcastReceiver は、認証されていないユーザーにチャンネル コンテンツを提案します。たとえば、アプリは最初に優れたコンテンツや現在人気のあるコンテンツを表示します。ユーザーがログインすると、パーソナライズされたコンテンツを表示できます。これは、ユーザーがログインする前にアプリをアップセルする絶好のチャンスです。
  • アプリがフォアグラウンドでなく、チャンネルや番組を更新する必要がある場合は、JobScheduler を使用して処理をスケジュールします(JobSchedulerJobService をご覧ください)。
  • アプリの動作に支障がある場合(たとえば、プロバイダに継続的にデータを大量に送る場合など)は、アプリのプロバイダ権限がシステムによって取り消されることがあります。プロバイダにアクセスするコードを try-catch 句でラップし、セキュリティ例外を処理してください。
  • 番組とチャンネルを更新する前に、データの更新と調整に必要なデータをプロバイダにクエリします。たとえば、ユーザーが UI から削除したいプログラムを更新する必要はありません。既存のデータをクエリし、チャネルの承認をリクエストした後に、プロバイダにデータを挿入または更新するバックグラウンド ジョブを使用します。このジョブは、アプリの起動時に、およびアプリがデータを更新する必要があるときに実行できます。

    Kotlin

    context.contentResolver
      .query(
          TvContractCompat.buildChannelUri(channelId),
              null, null, null, null).use({
                  cursor-> if (cursor != null and cursor.moveToNext()) {
                               val channel = Channel.fromCursor(cursor)
                               if (channel.isBrowsable()) {
                                   //update channel's programs
                               }
                           }
              })
    

    Java

    try (Cursor cursor = context.getContentResolver()
          .query(
              TvContractCompat.buildChannelUri(channelId),
              null,
              null,
              null,
              null)) {
                  if (cursor != null && cursor.moveToNext()) {
                      Channel channel = Channel.fromCursor(cursor);
                      if (channel.isBrowsable()) {
                          //update channel's programs
                      }
                  }
              }
    
  • すべての画像(ロゴ、アイコン、コンテンツ画像)に一意な URI を使用します。画像を更新するときには、必ず別の URI を使用してください。画像はすべてキャッシュに保存されます。画像を変更したときに URI を変更しないと、古い画像が表示されたままになります。

  • WHERE 句は許可されておらず、WHERE 句を使用してプロバイダを呼び出すとセキュリティ例外がスローされることに注意してください。

属性

このセクションでは、チャンネルとプログラムの属性について個別に説明します。

チャンネルの属性

すべてのチャンネルに次の属性を指定する必要があります。

属性 Notes
TYPE TYPE_PREVIEW に設定します。
DISPLAY_NAME チャンネルの名前を設定します。
APP_LINK_INTENT_URI ユーザーがチャンネルのロゴを選択すると、システムはチャンネルに関連するコンテンツを提示するアクティビティを開始するインテントを送信します。この属性に、そのアクティビティのインテント フィルタで使用される URI を設定します。

さらに、チャンネルには、アプリの内部使用のために予約された 6 つのフィールドもあります。これらのフィールドにキーやその他の値を保存して、チャンネルからアプリの内部データ構造への対応付けに使用できます。

  • INTERNAL_PROVIDER_ID
  • INTERNAL_PROVIDER_DATA
  • INTERNAL_PROVIDER_FLAG1
  • INTERNAL_PROVIDER_FLAG2
  • INTERNAL_PROVIDER_FLAG3
  • INTERNAL_PROVIDER_FLAG4

プログラムの属性

プログラムの属性については、タイプごとの個々のページをご覧ください。

サンプルコード

ホーム画面の操作を処理し、Android TV ホーム画面にチャンネルとプログラムを追加するアプリを作成する方法について詳しくは、ホーム画面の Codelab をご覧ください。