Android TV ホーム画面(あるいは単にホーム画面)では、おすすめのコンテンツをチャンネルとプログラムの表として表示する UI が提供されます。各行がチャンネルです。チャンネルには、そのチャンネルで利用可能なすべてのプログラムのカードが含まれています。
このドキュメントでは、ユーザーに最高のエクスペリエンスを提供できるように、ホーム画面へのチャンネルとプログラムの追加、コンテンツの更新、ユーザー アクションの処理をする方法を示します。(API の詳細を知りたい方は、ホーム画面の Codelab と I/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 チャンネルに追加するをご覧ください。
アプリ チャンネル
アプリが作成するチャンネルは、すべて次のライフサイクルに従います。
- ユーザーがアプリでチャンネルを発見し、それをホーム画面に追加するよう要求する。
- アプリがチャンネルを作成し、
TvProvider
に追加する(この時点ではチャンネルは表示されない)。 - アプリがシステムにチャンネルを表示するよう要求する。
- システムが、新しいチャンネルを承認するようユーザーに要求する。
- ホーム画面の最後の行に新しいチャンネルが表示される。
デフォルト チャンネル
アプリは、ユーザーがホーム画面に追加するチャンネルをいくつでも提供できます。ユーザーは通常、ホーム画面に表示される前に各チャンネルを選択して承認する必要があります。すべてのアプリはデフォルト チャンネルを 1 つ作成できます。デフォルト チャンネルは特別で、自動的にホーム画面に表示されます。ユーザーが明示的に要求する必要はありません。
要件
Android TV のホーム画面は、Android の TvProvider
API を使用して、アプリが作成するチャンネルとプログラムを管理します。プロバイダのデータにアクセスするには、アプリのマニフェストに次の権限を追加します。
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
TvProvider
サポート ライブラリの使用により、プロバイダの使用が簡単になります。次のように、build.gradle
ファイルの依存関係に追加してください。
compile 'com.android.support:support-tv-provider:27.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
を返します。
チャンネルを作成する手順は次のとおりです。
チャンネル ビルダーを作成し、その属性を設定します。チャンネル タイプは
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);チャンネルをプロバイダに挿入します。
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());
-
後でチャンネルにプログラムを追加するために、チャンネル ID を保存する必要があります。返された URI からチャンネル ID を抽出します。
Kotlin
var channelId = ContentUris.parseId(channelUri)
Java
long channelId = ContentUris.parseId(channelUri);
チャンネルのロゴを追加する必要があります。
Uri
またはBitmap
を使用します。ロゴアイコンは、縦 80 dp、横 80 dp、不透明でなければなりません。円形にマスクされて表示されます。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);
デフォルト チャンネルを追加します(省略可)。アプリが最初のチャンネルを作成するとき、ユーザーの操作なしで即座にホーム画面に表示されるように、デフォルト チャンネルにすることができます。作成した他のチャンネルは、ユーザーが明示的に選択するまで表示されません。
Kotlin
TvContractCompat.requestChannelBrowsable(context, channelId)
Java
TvContractCompat.requestChannelBrowsable(context, channelId);
- アプリを開く前にデフォルト チャンネルを表示します。この動作を実現するには、
BroadcastReceiver
を追加します。このレシーバには、android.media.tv.action.INITIALIZE_PROGRAMS
アクションをリッスンさせます。このアクションは、アプリがインストールされた後でホーム画面が送信します。<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
まれに、ユーザーがアプリを起動するのと同時に、アプリがブロードキャストを受信する場合があります。コードの中でデフォルト チャンネルの追加を 2 回以上していないか確認してください。
チャンネルを更新する
チャンネルの更新は、チャンネルの作成とよく似ています。
別の 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 アプリがユーザーのログインを必要とします。この場合、
BroadcastReceiver
(ただし、android.media.tv.action.INITIALIZE_PROGRAMS
をリッスンするもの)が認証されていないユーザーにチャンネル コンテンツをおすすめする必要があります。たとえば、アプリで最初に傑作や人気のコンテンツを表示できます。ユーザーがログインした後では、好みに合ったコンテンツを表示できます。これは、ログイン前にアプリでアップセルを行う絶好の機会です。 - アプリがフォアグラウンドにないときに、チャンネルあるいはプログラムを更新する必要がある場合、
JobScheduler
を使用して処理をスケジューリングします(JobScheduler と JobService をご覧ください)。 - プロバイダにデータを送り続けるなどの不正な動作をアプリが行った場合に、アプリのプロバイダの許可を取り消せます。プロバイダにアクセスするコードは必ず 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 句を使用してプロバイダを呼び出すとセキュリティ例外がスローされることに注意してください。
属性
このセクションでは、チャンネルとプログラムの属性について個別に説明します。
チャンネルの属性
すべてのチャンネルに次の属性を指定する必要があります。
属性 | 備考 |
---|---|
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 をご覧ください。