La pantalla principal de Android TV, o simplemente pantalla principal, proporciona una IU que muestra el contenido recomendado en una tabla de canales y programas. Cada fila corresponde a un canal. Un canal, a su vez, tiene tarjetas para cada uno de sus programas:
En este documento, se muestra cómo agregar canales y programas a la pantalla principal, actualizar contenido, controlar las acciones del usuario y proporcionar la mejor experiencia posible para todos los usuarios. (Si quieres indagar más en la API, prueba el codelab de la pantalla principal y mira la sesión de Android TV de I/O 2017).
Nota: Los canales de recomendaciones solo están disponibles en Android 8.0 (API nivel 26) y versiones posteriores. Debes usarlos si quieres proporcionar recomendaciones para las apps que se ejecutan en Android 8.0 (API nivel 26) y versiones posteriores. A fin de proporcionar recomendaciones para apps que se ejecutan en versiones anteriores de Android, tu app, en su lugar, debe usar la fila de recomendaciones.
IU de la pantalla principal
Las apps pueden crear nuevos canales, o bien agregar, quitar y actualizar programas en un canal, así como controlar el orden de los programas de un canal. Por ejemplo, una app puede crear un canal denominado "Novedades" y mostrar tarjetas para los nuevos programas disponibles.
Las apps no pueden controlar el orden en que se muestran los canales en la pantalla principal. Cuando tu app crea un nuevo canal, la pantalla principal lo agrega a la parte inferior de la lista de canales. El usuario puede reordenar, ocultar y mostrar los canales.
Canal "Ver a continuación"
El canal "Ver a continuación" es la segunda fila que se muestra en la pantalla principal, después de la fila de apps. El sistema crea y mantiene este canal. Tu app puede agregar programas a ese canal. Para obtener más información, consulta Cómo agregar programas al canal "Ver a continuación".
Canales de apps
Todos los canales que crea la app siguen este ciclo de vida:
- El usuario detecta un canal en tu app y solicita agregarlo a la pantalla principal.
- La app crea el canal y lo agrega a
TvProvider
(en este momento, el canal no es visible). - La app le solicita al sistema que muestre el canal.
- El sistema le solicita al usuario que apruebe el nuevo canal.
- El nuevo canal se muestra en la última fila de la pantalla principal.
Canal predeterminado
Tu app puede ofrecer cualquier número de canales para que el usuario los agregue a la pantalla principal. A fin de que estos aparezcan, el usuario debe seleccionar y aprobar cada uno. Cada app tiene la opción de crear un canal predeterminado. El canal predeterminado es especial porque se muestra automáticamente en la pantalla principal; el usuario no tiene que solicitarlo de forma explícita.
Requisitos previos
La pantalla principal de Android TV usa las API de TvProvider
de Android para administrar los canales y programas que crea tu app.
Para acceder a los datos del proveedor, agrega el siguiente permiso al manifiesto de la app:
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
La biblioteca de compatibilidad TvProvider
facilita el uso del proveedor. Agrégala a las dependencias de tu archivo build.gradle
:
compile 'com.android.support:support-tv-provider:27.0.0'
Para trabajar con canales y programas, asegúrate de incluir estas importaciones de la biblioteca de compatibilidad en tu 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;
Canales
El primer canal que crea tu app se convierte en el canal predeterminado. El canal predeterminado se muestra automáticamente en la pantalla principal. El usuario debe seleccionar y aceptar todos los demás canales que crees para que estos se muestren en la pantalla principal.
Cómo crear un canal
Tu app debe solicitar al sistema que muestre los últimos canales agregados solo cuando se ejecuta en segundo plano. De esta manera, se evita que tu app muestre un cuadro de diálogo solicitando la aprobación para agregar el canal mientras el usuario ejecuta otra app. Si intentas agregar un canal mientras se ejecuta en segundo plano, el método onActivityResult()
de la actividad muestra el código de estado RESULT_CANCELED
.
Para crear un canal, sigue estos pasos:
Diseña un compilador de canales y establece sus atributos. Ten en cuenta que el tipo de canal debe ser
TYPE_PREVIEW
. Agrega más atributos según sea necesario.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);Inserta el canal en el proveedor:
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());
-
Debes guardar el ID de canal en orden para agregar programas al canal más tarde. Extrae el ID de canal de la URI que se muestra:
Kotlin
var channelId = ContentUris.parseId(channelUri)
Java
long channelId = ContentUris.parseId(channelUri);
Debes agregar un logotipo para el canal. Usa un elemento
Uri
oBitmap
. El icono del logotipo debe ser opaco y de 80 dp x 80 dp. Se mostrará con una máscara circular: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);
Crea el canal predeterminado (opcional). Cuando tu app crea el primer canal, puedes convertirlo en el canal predeterminado para que se muestre en la pantalla principal de inmediato sin necesidad de ninguna acción del usuario. El resto de los canales que creas no se muestran hasta que el usuario los selecciona de forma explícita.
Kotlin
TvContractCompat.requestChannelBrowsable(context, channelId)
Java
TvContractCompat.requestChannelBrowsable(context, channelId);
- Puedes hacer que el canal predeterminado se muestre antes de que el usuario abra la app. Puedes hacer que se produzca este comportamiento si agregas un elemento
BroadcastReceiver
que escuche la acciónandroid.media.tv.action.INITIALIZE_PROGRAMS
, que la pantalla principal enviará después de instalar la 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>
Si transfieres tu app durante el desarrollo, para probar este paso, puedes activar el intent mediante adb, donde your.package.name/.YourReceiverName es el elementoBroadcastReceiver
de tu app:adb shell am broadcast -a android.media.tv.action.INITIALIZE_PROGRAMS -n \ your.package.name/.YourReceiverName
En unos pocos casos, es posible que tu app reciba la emisión al mismo tiempo que el usuario la inicia. Asegúrate de que tu código no intente agregar el canal predeterminado más de una vez.
Cómo actualizar un canal
La actualización de canales es muy similar a la creación.
Usa otro Channel.Builder
para configurar los atributos que deben cambiarse.
Usa ContentResolver
para actualizar el canal. Usa el ID de canal que guardaste cuando se agregó el canal 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 actualizar el logotipo de un canal, usa storeChannelLogo()
.
Cómo borrar un canal
Kotlin
context.contentResolver.delete(TvContractCompat.buildChannelUri(channelId), null, null)
Java
context.getContentResolver().delete(TvContractCompat.buildChannelUri(channelId), null, null);
Programas
Cómo agregar programas a un canal de app
Crea un PreviewProgram.Builder
y establece sus 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);
Agrega más atributos según el tipo de programa. (Puedes ver los atributos disponibles para cada tipo de programa en las tablas a continuación).
Inserta el programa en el proveedor:
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());
Obtén el ID de programa para referencia futura:
Kotlin
val programId = ContentUris.parseId(programUri)
Java
long programId = ContentUris.parseId(programUri);
Cómo agregar programas al canal "Ver a continuación"
Para insertar programas en el canal "Ver a continuación", consulta Cómo agregar programas al canal "Ver a continuación".
Cómo actualizar un programa
Puedes cambiar la información de un programa, por ejemplo, si quieres actualizar el precio del alquiler de una película o actualizar la barra de progreso que muestra qué porcentaje de un programa vio el usuario.
Usa un elemento PreviewProgram.Builder
para establecer los atributos que necesitas cambiar y luego llama a getContentResolver().update
para actualizar el programa. Especifica el ID de programa que guardaste cuando se agregó originalmente el programa:
Kotlin
context.contentResolver.update( TvContractCompat.buildPreviewProgramUri(programId), builder.build().toContentValues(), null, null )
Java
context.getContentResolver().update(TvContractCompat.buildPreviewProgramUri(programId), builder.build().toContentValues(), null, null);
Cómo borrar un programa
Kotlin
context.contentResolver .delete(TvContractCompat.buildPreviewProgramUri(programId), null, null)
Java
context.getContentResolver().delete(TvContractCompat.buildPreviewProgramUri(programId), null, null);
Cómo controlar las acciones del usuario
Tu app can puede ayudar a los usuarios a descubrir contenido mediante una IU que permita mostrar y agregar programas. La app también deberá controlar las interacciones con tus canales una vez que se muestren en la pantalla principal.
Cómo descubrir y agregar canales
Tu app puede proporcionar un elemento de IU que permita al usuario seleccionar y agregar sus canales (por ejemplo, un botón que solicite agregar el canal).
Después de que el usuario solicite un canal específico, ejecuta este código para obtener el permiso del usuario y agregarlo a la IU de la pantalla principal:
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 }
El sistema muestra un diálogo que solicita al usuario que apruebe el canal.
Controla el resultado de la solicitud en el método onActivityResult
de tu actividad (Activity.RESULT_CANCELED
o Activity.RESULT_OK
).
Eventos de la pantalla principal de Android TV
Cuando el usuario interactúa con los programas/canales publicados por la app, la pantalla principal envía instancias de intent a la app:
- La pantalla principal envía el elemento
Uri
almacenado en el atributo APP_LINK_INTENT_URI de un canal a la app cuando el usuario selecciona el logotipo del canal. La app debe lanzar su IU principal o una vista relacionada con el canal seleccionado. - La pantalla principal envía el elemento
Uri
almacenado en el atributo INTENT_URI de un programa a la app cuando el usuario selecciona un programa. La app debe mostrar el contenido seleccionado. - El usuario puede indicar que ya no está interesado en un programa y que quiere quitarlo de la IU de la pantalla principal. El sistema quita el programa de la IU y envía a la app propietaria del programa un intent (android.media.tv.ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED o android.media.tv.ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED) con el ID del programa. La app debe quitar el programa del proveedor y NO volver a insertarlo.
Asegúrate de crear filtros de intents para todos los elementos Uris
que la pantalla principal envía sobre interacciones del usuario, por ejemplo:
<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>
Recomendaciones
- Muchas apps de TV requieren que los usuarios accedan. En este caso, el elemento
BroadcastReceiver
que escuchaandroid.media.tv.action.INITIALIZE_PROGRAMS
debe sugerir el contenido del canal para los usuarios no autenticados. Por ejemplo, tu app inicialmente puede mostrar el mejor contenido o el más popular. Una vez que el usuario accede, puede mostrar contenido personalizado. Esto es ideal para realizar ventas verticales de apps a los usuarios antes de que accedan. - Cuando tu app no está en primer plano y necesitas actualizar un canal o un programa, usa
JobScheduler
para programar el trabajo (consulta JobScheduler y JobService). - El sistema puede revocar los permisos del proveedor de tu app si esta no funciona de manera correcta (por ejemplo, si envía spam de datos continuamente al proveedor). Asegúrate de encapsular el código que accede al proveedor con cláusulas try-catch para controlar las excepciones de seguridad.
Antes de actualizar los programas y canales, pídele al proveedor los datos que necesitas para hacer la actualización y concílialos. Por ejemplo, no es necesario actualizar un programa que el usuario desea quitar de la IU. Usa un trabajo en segundo plano que inserte/actualice los datos en el proveedor después de consultar sobre los datos existentes y solicitar la aprobación de los canales. Puedes ejecutar este trabajo cuando se inicia la app y cuando esta necesita actualizar sus datos.
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 URI exclusivas para todas las imágenes (logotipos, íconos, imágenes de contenido). Asegúrate de usar una URI diferente cuando actualices una imagen. Todas las imágenes se almacenan en caché. Si no modificas URI cuando cambias la imagen, se seguirá mostrando la imagen anterior.
Recuerda que las cláusulas WHERE no están permitidas y las llamadas a los proveedores con cláusulas WHERE generarán una excepción de seguridad.
Atributos
En esta sección, se describen los atributos de canal y de programa por separado.
Atributos de canal
Debes especificar los siguientes atributos para cada canal:
Atributo | Notas |
---|---|
TIPO | Se define en TYPE_PREVIEW . |
DISPLAY_NAME | Se define en el nombre del canal. |
APP_LINK_INTENT_URI | Cuando el usuario selecciona el logotipo del canal, el sistema envía un intent para iniciar una actividad que presenta el contenido relevante al canal. Define este atributo en la URI usada por el filtro de intent para esa actividad. |
Además, un canal también tiene seis campos reservados para uso interno de la app. Estos campos se pueden usar para almacenar claves y otros valores que pueden ayudar a la app a asignar el canal a la estructura interna de datos:
- INTERNAL_PROVIDER_ID
- INTERNAL_PROVIDER_DATA
- INTERNAL_PROVIDER_FLAG1
- INTERNAL_PROVIDER_FLAG2
- INTERNAL_PROVIDER_FLAG3
- INTERNAL_PROVIDER_FLAG4
Atributos de programa
Consulta las páginas individuales de los atributos para cada tipo de programa:
- Atributos de programa de video
- Atributos de programa de audio
- Atributo de programa de juegos
- Atributos de programa "Ver a continuación"
Código de muestra
Para obtener más información sobre cómo compilar apps que interactúan con la pantalla principal y agregar canales y programas a la pantalla principal de Android TV, consulta el codelab de la pantalla principal.