Canais na tela inicial

A tela inicial do Android TV, ou simplesmente tela inicial, fornece uma interface que exibe o conteúdo recomendado como uma tabela de canais e programas. Cada linha é um canal. Um canal contém cards para todos os programas disponíveis nele:

Tela inicial da TV

Este documento demonstra como adicionar canais e programas à tela inicial, atualizar o conteúdo, lidar com ações do usuário e fornecer a melhor experiência para seus usuários. (Se quiser se aprofundar na API, experimente o codelab da tela inicial e assista à sessão do Android TV do I/O 2017 (em inglês).

Observação:os canais de recomendações estão disponíveis apenas em Android 8.0 (nível 26 da API) e versões mais recentes. Você deve usá-los para fornecer recomendações para apps em execução no Android 8.0 (nível 26 da API) e versões mais recentes. Para fornecer recomendações para apps executados em versões anteriores do Android, seu app é necessário usar o linha de recomendações como alternativa.

A IU da tela inicial

Os apps podem criar novos canais, adicionar, remover e atualizar os programas em um canal e controlar a ordem dos programas em um canal. Por exemplo, um app pode criar um canal chamado "Novidades" e mostrar cards de programas recém-disponibilizados.

Os apps não podem controlar a ordem em que os canais aparecem na tela inicial. Quando seu app cria um novo canal, a tela inicial o adiciona à parte inferior da lista de canais. O usuário pode reordenar, ocultar e mostrar canais.

O canal "Assistir a seguir"

O canal "Assistir a seguir" é a segunda linha que aparece na tela inicial, depois de linha "Apps". O sistema cria e mantém esse canal. Seu app pode adicionar programas para o canal "Assistir a seguir". Para mais informações, consulte Adicionar programas ao canal "Assistir a seguir".

Canais do app

Todos os canais criados pelo seu app seguem este ciclo de vida:

  1. O usuário descobre um canal no seu app e solicita que ele seja adicionado à tela inicial.
  2. O app cria o canal e o adiciona a TvProvider (nesse ponto, o canal não está visível).
  3. O app solicita que o sistema exiba o canal.
  4. O sistema pede que o usuário aprove o novo canal.
  5. O novo canal aparece na última linha da tela inicial.

O canal padrão

Seu app pode oferecer qualquer número de canais para o usuário adicionar à tela inicial. O usuário geralmente precisa selecione e aprove cada canal antes que ele apareça na tela inicial. Cada app tem a opção de criar um canal padrão. O canal padrão é especial, porque aparece automaticamente na tela inicial. o usuário não precisa solicitá-la explicitamente.

Pré-requisitos

A tela inicial da Android TV usa as APIs TvProvider do Android para gerenciar os canais e programas criados pelo seu app. Para acessar os dados do provedor, adicione a seguinte permissão ao manifesto do seu app:

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

A Biblioteca de Suporte TvProvider facilita o uso do provedor. Adicione-a às dependências no seu arquivo build.gradle:

Groovy

implementation 'androidx.tvprovider:tvprovider:1.0.0'

Kotlin

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

Para trabalhar com canais e programas, não se esqueça de incluir estas importações da Biblioteca de Suporte no seu programa:

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;

Canais

O primeiro canal criado pelo app se torna o canal padrão. O canal padrão é exibido automaticamente na tela inicial. Todos os outros canais que você criar precisam ser selecionados e aceitos pelo usuário antes de serem exibidos na tela inicial.

Como criar um canal

Seu app pedirá ao sistema para mostrar os canais adicionados recentemente apenas quando ele estiver sendo executado em primeiro plano. Isso impede que o app exiba uma caixa de diálogo solicitando aprovação para adicionar seu canal enquanto o usuário estiver usando um app diferente. Se você tentar adicionar um canal durante a execução em segundo plano, o método onActivityResult() da atividade retornará o código de status RESULT_CANCELED.

Para criar um canal, siga estas etapas:

  1. Crie um gerador de canal e defina os atributos dele. Observe que o o tipo de canal precisa ser TYPE_PREVIEW. Adicionar mais attributes conforme necessário.

    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. Insira o canal no provedor:

    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. É necessário salvar o ID do canal para adicionar programas a ele mais tarde. Extraia o ID do canal do URI retornado:

    Kotlin

    var channelId = ContentUris.parseId(channelUri)
    

    Java

    long channelId = ContentUris.parseId(channelUri);
    
  4. Você precisa adicionar um logotipo para seu canal. Use um Uri ou Bitmap. O logotipo precisa ter 80 dp x 80 dp e ser opaco. Ele é exibido em um máscara circular:

    Máscara de ícone da tela inicial da 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. Criar o canal padrão (opcional): quando seu app criar o primeiro canal. você pode torná-lo o canal padrão para que ele apareça na página inicial tela imediatamente, sem qualquer ação do usuário. Quaisquer outros canais que você criar não ficam visíveis até que o usuário seleciona essas pessoas.

    Kotlin

    TvContractCompat.requestChannelBrowsable(context, channelId)
    

    Java

    TvContractCompat.requestChannelBrowsable(context, channelId);
    

  6. Faça com que seu canal padrão apareça antes que o app seja aberto. Você pode esse comportamento acontece adicionando um BroadcastReceiver que detecta o android.media.tv.action.INITIALIZE_PROGRAMS, que a tela inicial envia após a instalação do app:
    <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>
    
    Ao transferir o aplicativo por sideload durante o desenvolvimento, é possível testar essa etapa acionando a intent pelo adb, em que your.package.name/.YourReceiverName é do seu app BroadcastReceiver:

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

    Em casos raros, o app pode receber a transmissão ao mesmo tempo que o usuário inicia seu app. Verifique se o código não tenta adicionar o canal padrão mais de uma vez.

Como atualizar um canal

Atualizar canais é muito semelhante a criá-los.

Use outro Channel.Builder para definir os atributos que precisam ser mudados.

Use ContentResolver para atualizar o canal. Use o ID do canal que você salvou quando o canal foi adicionado originalmente:

Kotlin

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

Java

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

Para atualizar o logotipo de um canal, use storeChannelLogo().

Como excluir um canal

Kotlin

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

Java

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

Programas

Como adicionar programas a um canal do app

Crie um PreviewProgram.Builder e defina os atributos:

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

Adicione mais atributos dependendo do tipo de programa. Para conferir os atributos disponíveis para cada tipo de programa, consulte as tabelas abaixo.)

Insira o programa no provedor:

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

Recupere o ID do programa para referência futura:

Kotlin

val programId = ContentUris.parseId(programUri)

Java

long programId = ContentUris.parseId(programUri);

Como adicionar programas ao canal "Assistir a seguir"

Para inserir programas no canal "Assistir a seguir", consulte Adicionar programas ao canal "Assistir a seguir" Próximo canal.

Como atualizar um programa

Você pode mudar as informações de um programa. Por exemplo, convém atualizar o preço do aluguel de um filme ou atualizar uma barra de progresso que mostra quanto de um programa o usuário assistiu.

Use um PreviewProgram.Builder para definir os atributos que você precisa mudar. Em seguida, chame getContentResolver().update para atualizar o programa. Especifique o ID do programa que você salvou quando o programa foi adicionado originalmente:

Kotlin

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

Java

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

Como excluir um programa

Kotlin

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

Java

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

Como gerenciar ações do usuário

Seu app pode ajudar os usuários a descobrir o conteúdo fornecendo uma IU para exibir e adicionar canais. Ele também precisa lidar com interações com seus canais depois que eles aparecem na tela inicial.

Como descobrir e adicionar canais

Seu app pode fornecer um elemento de IU que permite ao usuário selecionar e adicionar canais (por exemplo, um botão que pede para adicionar o canal).

Depois que o usuário solicitar um canal específico, execute este código para receber a permissão do usuário para adicioná-lo à IU da tela inicial:

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
}

O sistema exibe uma caixa de diálogo solicitando que o usuário aprove o canal. Gerencie o resultado da solicitação no método onActivityResult da sua atividade (Activity.RESULT_CANCELED ou Activity.RESULT_OK).

Eventos da tela inicial do Android TV

Quando o usuário interage com os programas/canais publicados pelo app, a tela inicial envia intents para o app:

  • A tela inicial envia o Uri armazenado no atributo APP_LINK_INTENT_URI de um canal para o app quando o usuário seleciona o logotipo do canal. O app precisa abrir a IU principal ou uma visualização relacionada ao canal selecionado.
  • A tela inicial envia o Uri armazenado no atributo INTENT_URI de um programa para o app quando o usuário seleciona um programa. O app precisa reproduzir o conteúdo selecionado.
  • O usuário pode indicar que não está mais interessado em um programa e quer removê-lo da IU da tela inicial. O sistema removerá o programa da IU e enviará ao app proprietário do programa um intent (android.media.tv.ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED ou android.media.tv.ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED) com o ID do programa. O app precisa remover o programa do provedor e NÃO reinseri-lo.

Não esqueça de criar filtros de intent para todos os Uris que a tela inicial envia para interações de usuário. Por exemplo:

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

Práticas recomendadas

  • Muitos apps de TV exigem que os usuários façam login. Nesse caso, o BroadcastReceiver que detecta android.media.tv.action.INITIALIZE_PROGRAMS vai sugerir conteúdo do canal para usuários não autenticados.Por exemplo, seu app pode começar mostram o melhor conteúdo ou o conteúdo em alta no momento. Depois que o usuário faz login, ele podem mostrar conteúdo personalizado. Essa é uma ótima oportunidade para fazer o upsell dos apps usuários antes do login.
  • Quando seu app não está em primeiro plano e você precisa atualizar um canal ou um programa, use o JobScheduler para programar o trabalho (consulte: JobScheduler e JobService).
  • O sistema pode revogar as permissões de provedor do seu aplicativo caso o aplicativo tenha um comportamento inadequado Por exemplo: enviar spam continuamente para o provedor com dados. Certifique-se de unem o código que acessa o provedor com cláusulas try-catch para lidar com exceções de segurança.
  • Antes de atualizar programas e canais, consulte o provedor para saber quais dados você precisam atualizar e reconciliar os dados. Por exemplo, não é preciso atualizar um programa que o usuário quer remover da interface. Use um job em segundo plano que insere/atualiza seus dados no provedor depois de consultar as e solicitar aprovação para seus canais. É possível executar esse job o aplicativo é iniciado e sempre que o aplicativo precisa atualizar seus dados.

    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
                      }
                  }
              }
    
  • Use URIs exclusivos para todas as imagens (logotipos, ícones, imagens de conteúdo). Use um URI diferente ao atualizar uma imagem. Todas as imagens são armazenadas em cache. Se você não mudar o URI quando mudar a imagem, a imagem antiga continuará aparecendo.

  • Lembre-se de que cláusulas WHERE não são permitidas, e chamadas para os provedores com cláusulas WHERE gerarão uma exceção de segurança.

Atributos

Esta seção descreve os atributos do canal e do programa separadamente.

Atributos do canal

Você precisa especificar estes atributos para cada canal:

Atributo Observações
TYPE defina como TYPE_PREVIEW.
DISPLAY_NAME defina como o nome do canal.
APP_LINK_INTENT_URI Quando o usuário seleciona o logotipo do canal, o sistema envia um intent para iniciar uma atividade que apresenta conteúdo relevante para o canal. Defina esse atributo como o URI usado no filtro de intent dessa atividade.

Além disso, um canal também tem seis campos reservados para uso interno do app. Esses campos podem ser usados para armazenar chaves ou outros valores que podem ajudar o app a mapear o canal para a estrutura de dados interna:

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

Atributos do programa

Veja as páginas individuais para os atributos de cada tipo de programa:

Exemplo de código

Para saber mais sobre como criar apps que interagem com a tela inicial e adicionar canais e programas à tela inicial da Android TV, consulte o codelab da tela inicial.