Каналы на главном экране

На главном экране Android TV рекомендованный контент представлен в виде таблицы каналов и программ. Каждая строка соответствует одному каналу. Канал содержит карточки для всех доступных на нем программ.

Главный экран Android TV
Главный экран Android TV

В этом документе показано, как добавлять каналы и программы на главный экран, обновлять контент, обрабатывать действия пользователей и обеспечивать наилучшие условия для пользователей. Если вы хотите узнать больше об API, попробуйте практическую работу по главному экрану и посмотрите семинар по Android TV на I/O 2017.

Интерфейс главного экрана

Приложения могут создавать новые каналы, добавлять, удалять и обновлять программы в канале, а также управлять порядком программ в канале. Например, приложение может создать канал "Что нового" и показывать карточки с недавно добавленными программами.

Приложения не могут управлять порядком, в котором каналы появляются на главном экране. Когда приложение создает новый канал, он добавляется в конец списка на главном экране. Пользователь может менять порядок каналов, а также скрывать и показывать их.

Канал "Смотреть дальше"

Канал "Смотреть дальше" – это вторая строка на главном экране, которая находится под строкой приложений. Этот канал создается и поддерживается системой. Ваше приложение может добавлять программы в канал "Смотреть дальше". Подробнее о том, как добавлять программы в канал "Смотреть дальше"…

Каналы приложений

Все каналы, создаваемые приложением, проходят следующий жизненный цикл:

  1. Пользователь находит канал в вашем приложении и запрашивает его добавление на главный экран.
  2. Приложение создает канал и добавляет его в TvProvider (на этом этапе канал не виден).
  3. Приложение запрашивает у системы показ канала.
  4. Система просит пользователя одобрить новый канал.
  5. Новый канал появится в последней строке главного экрана.

Канал по умолчанию

Приложение может предлагать пользователю любое количество каналов для добавления на главный экран. Обычно пользователю нужно выбрать и одобрить каждый канал, прежде чем он появится на главном экране. В каждом приложении можно создать один канал по умолчанию. Канал по умолчанию автоматически появляется на главном экране, и пользователю не нужно запрашивать его.

Требования

На главном экране Android TV используются API TvProvider Android для управления каналами и программами, которые создает ваше приложение. Чтобы получить доступ к данным поставщика, добавьте в манифест приложения следующее разрешение:

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

Библиотека поддержки TvProvider упрощает использование поставщика. Добавьте его в зависимости в файле build.gradle:

Яркий

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. Чтобы добавлять программы на канал, вам нужно сохранить идентификатор канала. Извлеките идентификатор канала из возвращенного URI:

    Kotlin

    var channelId = ContentUris.parseId(channelUri)
    

    Java

    long channelId = ContentUris.parseId(channelUri);
    
  4. Добавьте логотип канала. Используйте Uri или Bitmap. Значок логотипа должен быть непрозрачным и иметь размер 80 x 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);
    
  5. Создайте канал по умолчанию (необязательно). При создании первого канала в приложении вы можете сделать его каналом по умолчанию, чтобы он сразу появлялся на главном экране без каких-либо действий со стороны пользователя. Любые другие созданные вами каналы не будут видны, пока пользователь явно не выберет их.

    Kotlin

    TvContractCompat.requestChannelBrowsable(context, channelId)
    

    Java

    TvContractCompat.requestChannelBrowsable(context, channelId);
    
  6. Сделайте так, чтобы канал по умолчанию появлялся до открытия приложения. Для этого добавьте 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
    

    В редких случаях приложение может получить широковещательное сообщение в момент запуска. Убедитесь, что ваш код не пытается добавить канал по умолчанию несколько раз.

Обновление канала

Обновление каналов выполняется почти так же, как и их создание.

Используйте другой атрибут Channel.Builder, чтобы задать атрибуты, которые нужно изменить.

Обновите канал с помощью ContentResolver. Используйте идентификатор канала, который вы сохранили, когда канал был добавлен:

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

Получите идентификатор программы, чтобы использовать его в дальнейшем:

Kotlin

val programId = ContentUris.parseId(programUri)

Java

long programId = ContentUris.parseId(programUri);

Как добавлять программы на канал "Смотреть дальше"

Чтобы добавить программы в канал "Смотреть дальше", ознакомьтесь с разделом Добавление программ в канал "Смотреть дальше".

Как обновить программу

Вы можете изменить информацию о программе. Например, вы можете обновить цену проката фильма или индикатор выполнения, показывающий, какую часть программы пользователь уже посмотрел.

Используйте PreviewProgram.Builder, чтобы задать атрибуты, которые нужно изменить, а затем вызовите getContentResolver().update, чтобы обновить программу. Укажите идентификатор программы, который вы сохранили при ее добавлении:

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

Обработка действий пользователя

Вы можете добавить в приложение интерфейс, который позволит пользователям находить и добавлять каналы. Приложение также должно обрабатывать взаимодействия с каналами после их появления на главном экране.

Поиск и добавление каналов

В приложении можно добавить элемент интерфейса, позволяющий пользователю выбрать и добавить каналы (например, кнопку с предложением добавить канал).

После того как пользователь запросит определенный канал, выполните этот код, чтобы получить разрешение пользователя на добавление канала в интерфейс главного экрана:

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 (Activity.RESULT_CANCELED или Activity.RESULT_OK).

События на главном экране Android TV

Когда пользователь взаимодействует с программами и каналами, опубликованными приложением, главный экран отправляет приложению намерения:

  • Когда пользователь нажимает на логотип канала, главный экран отправляет в приложение значение Uri, сохраненное в атрибуте APP_LINK_INTENT_URI канала. Приложение должно просто запустить свой основной пользовательский интерфейс или представление, связанное с выбранным каналом.
  • Когда пользователь выбирает программу, главный экран отправляет в приложение значение Uri, сохраненное в атрибуте INTENT_URI программы. Приложение должно воспроизвести выбранный контент.
  • Пользователь может указать, что его больше не интересует программа и он хочет удалить ее с главного экрана. Система удаляет программу из интерфейса и отправляет приложению, которому принадлежит программа, намерение (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>

Дополнительные сведения

  • Для работы со многими ТВ-приложениями требуется вход в аккаунт. В этом случае BroadcastReceiver, который ожидает android.media.tv.action.INITIALIZE_PROGRAMS, должен предлагать контент канала для неаутентифицированных пользователей. Например, в приложении можно сначала показывать лучший или популярный контент. После входа в аккаунт пользователю может показываться персонализированный контент. Это отличная возможность для приложений продавать пользователям дополнительные услуги до того, как они войдут в систему.
  • Если приложение неактивно и вам нужно обновить канал или программу, используйте JobScheduler, чтобы запланировать работу (см. JobScheduler и JobService).
  • Система может отозвать разрешения поставщика, если приложение работает некорректно (например, постоянно отправляет поставщику спам). Обязательно оберните код, который обращается к поставщику, в блоки try-catch, чтобы обрабатывать исключения безопасности.
  • Перед обновлением программ и каналов запросите у поставщика данные, которые необходимо обновить, и сверьте их. Например, не нужно обновлять программу, которую пользователь хочет удалить из интерфейса. Используйте фоновое задание, которое вставляет или обновляет данные в поставщике после запроса существующих данных, а затем запрашивает одобрение для ваших каналов. Вы можете запускать это задание при запуске приложения и всякий раз, когда приложению необходимо обновить свои данные.

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 &amp;&amp; cursor.moveToNext()) {
                      Channel channel = Channel.fromCursor(cursor);
                      if (channel.isBrowsable()) {
                          //update channel's programs
                      }
                  }
              }
  • Используйте уникальные URI для всех изображений (логотипов, значков, изображений контента). При обновлении изображения обязательно используйте другой URI. Все изображения кешируются. Если вы не измените URI при изменении изображения, будет по-прежнему показываться старое изображение.

  • Помните, что операторы WHERE не разрешены, и вызовы поставщиков с операторами WHERE вызовут исключение безопасности.

Атрибуты

В этом разделе атрибуты каналов и программ описаны отдельно.

Атрибуты канала

Для каждого канала необходимо указать следующие атрибуты:

Атрибут Примечания
ПЕЧАТ задано значение TYPE_PREVIEW.
DISPLAY_NAME имеет значение, равное названию канала.
APP_LINK_INTENT_URI Когда пользователь выбирает логотип канала, система отправляет намерение начать действие, которое представляет контент, относящийся к каналу. Укажите в этом атрибуте URI, который используется в фильтре интентов для этого объекта Activity.

Кроме того, в канале есть шесть полей, зарезервированных для внутреннего использования приложения. Эти поля можно использовать для хранения ключей или других значений, которые помогают приложению сопоставить канал со своей внутренней структурой данных:

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

Атрибуты программы

Подробную информацию об атрибутах для каждого типа программ можно найти на следующих страницах:

Пример кода

Чтобы узнать больше о создании приложений, взаимодействующих с главным экраном, и добавлении каналов и программ на главный экран Android TV, ознакомьтесь с практической работой.