The Android Developer Challenge is back! Submit your idea before December 2.

Channel di layar utama

Layar utama Android TV, atau cukup layar utama, menyediakan UI yang menampilkan rekomendasi konten sebagai tabel saluran dan program. Setiap baris adalah saluran. Saluran berisi kartu untuk setiap program yang tersedia di saluran itu:

Layar utama TV

Dokumen ini menunjukkan cara menambahkan saluran dan program ke layar utama, memperbarui konten, menangani tindakan pengguna, dan memberikan pengalaman terbaik bagi pengguna Anda. (Jika Anda ingin mendalami API lebih lanjut, coba codelab layar utama dan tonton sesi Android TV I/O 2017.)

Catatan: Saluran rekomendasi hanya tersedia di Android 8.0 (API level 26) dan yang lebih baru. Anda harus menggunakannya untuk menyediakan rekomendasi untuk aplikasi yang berjalan di Android 8.0 (API level 26) dan yang lebih baru. Guna menyediakan rekomendasi untuk aplikasi yang berjalan pada Android versi sebelumnya, aplikasi Anda harus menggunakan baris rekomendasi sebagai gantinya.

UI layar utama

Aplikasi dapat membuat saluran baru, menambahkan, menghapus, dan memperbarui program di saluran, serta mengontrol urutan program di saluran. Misalnya, aplikasi dapat membuat saluran yang disebut "Yang Baru" dan menampilkan kartu untuk program baru yang tersedia.

Aplikasi tidak dapat mengontrol urutan saluran yang muncul di layar utama. Jika aplikasi Anda membuat saluran baru, layar utama akan menambahkannya ke tombol daftar saluran. Pengguna dapat mengurutkan ulang, menyembunyikan, dan menampilkan saluran.

Saluran Tonton Berikutnya

Saluran Tonton Berikutnya adalah baris kedua yang muncul di layar utama, setelah baris aplikasi. Sistem akan membuat dan menyimpan saluran ini. Aplikasi Anda dapat menambahkan program ke saluran Tonton Berikutnya: program yang ditandai pengguna sebagai menarik, berhenti menonton di tengah, atau yang terkait dengan konten yang ditonton pengguna (seperti episode berikutnya dalam seri atau season pertunjukan berikutnya).

Saluran Tonton Berikutnya memiliki beberapa batasan: Aplikasi Anda tidak dapat memindahkan, menghapus, atau menyembunyikan baris saluran Tonton Berikutnya.

Saluran aplikasi

Saluran yang dibuat aplikasi Anda semuanya mengikuti siklus proses ini:

  1. Pengguna menemukan saluran di aplikasi dan meminta untuk menambahkannya ke layar utama.
  2. Aplikasi membuat saluran dan menambahkannya ke TvProvider (pada tahap ini, saluran tidak terlihat).
  3. Aplikasi meminta sistem untuk menampilkan saluran.
  4. Sistem meminta pengguna untuk menyetujui saluran baru.
  5. Saluran baru akan muncul di baris terakhir layar utama.

Saluran default

Aplikasi Anda dapat menawarkan sejumlah saluran untuk ditambahkan pengguna ke layar utama. Pengguna biasanya harus memilih dan menyetujui setiap saluran sebelum saluran itu muncul di layar utama. Setiap aplikasi memiliki opsi untuk membuat satu saluran default. Saluran default bersifat khusus karena otomatis muncul di layar utama; pengguna tidak harus secara eksplisit memintanya.

Prasyarat

Layar utama Android TV menggunakan TvProvider API Android untuk mengelola saluran dan program yang dibuat oleh aplikasi Anda. Untuk mengakses data penyedia, tambahkan izin berikut ke manifes aplikasi Anda:

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

Library dukungan TvProvider memudahkan untuk menggunakan penyedia. Tambahkan library tersebut ke dependensi di file build.gradle Anda:

compile 'com.android.support:support-tv-provider:27.0.0'
    

Untuk menangani saluran dan program, pastikan untuk menyertakan impor library dukungan dalam program Anda:

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;
    

Channel

Saluran pertama yang dibuat aplikasi Anda menjadi saluran defaultnya. Saluran default otomatis akan muncul di layar utama. Semua saluran yang Anda buat harus dipilih dan diterima oleh pengguna sebelum saluran tersebut muncul di layar utama.

Membuat saluran

Aplikasi Anda harus meminta sistem untuk menampilkan saluran yang baru ditambahkan hanya saat aplikasi sedang berjalan di latar depan. Hal ini mencegah aplikasi menampilkan dialog yang meminta persetujuan untuk menambahkan saluran Anda saat pengguna menjalankan aplikasi lain. Jika Anda mencoba untuk menambahkan saluran saat berjalan di latar belakang, metode onActivityResult() aktivitas akan menampilkan kode status RESULT_CANCELED.

Untuk membuat saluran, ikuti langkah-langkah berikut:

  1. Buat builder saluran dan tetapkan atributnya. Ingat bahwa jenis saluran harus berupa TYPE_PREVIEW. Tambahkan atribut lainnya jika diperlukan.

    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. Masukkan saluran ke penyedia:

    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. Anda perlu menyimpan ID saluran untuk menambahkan program ke saluran nanti. Ekstrak ID saluran dari URI yang ditampilkan:

    Kotlin

        var channelId = ContentUris.parseId(channelUri)
        

    Java

        long channelId = ContentUris.parseId(channelUri);
        
  4. Anda harus menambahkan logo untuk saluran. Gunakan Uri atau Bitmap. Ikon logo harus berukuran 80 dp x 80 dp, dan harus berjenis opaque. Logo ditampilkan di bagian mask berbentuk bundar:

    Mask ikon layar utama 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. Buat saluran default (opsional): Saat aplikasi Anda membuat saluran pertamanya, Anda dapat menjadikannya saluran default sehingga akan muncul langsung di layar utama tanpa tindakan pengguna apa pun. Saluran lain yang Anda buat tidak akan terlihat sampai pengguna memilih secara eksplisit.

    Kotlin

        TvContractCompat.requestChannelBrowsable(context, channelId)
        

    Java

        TvContractCompat.requestChannelBrowsable(context, channelId);
        

  6. Buat saluran default Anda muncul sebelum aplikasi Anda terbuka. Anda dapat membuat perilaku terjadi dengan menambahkan BroadcastReceiver yang memproses tindakan android.media.tv.action.INITIALIZE_PROGRAMS, yang dikirimkan layar utama setelah aplikasi diinstal:
        <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>
        
    Saat men-sideload aplikasi Anda selama pengembangan, Anda dapat menguji dengan memicu intent melalui adb, di mana your.package.name/.YourReceiverName adalah BroadcastReceiver aplikasi Anda:

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

    Dalam kasus yang jarang terjadi, aplikasi Anda mungkin menerima siaran pada saat yang sama saat pengguna memulai aplikasi. Pastikan kode Anda tidak mencoba menambahkan saluran default lebih dari satu kali.

Memperbarui saluran

Memperbarui saluran sangat mirip dengan saat membuatnya.

Gunakan Channel.Builder lain untuk menetapkan atribut yang perlu diubah.

Gunakan ContentResolver untuk memperbarui saluran. Gunakan ID saluran yang Anda simpan saat saluran ditambahkan untuk pertama kalinya:

Kotlin

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

Java

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

Untuk memperbarui logo saluran, gunakan storeChannelLogo().

Menghapus saluran

Kotlin

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

Java

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

Program

Menambahkan program ke saluran aplikasi

Buat PreviewProgram.Builder dan tetapkan atributnya:

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);
    

Tambahkan atribut lain yang bergantung pada jenis program. (Untuk melihat atribut yang tersedia untuk setiap jenis program, lihat tabel di bawah ini.)

Masukkan program ke penyedia:

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());
    

Ambil ID program untuk referensi nanti:

Kotlin

    val programId = ContentUris.parseId(programUri)
    

Java

    long programId = ContentUris.parseId(programUri);
    

Menambahkan program ke saluran Tonton Berikutnya

Memasukkan program ke dalam saluran Tonton Berikutnya sama dengan memasukkan program ke dalam saluran Anda sendiri.

Ada empat jenis program; pilih jenis yang sesuai:

JenisCatatan
WATCH_NEXT_TYPE_CONTINUEPengguna berhenti saat menonton konten.
WATCH_NEXT_TYPE_NEXTProgram yang tersedia berikutnya dalam seri yang ditonton pengguna tersedia. Misalnya, saat pengguna menonton episode 3 dari sebuah serial, aplikasi dapat menyarankan agar mereka menonton episode 4.
WATCH_NEXT_TYPE_NEWKonten baru yang dengan jelas mengikuti apa yang ditonton pengguna kini tersedia. Misalnya, pengguna menonton episode nomor 5 dari sebuah serial dan episode 6 menjadi tersedia untuk ditonton.
WATCH_NEXT_TYPE_WATCHLISTDimasukkan oleh sistem atau aplikasi saat pengguna menyimpan suatu program.

Gunakan WatchNextProgram.Builder:

Kotlin

    val builder = WatchNextProgram.Builder()
    builder.setType(TvContractCompat.WatchNextPrograms.TYPE_CLIP)
            .setWatchNextType(TvContractCompat.WatchNextPrograms.WATCH_NEXT_TYPE_CONTINUE)
            .setLastEngagementTimeUtcMillis(time)
            .setTitle("Title")
            .setDescription("Program description")
            .setPosterArtUri(uri)
            .setIntentUri(uri)
            .setInternalProviderId(appProgramId)

    val watchNextProgramUri = context.contentResolver
            .insert(TvContractCompat.WatchNextPrograms.CONTENT_URI,
                    builder.build().toContentValues())
    

Java

    WatchNextProgram.Builder builder = new WatchNextProgram.Builder();
    builder.setType(TvContractCompat.WatchNextPrograms.TYPE_CLIP)
            .setWatchNextType(TvContractCompat.WatchNextPrograms.WATCH_NEXT_TYPE_CONTINUE)
            .setLastEngagementTimeUtcMillis(time)
            .setTitle("Title")
            .setDescription("Program description")
            .setPosterArtUri(uri)
            .setIntentUri(uri)
            .setInternalProviderId(appProgramId);

    Uri watchNextProgramUri = context.getContentResolver()
            .insert(TvContractCompat.WatchNextPrograms.CONTENT_URI, builder.build().toContentValues());
    

Gunakan TvContractCompat.buildWatchNextProgramUri(long watchNextProgramId) untuk membuat Uri, Anda perlu memperbarui program Tonton Berikutnya.

Saat pengguna menambahkan program ke saluran Tonton Berikutnya, sistem akan menyalin program ke baris. Program akan mengirimkan intent TvContractCompat.ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT untuk memberi tahu aplikasi bahwa program telah ditambahkan. Intent akan menyertakan dua tambahan: ID program yang disalin dan ID program yang dibuat untuk program dalam saluran Tonton Berikutnya.

Memperbarui program

Anda dapat mengubah informasi program. Misalnya, Anda mungkin ingin memperbarui harga sewa untuk sebuah film, atau memperbarui status progres yang menunjukkan jumlah program yang ditonton pengguna.

Gunakan PreviewProgram.Builder untuk menetapkan atribut yang perlu Anda ubah, maka panggil getContentResolver().update untuk memperbarui program. Tentukan ID program yang Anda simpan saat program ditambahkan untuk pertama kali:

Kotlin

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

Java

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

Menghapus program

Kotlin

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

Java

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

Menangani tindakan pengguna

Aplikasi Anda dapat membantu pengguna menemukan konten dengan menyediakan UI untuk menampilkan dan menambahkan saluran. Aplikasi Anda juga harus menangani interaksi dengan saluran setelah muncul di layar utama.

Menemukan dan menambahkan saluran

Aplikasi Anda dapat menyediakan elemen UI yang memungkinkan pengguna memilih dan menambahkan salurannya (misalnya, tombol yang meminta untuk menambahkan saluran).

Setelah pengguna meminta saluran tertentu, jalankan kode ini untuk mendapatkan izin pengguna untuk menambahkannya ke UI layar utama:

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
    }
    

Sistem menampilkan dialog yang meminta pengguna untuk menyetujui saluran. Tangani hasil dari permintaan dalam metode onActivityResult aktivitas Anda (Activity.RESULT_CANCELED atau Activity.RESULT_OK).

Peristiwa layar utama Android TV

Saat pengguna berinteraksi dengan saluran/program yang dipublikasikan oleh aplikasi, layar utama akan mengirimkan intent ke aplikasi:

  • Layar utama mengirimkan Uri yang disimpan dalam atribut APP_LINK_INTENT_URI dari saluran ke aplikasi saat pengguna memilih logo saluran. Aplikasi cukup meluncurkan UI utamanya atau tampilan terkait saluran yang dipilih.
  • Layar utama mengirimkan Uri yang disimpan dalam atribut INTENT_URI dari program ke aplikasi saat pengguna memilih sebuah program. Aplikasi harus memutar konten yang dipilih.
  • Pengguna dapat menunjukkan bahwa mereka tidak lagi tertarik pada program dan ingin menghapusnya dari UI layar utama. Sistem akan menghapus program dari UI dan mengirimkan aplikasi yang memiliki intent program (android.media.tv.ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED atau android.media.tv.ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED) dengan ID program. Aplikasi harus menghapus program dari penyedia dan TIDAK harus memasukkannya kembali.

Pastikan membuat filter intent untuk semua Uris yang dikirimkan layar utama untuk interaksi pengguna; misalnya:

<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>
    

Tips

  • Beberapa aplikasi TV mengharuskan pengguna untuk login. Dalam hal ini, BroadcastReceiver yang memproses android.media.tv.action.INITIALIZE_PROGRAMS harus menyarankan konten saluran untuk pengguna yang tidak diautentikasi. Misalnya, aplikasi Anda mulanya dapat menampilkan konten terbaik atau konten populer saat ini. Setelah pengguna login, aplikasi dapat menampilkan konten yang dipersonalisasi. Ini merupakan peluang besar bagi aplikasi untuk meng-upsell pengguna sebelum mereka login. Aplikasi contoh leanback-homescreen-channels menunjukkan cara memuat saluran setelah aplikasi Anda diinstal (atau setelah penyiapan perangkat jika aplikasi sudah diinstal sebelumnya).
  • Saat aplikasi Anda tidak berada di latar depan dan Anda ingin memperbarui saluran atau program, gunakan JobScheduler untuk menjadwalkan pekerjaan (lihat: JobScheduler{/1 dan JobService).
  • Sistem dapat mencabut izin penyedia aplikasi Anda jika aplikasi melakukan kesalahan (misalnya: terus mengirimkan spam ke penyedia dengan data). Pastikan Anda menggabungkan kode yang mengakses penyedia dengan klausa try-catch untuk menangani pengecualian keamanan.
  • Sebelum memperbarui program dan saluran, minta penyedia untuk data yang Anda perlukan guna memperbarui dan merekonsiliasi data tersebut. Misalnya, tidak perlu memperbarui program yang ingin dihapus pengguna dari UI. Gunakan pekerjaan latar belakang yang menyertakan/memperbarui data Anda ke penyedia setelah meminta data yang ada, kemudian meminta persetujuan untuk saluran Anda. Anda dapat menjalankan pekerjaan ini saat aplikasi memulai dan kapan pun aplikasi perlu memperbarui datanya.

    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
                          }
                      }
                  }
        
  • Gunakan Uri unik untuk semua gambar (logo, ikon, gambar konten) Pastikan untuk menggunakan Uri yang berbeda saat Anda memperbarui gambar. Semua gambar di-cache. Jika tidak mengubah Uri saat Anda mengubah gambar, gambar lama akan terus muncul.

  • Ingat bahwa klausa WHERE tidak diizinkan dan panggilan ke penyedia dengan klausa WHERE akan menampilkan pengecualian keamanan.

Atribut

Bagian ini menjelaskan atribut saluran dan program secara terpisah.

Atribut saluran

Anda harus menentukan atribut ini untuk setiap saluran:

Atribut Catatan
JENIS tetapkan ke TYPE_PREVIEW.
DISPLAY_NAME tetapkan ke nama saluran.
APP_LINK_INTENT_URI Saat pengguna memilih logo saluran, sistem akan mengirimkan intent untuk memulai aktivitas yang menyajikan konten yang relevan dengan saluran. Tetapkan atribut ke Uri yang digunakan dalam filter intent untuk aktivitas itu.

Selain itu, saluran juga memiliki enam kolom yang diperuntukkan untuk penggunaan aplikasi internal. Kolom tersebut dapat digunakan untuk menyimpan kunci atau nilai yang dapat membantu aplikasi memetakan saluran ke struktur data internalnya:

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

Atribut program

Lihat halaman individu untuk atribut bagi setiap jenis program:

Kode Contoh

Untuk mempelajari lebih lanjut tentang membuat aplikasi yang berinteraksi dengan layar utama dan menambahkan saluran dan program ke layar utama Android TV, lihat codelab dan contoh github layar utama kami.