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

Главный экран Android TV или просто главный экран предоставляет пользовательский интерфейс, который отображает рекомендуемый контент в виде таблицы каналов и программ . Каждая строка представляет собой канал. Канал содержит карточки для каждой программы, доступной на этом канале:

Главный экран телевизора

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

Примечание. Каналы рекомендаций доступны только в Android 8.0 (уровень API 26) и более поздних версиях. Их необходимо использовать для предоставления рекомендаций для приложений, работающих в Android 8.0 (уровень API 26) и более поздних версиях. Чтобы предоставить рекомендации для приложений, работающих на более ранних версиях Android, ваше приложение должно использовать вместо этого строку рекомендаций .

Пользовательский интерфейс главного экрана

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

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

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

Канал «Смотреть дальше» — это вторая строка, которая появляется на главном экране после строки приложений. Система создает и поддерживает этот канал. Ваше приложение может добавлять программы на канал Watch Next. Дополнительную информацию см. в разделе Добавление программ на канал «Смотреть дальше» .

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

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

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

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

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

Предварительные условия

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

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

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

классный

implementation 'androidx.tvprovider:tvprovider:1.0.0'

Котлин

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

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

Котлин

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

Ява

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 . При необходимости добавьте дополнительные атрибуты .

    Котлин

    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)
    

    Ява

    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. Вставляем канал в провайдер:

    Котлин

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

    Ява

    Uri channelUri = context.getContentResolver().insert(
            TvContractCompat.Channels.CONTENT_URI, builder.build().toContentValues());
    
  3. Вам необходимо сохранить идентификатор канала, чтобы в дальнейшем добавлять программы на канал. Извлеките идентификатор канала из возвращенного URI:

    Котлин

    var channelId = ContentUris.parseId(channelUri)
    

    Ява

    long channelId = ContentUris.parseId(channelUri);
    
  4. Вам необходимо добавить логотип для своего канала. Используйте Uri или Bitmap . Размер значка логотипа должен быть 80 x 80 dp, и он должен быть непрозрачным. Он отображается под круглой маской:

    Маска значка главного экрана телевизора

    Котлин

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

    Ява

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

    Котлин

    TvContractCompat.requestChannelBrowsable(context, channelId)
    

    Ява

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

Котлин

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

Ява

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

Чтобы обновить логотип канала, используйте storeChannelLogo() .

Удаление канала

Котлин

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

Ява

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

Программы

Добавление программ в канал приложения

Создайте PreviewProgram.Builder и установите его атрибуты:

Котлин

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

Ява

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

Добавьте больше атрибутов в зависимости от типа программы. (Чтобы увидеть атрибуты, доступные для каждого типа программы, обратитесь к таблицам ниже.)

Вставляем программу в провайдер:

Котлин

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

Ява

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

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

Котлин

val programId = ContentUris.parseId(programUri)

Ява

long programId = ContentUris.parseId(programUri);

Добавление программ на канал Watch Next

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

Обновление программы

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

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

Котлин

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

Ява

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

Удаление программы

Котлин

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

Ява

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

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

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

Обнаружение и добавление каналов

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

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

Котлин

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
}

Ява

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

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

  • Главный экран отправляет 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 для обработки исключений безопасности.
  • Прежде чем обновлять программы и каналы, запросите у провайдера данные, необходимые для обновления и согласования данных. Например, нет необходимости обновлять программу, которую пользователь хочет удалить из пользовательского интерфейса. Используйте фоновое задание, которое вставляет или обновляет ваши данные в поставщике после запроса существующих данных и последующего запроса утверждения для ваших каналов. Вы можете запускать это задание при запуске приложения и всякий раз, когда приложению необходимо обновить свои данные.

    Котлин

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

    Ява

    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
                      }
                  }
              }
    
  • Используйте уникальные Uris для всех изображений (логотипов, значков, изображений контента). Обязательно используйте другой Uri при обновлении изображения. Все изображения кэшируются. Если вы не измените Uri при смене изображения, старое изображение продолжит появляться.

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

Атрибуты

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

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

Вы должны указать эти атрибуты для каждого канала:

Атрибут Примечания
ТИП установлен на TYPE_PREVIEW .
ОТОБРАЖАЕМОЕ ИМЯ установите имя канала.
APP_LINK_INTENT_URI Когда пользователь выбирает логотип канала, система отправляет намерение начать действие, представляющее контент, относящийся к каналу. Установите для этого атрибута Uri, используемый в фильтре намерений для этого действия.

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

  • INTERNAL_PROVIDER_ID
  • ВНУТРЕННИЕ_ПРОВИДЕРЫ_ДАННЫЕ
  • INTERNAL_PROVIDER_FLAG1
  • INTERNAL_PROVIDER_FLAG2
  • INTERNAL_PROVIDER_FLAG3
  • INTERNAL_PROVIDER_FLAG4

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

См. отдельные страницы для атрибутов каждого типа программы:

Пример кода

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