Utiliser les données de chaîne

Votre entrée TV doit fournir les données du guide des programmes électronique (EPG) pendant au moins un canal dans son activité de configuration. Vous devez également mettre régulièrement à jour données, en tenant compte de la taille de la mise à jour et du thread de traitement qui le gère. Vous pouvez également fournir des liens vers l'application pour les chaînes. qui guident l'utilisateur vers du contenu et des activités connexes. Cette leçon explique comment créer et mettre à jour les données d'une chaîne et d'un programme la base de données système en tenant compte de ces considérations.

Essayez le Exemple d'application TV Input Service.

Obtenir l'autorisation

Pour que votre entrée TV fonctionne avec les données EPG, elle doit déclarer l'élément l'autorisation d'écriture dans son fichier manifeste Android, comme suit:

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

Enregistrer des canaux dans la base de données

La base de données du système Android TV conserve des enregistrements des données de chaîne pour les entrées TV. Dans votre configuration d'activité, pour chacun de vos canaux, vous devez mapper les données de votre chaîne avec les champs suivants de la Classe TvContract.Channels:

Bien que le cadre d'entrée TV soit suffisamment générique pour gérer à la fois la diffusion traditionnelle et de service de distribution par contournement (OTT, over-the-top) sans distinction, vous pouvez définir les colonnes suivantes dans en plus de celles mentionnées ci-dessus afin de mieux identifier les chaînes de diffusion traditionnelles:

Si vous souhaitez fournir des liens vers une application pour vos chaînes, vous devez : mettre à jour quelques champs supplémentaires. Pour en savoir plus sur les champs de lien d'application, consultez Ajoutez des informations sur les liens vers une application.

Pour les entrées TV basées sur le streaming sur Internet, attribuez vos propres valeurs aux valeurs ci-dessus en conséquence. chaque canal peut être identifié de manière unique.

Extrayez les métadonnées de votre chaîne (au format XML, JSON ou autre) depuis votre serveur backend et dans votre configuration. l'activité mappe les valeurs à la base de données système comme suit:

Kotlin

val values = ContentValues().apply {
    put(TvContract.Channels.COLUMN_DISPLAY_NUMBER, channel.number)
    put(TvContract.Channels.COLUMN_DISPLAY_NAME, channel.name)
    put(TvContract.Channels.COLUMN_ORIGINAL_NETWORK_ID, channel.originalNetworkId)
    put(TvContract.Channels.COLUMN_TRANSPORT_STREAM_ID, channel.transportStreamId)
    put(TvContract.Channels.COLUMN_SERVICE_ID, channel.serviceId)
    put(TvContract.Channels.COLUMN_VIDEO_FORMAT, channel.videoFormat)
}
val uri = context.contentResolver.insert(TvContract.Channels.CONTENT_URI, values)

Java

ContentValues values = new ContentValues();

values.put(Channels.COLUMN_DISPLAY_NUMBER, channel.number);
values.put(Channels.COLUMN_DISPLAY_NAME, channel.name);
values.put(Channels.COLUMN_ORIGINAL_NETWORK_ID, channel.originalNetworkId);
values.put(Channels.COLUMN_TRANSPORT_STREAM_ID, channel.transportStreamId);
values.put(Channels.COLUMN_SERVICE_ID, channel.serviceId);
values.put(Channels.COLUMN_VIDEO_FORMAT, channel.videoFormat);

Uri uri = context.getContentResolver().insert(TvContract.Channels.CONTENT_URI, values);

Dans l'exemple ci-dessus, channel est un objet qui contient les métadonnées de la chaîne provenant du à un serveur backend.

Présenter des informations sur la chaîne et le programme

L'appli System TV présente des informations sur les chaînes et les programmes aux utilisateurs lorsqu'ils parcourent les chaînes. comme illustré dans la figure 1. Pour s'assurer que les informations de la chaîne et du programme fonctionnent avec le système les informations sur la chaîne et le programme, suivez les consignes ci-dessous.

  1. Numéro de la chaîne (COLUMN_DISPLAY_NUMBER)
  2. Icône (android:icon dans le fichier manifeste de l'entrée TV)
  3. Program description (Description du programme) (COLUMN_SHORT_DESCRIPTION)
  4. Titre du programme (COLUMN_TITLE)
  5. Logo de la chaîne (TvContract.Channels.Logo) <ph type="x-smartling-placeholder">
      </ph>
    • Utilisez la couleur #EEEEEE pour faire correspondre le texte environnant.
    • Ne pas inclure de marge intérieure
  6. Poster art (COLUMN_POSTER_ART_URI) <ph type="x-smartling-placeholder">
      </ph>
    • Format entre 16:9 et 4:3

Figure 1 : Présentateur des informations sur le programme et la chaîne de l'application TV système.

L'appli System TV fournit les mêmes informations via le guide des programmes, y compris l'affiche, comme illustré dans la figure 2.

Figure 2. Le guide des programmes de l'application System TV

Mettre à jour les données de la chaîne

Lorsque vous mettez à jour les données d'un canal existant, utilisez le update() au lieu de supprimer et d'ajouter à nouveau les données. Vous pouvez identifier la version actuelle des données en utilisant Channels.COLUMN_VERSION_NUMBER et Programs.COLUMN_VERSION_NUMBER lorsque vous choisissez les enregistrements à mettre à jour.

Remarque:Ajouter les données de la chaîne au ContentProvider peut prendre du temps. Ajouter les programmes en cours (ceux qui se trouvent à moins de deux heures de l'heure actuelle) uniquement lorsque vous configurez votre EpgSyncJobService pour mettre à jour le reste des données de la chaîne en arrière-plan. Voir le <ph type="x-smartling-placeholder"></ph> Exemple d'application Android TV Live TV.

Chargement par lot des données de canaux

Lorsque vous mettez à jour la base de données système avec une grande quantité de données de canaux, utilisez ContentResolver applyBatch() ou bulkInsert() . Voici un exemple avec applyBatch():

Kotlin

val ops = ArrayList<ContentProviderOperation>()
val programsCount = channelInfo.mPrograms.size
channelInfo.mPrograms.forEachIndexed { index, program ->
    ops += ContentProviderOperation.newInsert(
            TvContract.Programs.CONTENT_URI).run {
        withValues(programs[index])
        withValue(TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS, programStartSec * 1000)
        withValue(
                TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS,
                (programStartSec + program.durationSec) * 1000
        )
        build()
    }
    programStartSec += program.durationSec
    if (index % 100 == 99 || index == programsCount - 1) {
        try {
            contentResolver.applyBatch(TvContract.AUTHORITY, ops)
        } catch (e: RemoteException) {
            Log.e(TAG, "Failed to insert programs.", e)
            return
        } catch (e: OperationApplicationException) {
            Log.e(TAG, "Failed to insert programs.", e)
            return
        }
        ops.clear()
    }
}

Java

ArrayList<ContentProviderOperation> ops = new ArrayList<>();
int programsCount = channelInfo.mPrograms.size();
for (int j = 0; j < programsCount; ++j) {
    ProgramInfo program = channelInfo.mPrograms.get(j);
    ops.add(ContentProviderOperation.newInsert(
            TvContract.Programs.CONTENT_URI)
            .withValues(programs.get(j))
            .withValue(Programs.COLUMN_START_TIME_UTC_MILLIS,
                    programStartSec * 1000)
            .withValue(Programs.COLUMN_END_TIME_UTC_MILLIS,
                    (programStartSec + program.durationSec) * 1000)
            .build());
    programStartSec = programStartSec + program.durationSec;
    if (j % 100 == 99 || j == programsCount - 1) {
        try {
            getContentResolver().applyBatch(TvContract.AUTHORITY, ops);
        } catch (RemoteException | OperationApplicationException e) {
            Log.e(TAG, "Failed to insert programs.", e);
            return;
        }
        ops.clear();
    }
}

Traiter les données des canaux de manière asynchrone

La manipulation des données, telle que l’extraction d’un flux du serveur ou l’accès à la base de données, doit et non à bloquer le thread UI. L'utilisation d'un AsyncTask permet d'effectuer des mises à jour de manière asynchrone. Par exemple, lorsque vous chargez des informations de canal à partir d'un serveur backend, vous pouvez utiliser AsyncTask comme suit:

Kotlin

private class LoadTvInputTask(val context: Context) : AsyncTask<Uri, Unit, Unit>() {

    override fun doInBackground(vararg uris: Uri) {
        try {
            fetchUri(uris[0])
        } catch (e: IOException) {
            Log.d("LoadTvInputTask", "fetchUri error")
        }
    }

    @Throws(IOException::class)
    private fun fetchUri(videoUri: Uri) {
        context.contentResolver.openInputStream(videoUri).use { inputStream ->
            Xml.newPullParser().also { parser ->
                try {
                    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false)
                    parser.setInput(inputStream, null)
                    sTvInput = ChannelXMLParser.parseTvInput(parser)
                    sSampleChannels = ChannelXMLParser.parseChannelXML(parser)
                } catch (e: XmlPullParserException) {
                    e.printStackTrace()
                }
            }
        }
    }
}

Java

private static class LoadTvInputTask extends AsyncTask<Uri, Void, Void> {

    private Context mContext;

    public LoadTvInputTask(Context context) {
        mContext = context;
    }

    @Override
    protected Void doInBackground(Uri... uris) {
        try {
            fetchUri(uris[0]);
        } catch (IOException e) {
          Log.d("LoadTvInputTask", "fetchUri error");
        }
        return null;
    }

    private void fetchUri(Uri videoUri) throws IOException {
        InputStream inputStream = null;
        try {
            inputStream = mContext.getContentResolver().openInputStream(videoUri);
            XmlPullParser parser = Xml.newPullParser();
            try {
                parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
                parser.setInput(inputStream, null);
                sTvInput = ChannelXMLParser.parseTvInput(parser);
                sSampleChannels = ChannelXMLParser.parseChannelXML(parser);
            } catch (XmlPullParserException e) {
                e.printStackTrace();
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }
}

Si vous devez mettre à jour les données EPG régulièrement, envisagez d'utiliser WorkManager pour exécuter le processus de mise à jour en cas d'inactivité, par exemple tous les jours à 3h du matin.

D'autres techniques permettant de séparer les tâches de mise à jour de données du thread UI incluent l'utilisation de la méthode HandlerThread, ou vous pouvez implémenter la vôtre à l'aide de Looper et Handler. Voir <ph type="x-smartling-placeholder"></ph> Processus et threads.

Les chaînes peuvent utiliser des liens vers l'application pour permettre aux utilisateurs de lancer facilement une vidéo associée pendant qu'ils regardent le contenu de la chaîne. Version de la chaîne utilisée par les applis des liens vers l'application pour accroître l'engagement utilisateur en lançant des activités qui montrent les informations associées ou tout autre contenu. Par exemple, vous pouvez utiliser des liens d'application pour effectuer les opérations suivantes:

  • Guidez l'utilisateur pour qu'il découvre et achète du contenu associé.
  • Fournissez des informations supplémentaires sur le contenu en cours de lecture.
  • Lorsque vous regardez des épisodes, commencez à regarder l'épisode suivant dans de la série.
  • Permettre à l'utilisateur d'interagir avec le contenu (par exemple, donner une note ou un avis) sans interrompre la lecture.

Les liens vers l'application s'affichent lorsque l'utilisateur appuie sur Sélectionner pour afficher Menu TV lorsque vous regardez le contenu de la chaîne.

Figure 1 : Exemple de lien d'application sur la ligne Chaînes lorsque le contenu de la chaîne est affiché.

Lorsque l'utilisateur sélectionne le lien vers l'application, le système lance une activité en utilisant un URI d'intent spécifié par l'application de canal. La lecture du contenu de la chaîne continue lorsque l'activité des liens vers une application est active. L'utilisateur peut revenir à la chaîne. le contenu en appuyant sur Retour.

Fournir les données de canal de lien d'application

Android TV crée automatiquement un lien d'application pour chaque chaîne. à l'aide des informations des données de la chaîne. Pour fournir des informations sur les liens vers une application, spécifiez les informations suivantes dans votre Champs TvContract.Channels:

  • COLUMN_APP_LINK_COLOR : le couleur d'accentuation du lien vers l'application pour cette chaîne. Pour un exemple de couleur d’accentuation, voir figure 2, légende 3.
  • COLUMN_APP_LINK_ICON_URI – URI de l'icône du badge d'application du lien d'application pour cette chaîne. Pour une exemple de l'icône de badge d'application (voir figure 2, légende 2).
  • COLUMN_APP_LINK_INTENT_URI – URI d'intent du lien vers l'application pour cette chaîne. Vous pouvez créer l'URI en utilisant toUri(int) avec URI_INTENT_SCHEME et reconvertissez l'URI dans l'intent d'origine avec parseUri()
  • COLUMN_APP_LINK_POSTER_ART_URI - URI de l'affiche utilisée comme arrière-plan du lien vers l'application pour cette chaîne. Pour obtenir un exemple d'image poster, consultez la figure 2, légende 1.
  • COLUMN_APP_LINK_TEXT – Texte descriptif du lien vers l'application pour cette chaîne. Exemple : description du lien vers l'application (voir le texte de la figure 2, légende 3).

Figure 2. Détails du lien vers l'application.

Si les données de la chaîne n'indiquent pas d'informations sur les liens vers une application, le système crée un lien d'application par défaut. Le système choisit les détails par défaut comme suit:

  • Pour l'URI de l'intent (COLUMN_APP_LINK_INTENT_URI), le système utilise ACTION_MAIN activité pour la catégorie CATEGORY_LEANBACK_LAUNCHER, généralement définie dans le fichier manifeste de l'application. Si cette activité n'est pas définie, un lien d'application non fonctionnel s'affiche. l'utilisateur clique dessus, rien ne se passe.
  • Pour le texte descriptif (COLUMN_APP_LINK_TEXT) : le système utilise "Ouvrir app-name". Si aucun URI d'intent de lien d'application viable n'est défini, le système utilise "Aucun lien disponible".
  • Pour la couleur d'accentuation (COLUMN_APP_LINK_COLOR), le système utilise la couleur par défaut de l'application.
  • Pour l'image poster (COLUMN_APP_LINK_POSTER_ART_URI), le système utilise la bannière de l'écran d'accueil de l'application. Si l'application ne fournit pas le système utilise une image par défaut de l'application TV.
  • Pour l'icône du badge (COLUMN_APP_LINK_ICON_URI), le utilise un badge indiquant le nom de l'application. Si le système utilise également de la bannière de l'application ou de l'image poster par défaut, aucun badge d'application n'est affiché.

Vous pouvez spécifier les détails des liens d'application pour vos chaînes dans la section activité de configuration. Vous pouvez modifier ces informations à tout moment. Si un lien d'application doit correspondre aux modifications apportées à la version, mettez à jour l'application détails du lien et appel ContentResolver.update() si nécessaire. Pour en savoir plus sur la mise à jour données de canal, consultez Mettre à jour les données de la chaîne.