L'input TV deve fornire i dati della guida ai programmi elettronica (EPG) per almeno un canale nella sua attività di configurazione. Dovresti anche aggiornare periodicamente questi dati, tenendo conto delle dimensioni dell'aggiornamento e del thread di elaborazione che lo gestisce. Inoltre, puoi fornire link alle app per i canali che guidano l'utente a contenuti e attività correlate. Questa lezione illustra la creazione e l'aggiornamento dei dati di canali e programmi nel database di sistema tenendo conto di queste considerazioni.
Prova l' app di esempio del servizio di input TV.
Ottieni autorizzazione
Affinché l'input TV funzioni con i dati EPG, deve dichiarare l' autorizzazione di scrittura nel file manifest di Android come segue:
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
Registra i canali nel database
Il database di sistema di Android TV conserva i record dei dati dei canali per gli input TV. Nell'attività di configurazione, per ciascuno dei tuoi canali, devi mappare i dati del canale ai seguenti campi della classe TvContract.Channels:
COLUMN_DISPLAY_NAME- il nome visualizzato del canaleCOLUMN_DISPLAY_NUMBER- il numero del canale visualizzatoCOLUMN_INPUT_ID- l'ID del servizio di input TVCOLUMN_SERVICE_TYPE- il tipo di servizio del canaleCOLUMN_TYPE- il tipo di standard di trasmissione del canaleCOLUMN_VIDEO_FORMAT- il formato video predefinito per il canale
Sebbene il framework di input TV sia sufficientemente generico da gestire sia i contenuti di trasmissione tradizionali sia i contenuti over-the-top (OTT) senza distinzioni, potresti voler definire le seguenti colonne in aggiunta per identificare meglio i canali di trasmissione tradizionali:
COLUMN_ORIGINAL_NETWORK_ID- l'ID della rete televisivaCOLUMN_SERVICE_ID- l'ID del servizioCOLUMN_TRANSPORT_STREAM_ID- l'ID dello stream di trasporto
Se vuoi fornire i dettagli dei link alle app per i tuoi canali, devi aggiornare alcuni campi aggiuntivi. Per ulteriori informazioni sui campi dei link alle app, vedi Aggiungi informazioni sui link alle app.
Per gli input TV basati sullo streaming internet, assegna i tuoi valori di conseguenza in modo che ogni canale possa essere identificato in modo univoco.
Estrai i metadati del canale (in XML, JSON o altro) dal server di backend e, nell'attività di configurazione, 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);
In questo esempio, channel è un oggetto che contiene i metadati del canale dal server di backend.
Presenta le informazioni su canali e programmi
L'app TV di sistema presenta agli utenti le informazioni su canali e programmi mentre scorrono i canali, come mostrato nella Figura 1. Per assicurarti che le informazioni su canali e programmi funzionino con il presentatore di informazioni su canali e programmi dell'app TV di sistema, segui queste linee guida:
- Numero del canale (
COLUMN_DISPLAY_NUMBER) - Icona
(
android:iconnel manifest dell'input TV) - Descrizione del programma (
COLUMN_SHORT_DESCRIPTION) - Titolo del programma (
COLUMN_TITLE) - Logo del canale (
TvContract.Channels.Logo)- Utilizza il colore #EEEEEE per abbinarlo al testo circostante
- Non includere il padding
- Locandina (
COLUMN_POSTER_ART_URI) - Proporzioni tra 16:9 e 4:3
L'app TV di sistema fornisce le stesse informazioni tramite la guida ai programmi, inclusa la locandina, come mostrato nella Figura 2.
Aggiorna i dati del canale
Quando aggiorni i dati del canale esistenti, utilizza il metodo update anziché eliminare e aggiungere di nuovo i dati. Puoi identificare la versione corrente dei dati utilizzando Channels.COLUMN_VERSION_NUMBER e Programs.COLUMN_VERSION_NUMBER quando scegli i record da aggiornare.
Nota: l'aggiunta di dati dei canali al ContentProvider può richiedere tempo. Aggiungi i programmi attuali (quelli entro due ore dall'ora corrente) solo quando configuri EpgSyncJobService per aggiornare il resto dei dati del canale in background. Per un esempio, consulta l'
app di esempio di TV in diretta di Android TV.
Carica in batch i dati dei canali
Quando aggiorni il database di sistema con una grande quantità di dati dei canali, utilizza il metodo ContentResolver
applyBatch o bulkInsert. Ecco un esempio che utilizza 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, ad esempio il recupero di uno stream dal server o l'accesso al database, non deve bloccare il thread dell'interfaccia utente. L'utilizzo di AsyncTask è un modo per eseguire gli aggiornamenti in modo asincrono. Ad esempio, quando carichi le informazioni sul canale da un server di backend, puoi utilizzare AsyncTask come segue:
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 devi aggiornare regolarmente i dati EPG, valuta la possibilità di utilizzare
WorkManager
per eseguire il processo di aggiornamento durante il tempo di inattività, ad esempio ogni giorno alle 03:00.
Altre tecniche per separare le attività di aggiornamento dei dati dal thread dell'interfaccia utente includono l'utilizzo della
HandlerThread classe, oppure puoi implementare la tua utilizzando Looper
e Handler classi. Per ulteriori informazioni, consulta la sezione
Processi e thread.
Aggiungi informazioni sui link alle app
I canali possono utilizzare i link alle app per consentire agli utenti di avviare un'attività correlata mentre guardano i contenuti del canale. Le app dei canali utilizzano i link alle app per estendere il coinvolgimento degli utenti avviando attività che mostrano informazioni correlate o contenuti aggiuntivi. Ad esempio, puoi utilizzare i link alle app per:
- Guidare l'utente alla scoperta e all'acquisto di contenuti correlati.
- Fornire informazioni aggiuntive sui contenuti in riproduzione.
- Durante la visualizzazione di contenuti episodici, avvia la visualizzazione dell'episodio successivo di una serie.
- Consentire all'utente di interagire con i contenuti, ad esempio valutandoli o recensendoli, senza interrompere la riproduzione dei contenuti.
I link alle app vengono visualizzati quando l'utente preme Seleziona per mostrare il menu TV mentre guarda i contenuti del canale.
Figura 1. Un 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 intent specificato dall'app del canale. I contenuti del canale continuano a essere riprodotti mentre l'attività del link all'app è attiva. L'utente può tornare ai contenuti del canale premendo Indietro.
Fornisci i dati dei canali dei link alle app
Android TV crea automaticamente un link all'app per ogni canale, utilizzando le informazioni dei dati del canale. Per fornire informazioni sui link alle app, specifica i seguenti dettagli nei campi TvContract.Channels:
COLUMN_APP_LINK_COLOR- Il colore intenso del link all'app per 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 all'app per questo canale. Per un esempio di icona del badge dell'app, vedi la Figura 2, callout 2.COLUMN_APP_LINK_INTENT_URI- L'URI intent del link all'app per questo canale. Puoi creare l'URI utilizzandotoUri(int)conURI_INTENT_SCHEMEe convertire l'URI di nuovo nell'intent originale conparseUri.COLUMN_APP_LINK_POSTER_ART_URI- L'URI della locandina utilizzata come sfondo del link all'app per questo canale. Per un esempio di immagine poster, vedi la Figura 2, callout 1.COLUMN_APP_LINK_TEXT- Il testo descrittivo del link all'app per questo canale. Per un esempio di descrizione del link all'app, vedi il testo nella Figura 2, callout 3.
Se i dati del canale non specificano le informazioni sui link alle app, il sistema crea un link all'app predefinito. Il sistema sceglie i dettagli predefiniti come segue:
- Per l'URI intent (
COLUMN_APP_LINK_INTENT_URI), il sistema utilizza l'attivitàACTION_MAINper la categoriaCATEGORY_LEANBACK_LAUNCHER, in genere definita nel manifest dell'app. Se questa attività non è definita, viene visualizzato un link all'app non funzionante: se l'utente fa clic, non succede nulla. - Per il testo descrittivo
(
COLUMN_APP_LINK_TEXT), il sistema utilizza "Apri app-name". Se non è definito alcun URI intent di link all'app valido, il sistema utilizza "Nessun link disponibile". - Per il colore principale (
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), il sistema utilizza un badge che mostra il nome dell'app. Se il sistema utilizza anche il banner dell'app o l'immagine predefinita dell'app per l'immagine poster, non viene visualizzato alcun badge dell'app.
Specifica i dettagli dei link alle app per i tuoi canali nell'attività di configurazione dell'app. Puoi aggiornare questi dettagli dei link alle app in qualsiasi momento, quindi se un link all'app deve corrispondere alle modifiche del canale, aggiorna i dettagli del link all'app e chiama ContentResolver.update in base alle esigenze. Per ulteriori dettagli sull'aggiornamento dei dati dei canali, vedi Aggiorna i dati dei canali.