Utilizza i dati del canale

L'ingresso TV deve fornire dati EPG (Electronic Program Guide) per almeno un canale nella sua attività di configurazione. Devi inoltre aggiornare periodicamente di dati, tenendo conto delle dimensioni dell'aggiornamento e del thread di elaborazione che li gestisce. Inoltre, puoi fornire link dell'app per i canali che indirizzano l'utente verso contenuti e attività correlati. Questa lezione illustra la creazione e l'aggiornamento dei dati del canale e del programma sulla di sistema tenendo a mente queste considerazioni.

Prova App di esempio del servizio di input TV.

Autorizza

Affinché l'ingresso TV funzioni con i dati EPG, deve dichiarare il valore l'autorizzazione di scrittura nel relativo file manifest Android, in questo modo:

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

Registra canali nel database

Il database del sistema Android TV conserva i record dei dati dei canali per gli ingressi della TV. Nella configurazione attività, per ciascuno dei tuoi canali, devi mappare i dati dei canali ai seguenti campi del TvContract.Channels corso:

Sebbene il framework di input della TV sia abbastanza generico da gestire sia i sistemi di trasmissione tradizionali contenuti over-the-top (OTT) senza alcuna distinzione, ti consigliamo di definire le seguenti colonne in oltre a quelli elencati sopra per identificare meglio i canali televisivi tradizionali:

Se vuoi fornire i dettagli dei link dell'app per i tuoi canali, devi: aggiorna alcuni campi aggiuntivi. Per ulteriori informazioni sui campi dei link dell'app, consulta Aggiungi informazioni sul link dell'app.

Per gli ingressi TV basati su streaming internet, assegna i tuoi valori a quanto sopra in modo che ciascun canale può essere identificato in modo univoco.

Estrai i metadati del canale (in XML, JSON o altro) dal tuo server di backend e nella tua configurazione l'attività mappa i valori al database di sistema come segue:

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

Nell'esempio precedente, channel è un oggetto che contiene i metadati del canale di backend.

Presentare informazioni sul canale e sul programma

L'app TV di sistema mostra informazioni su canali e programmi agli utenti mentre esplorano i canali. come mostrato nella Figura 1. Per assicurarti che le informazioni sul canale e sul programma siano compatibili con il set di dati dell'app di sistema per la TV presentatore delle informazioni sul canale e sul programma segui le linee guida riportate di seguito.

  1. Numero del canale (COLUMN_DISPLAY_NUMBER)
  2. Icona (android:icon nel manifest dell'input TV)
  3. Descrizione del programma (COLUMN_SHORT_DESCRIPTION)
  4. Titolo del programma (COLUMN_TITLE)
  5. Logo del canale (TvContract.Channels.Logo)
    • Utilizza il colore #EEEEEE per abbinarlo al testo circostante
    • Non includere spaziatura interna
  6. Locandina (COLUMN_POSTER_ART_URI)
    • Proporzioni tra 16:9 e 4:3

Figura 1. Il canale dell'app TV di sistema e il presentatore delle informazioni sul programma.

L'app TV di sistema fornisce le stesse informazioni nella guida ai programmi, comprese locandina, come mostrato nella Figura 2.

Figura 2. La guida ai programmi dell'app TV di sistema.

Aggiornare i dati del canale

Quando aggiorni i dati dei canali esistenti, utilizza update() anziché eliminare e aggiungere nuovamente i dati. Puoi identificare la versione attuale dei dati utilizzando Channels.COLUMN_VERSION_NUMBER e Programs.COLUMN_VERSION_NUMBER quando si scelgono i record da aggiornare.

Nota: aggiungi i dati del canale a ContentProvider può richiedere tempo. Aggiungere i programmi attuali (entro due ore dall'ora corrente) solo quando configuri EpgSyncJobService per aggiornare il resto dei dati del canale in background. Consulta Esempio dell'app Android TV Live TV.

Caricamento in batch dei dati dei canali

Quando aggiorni il database di sistema con una grande quantità di dati di canali, utilizza ContentResolver applyBatch() o bulkInsert() . Ecco un esempio in cui viene utilizzato 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();
    }
}

Elabora i dati dei canali in modo asincrono

La manipolazione dei dati, come il recupero di un flusso dal server o l'accesso al database, non bloccano il thread dell'interfaccia utente. Utilizzare AsyncTask è uno eseguire aggiornamenti in modo asincrono. Ad esempio, quando carichi informazioni sul canale da un server di backend, puoi usare AsyncTask nel seguente modo:

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

Se hai bisogno di aggiornare regolarmente i dati EPG, WorkManager eseguire il processo di aggiornamento durante il tempo di inattività, ad esempio ogni giorno alle 3:00

Altre tecniche per separare le attività di aggiornamento dei dati dal thread dell'interfaccia utente includono l'utilizzo HandlerThread o puoi implementarne una personalizzata utilizzando Looper e Handler corsi. Vedi Processi e thread per ulteriori informazioni.

I canali possono utilizzare i link alle app per consentire agli utenti di avviare facilmente un all'attività durante la visione dei contenuti del canale. Utilizzo da parte delle app del canale link alle app per aumentare il coinvolgimento degli utenti avviando attività che mostrano informazioni correlate o contenuti aggiuntivi. Ad esempio, puoi usare i link dell'app effettuare le seguenti operazioni:

  • Guida l'utente a scoprire e acquistare contenuti correlati.
  • Fornisci ulteriori informazioni sui contenuti attualmente in riproduzione.
  • Mentre guardi i contenuti a episodi, inizia a guardare la puntata successiva in un Google Cloud.
  • Consentire all'utente di interagire con i contenuti, ad esempio valutando o recensisci senza interrompere la riproduzione.

I link dell'app vengono mostrati quando l'utente preme Seleziona per visualizzare Menu della TV mentre guardi i contenuti del canale.

Figura 1. Esempio di link all'app visualizzato nella riga Canali mentre vengono mostrati i contenuti del canale.

Quando l'utente seleziona il link all'app, il sistema avvia un'attività utilizzando un URI di intent specificato dall'app del canale. La riproduzione dei contenuti del canale continua mentre l'attività di link dell'app è attiva. L'utente può tornare al canale contenuti premendo Indietro.

Fornisci i dati dei canali per il collegamento dell'app

Android TV crea automaticamente un link all'app per ogni canale utilizzando le informazioni provenienti dai dati del canale. Per fornire informazioni sui link dell'app, specificare i seguenti dettagli TvContract.Channels campi:

  • COLUMN_APP_LINK_COLOR - Il colore intenso del link dell'app di questo canale. Per un esempio di colore intenso, vedi la figura 2, callout 3.
  • COLUMN_APP_LINK_ICON_URI - L'URI dell'icona del badge dell'app del link dell'app di questo canale. Per un esempio di icona del badge dell'app; vedi figura 2, callout 2.
  • COLUMN_APP_LINK_INTENT_URI - L'URI intent del link dell'app per questo canale. Puoi creare l'URI utilizza toUri(int) con URI_INTENT_SCHEME e converti l'URI all'intent originale con parseUri().
  • COLUMN_APP_LINK_POSTER_ART_URI - L'URI della locandina utilizzata come sfondo del link dell'app per questo canale. Per un esempio di immagine poster, vedi figura 2, callout 1.
  • COLUMN_APP_LINK_TEXT - Il testo descrittivo del link dell'app per questo canale. Ad esempio, descrizione del link dell'app, vedi il testo nella figura 2, callout 3.

Figura 2. Dettagli link dell'app.

Se i dati del canale non specificano informazioni sui link dell'app, il sistema crea un link all'app predefinito. Il sistema sceglie i dettagli predefiniti nel seguente modo:

  • Per l'URI intent (COLUMN_APP_LINK_INTENT_URI), il sistema utilizza ACTION_MAIN attività per la categoria CATEGORY_LEANBACK_LAUNCHER, solitamente definita nel file manifest dell'app. Se questa attività non è definita, viene visualizzato un link di app non funzionante, se l'utente fa clic su di esso, non accade nulla.
  • Per il testo descrittivo (COLUMN_APP_LINK_TEXT), il sistema utilizza "Apri app-name". Se non è stato definito alcun URI di intent del link dell'app utilizzabile, il sistema utilizza "Nessun link disponibile".
  • Per il colore di contrasto (COLUMN_APP_LINK_COLOR), il sistema utilizza il colore predefinito dell'app.
  • Per l'immagine poster (COLUMN_APP_LINK_POSTER_ART_URI), Il sistema utilizza il banner della schermata Home dell'app. Se l'app non fornisce un banner, il sistema utilizza un'immagine predefinita dell'app TV.
  • Per l'icona del badge (COLUMN_APP_LINK_ICON_URI), usa un badge che mostra il nome dell'app. Se il sistema utilizza anche banner dell'app o immagine dell'app predefinita per l'immagine poster, non viene mostrato alcun badge dell'app.

Devi specificare i dettagli dei link dell'app per i tuoi canali nella sezione attività di configurazione. Puoi aggiornare questi dettagli dei link all'app in qualsiasi momento, quindi Se il link di un'app deve corrispondere alle modifiche al canale, aggiorna l'app dettagli del collegamento e chiamata ContentResolver.update() secondo necessità. Per ulteriori dettagli sull'aggiornamento Consulta i dati dei canali Aggiornare i dati dei canali.