Un servizio di input TV rappresenta una sorgente di stream multimediali e ti consente di presentare i tuoi contenuti multimediali in modo lineare e televisivo come canali e programmi. Con un servizio di input TV, puoi fornire Controllo genitori, informazioni sulla guida ai programmi e classificazioni dei contenuti. Il servizio di input TV funziona con l'app Android TV, che controlla e presenta i contenuti dei canali sulla TV. L'app di sistema per la TV è sviluppata appositamente per il dispositivo ed è immutabile dalle app di terze parti. Per ulteriori informazioni sull'architettura TIF (TV Input Framework) e sui suoi componenti, consulta la pagina TV Input Framework.
Creare un servizio di input TV utilizzando la libreria companion TIF
La libreria Companion TIF è un framework che fornisce implementazioni estensibili delle funzionalità comuni dei servizi di input TV. È destinata esclusivamente agli OEM per creare canali da Android 5.0 (livello API 21) ad Android 7.1 (livello API 25).
Aggiorna il progetto
La libreria companion TIF è disponibile per l'utilizzo in versione legacy da parte degli OEM nel repository androidtv-sample-inputs. Consulta il repository per un esempio di come includere la libreria in un'app.
Dichiara il servizio di input TV nel file manifest
La tua app deve fornire un servizio compatibile con TvInputService
che il sistema utilizza per accedere all'app. La libreria companion TIF fornisce la classe BaseTvInputService
, che offre un'implementazione predefinita di TvInputService
che puoi personalizzare. Crea una sottoclasse di BaseTvInputService
e dichiarala nel tuo manifest come servizio.
Nella dichiarazione del file manifest, specifica l'autorizzazione BIND_TV_INPUT
per consentire al servizio di connettere l'ingresso TV al sistema. Un servizio di sistema esegue l'associazione e ha l'autorizzazione BIND_TV_INPUT
.
L'app TV di sistema invia richieste ai servizi di input TV
tramite l'interfaccia TvInputManager
.
Nella dichiarazione del servizio, includi un filtro per intent che specifichi TvInputService
come azione da eseguire con l'intent. Inoltre, dichiara i metadati del servizio come risorsa XML separata. La dichiarazione del servizio, il filtro di intent e la dichiarazione dei metadati di servizio sono mostrati nell'esempio seguente:
<service android:name=".rich.RichTvInputService" android:label="@string/rich_input_label" android:permission="android.permission.BIND_TV_INPUT"> <!-- Required filter used by the system to launch our account service. --> <intent-filter> <action android:name="android.media.tv.TvInputService" /> </intent-filter> <!-- An XML file which describes this input. This provides pointers to the RichTvInputSetupActivity to the system/TV app. --> <meta-data android:name="android.media.tv.input" android:resource="@xml/richtvinputservice" /> </service>
Definisci i metadati del servizio in un file XML separato. Il file XML dei metadati del servizio deve includere un'interfaccia di configurazione che descriva la configurazione iniziale e la scansione dei canali dell'ingresso TV. Il file di metadati deve anche contenere un flag che indica se gli utenti possono o meno registrare contenuti. Per ulteriori informazioni su come supportare la registrazione di contenuti nella tua app, consulta Supportare la registrazione di contenuti.
Il file di metadati del servizio si trova nella directory delle risorse XML dell'app e deve corrispondere al nome della risorsa dichiarata nel file manifest. Utilizzando le voci manifest dell'esempio precedente, creerai il file XML in res/xml/richtvinputservice.xml
, con il seguente contenuto:
<?xml version="1.0" encoding="utf-8"?> <tv-input xmlns:android="http://schemas.android.com/apk/res/android" android:canRecord="true" android:setupActivity="com.example.android.sampletvinput.rich.RichTvInputSetupActivity" />
Definisci i canali e crea la tua attività di configurazione
Il servizio di input TV deve definire almeno un canale a cui gli utenti accedono tramite l'app di sistema per TV. Dovresti registrare i canali nel database di sistema e fornire un'attività di configurazione che il sistema richiama quando non riesce a trovare un canale per la tua app.
Prima di tutto, consenti alla tua app di leggere e scrivere nella Guida elettronica di programmazione (EPG), i cui dati includono canali e programmi disponibili per l'utente. Per consentire alla tua app di eseguire queste azioni ed eseguire la sincronizzazione con l'EPG dopo il riavvio del dispositivo, aggiungi i seguenti elementi al file manifest dell'app:
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED "/>
Aggiungi il seguente elemento per assicurarti che la tua app venga visualizzata nel Google Play Store come app che fornisce canali di contenuti su Android TV:
<uses-feature android:name="android.software.live_tv" android:required="true" />
A questo punto, crea una classe che estenda la classe EpgSyncJobService
. Questa classe astratta semplifica la creazione di un servizio job che crea e aggiorna canali nel database di sistema.
Nella sottoclasse, crea e restituisci l'elenco completo dei tuoi canali in
getChannels()
. Se i tuoi canali provengono da un file XMLTV,
utilizza il corso XmlTvParser
. In caso contrario, genera i canali in modo programmatico utilizzando la classe Channel.Builder
.
Per ogni canale, il sistema chiama getProgramsForChannel()
quando ha bisogno di un elenco di programmi che possono essere visualizzati in un determinato periodo di tempo
sul canale. Restituisci un elenco di oggetti Program
per il canale. Utilizza la classe XmlTvParser
per ottenere i programmi da un file XMLTV oppure generali in modo programmatico utilizzando la classe Program.Builder
.
Per ogni oggetto Program
, utilizza un
oggetto InternalProviderData
per impostare informazioni del programma come
il tipo di video del programma. Se hai solo un numero limitato di programmi che vuoi che il canale si ripeta in loop, utilizza il metodo InternalProviderData.setRepeatable()
con valore true
quando imposti le informazioni sul programma.
Dopo aver implementato il servizio job, aggiungilo al manifest dell'app:
<service android:name=".sync.SampleJobService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true" />
Infine, crea un'attività di configurazione. L'attività di configurazione dovrebbe fornire un modo per sincronizzare i dati del canale e del programma. Un modo è che l'utente lo faccia tramite l'interfaccia utente nell'attività. Potresti anche impostare l'app in modo automatico quando inizia l'attività. Quando l'attività di configurazione deve sincronizzare le informazioni sul canale e sul programma, l'app deve avviare il servizio:
Kotlin
val inputId = getActivity().intent.getStringExtra(TvInputInfo.EXTRA_INPUT_ID) EpgSyncJobService.cancelAllSyncRequests(getActivity()) EpgSyncJobService.requestImmediateSync( getActivity(), inputId, ComponentName(getActivity(), SampleJobService::class.java) )
Java
String inputId = getActivity().getIntent().getStringExtra(TvInputInfo.EXTRA_INPUT_ID); EpgSyncJobService.cancelAllSyncRequests(getActivity()); EpgSyncJobService.requestImmediateSync(getActivity(), inputId, new ComponentName(getActivity(), SampleJobService.class));
Utilizza il metodo requestImmediateSync()
per sincronizzare
il servizio di job. L'utente deve attendere il completamento della sincronizzazione, quindi il periodo della richiesta deve essere relativamente breve.
Utilizza il metodo setUpPeriodicSync()
per fare in modo che il servizio job sincronizzi periodicamente il canale e programmi i dati in background:
Kotlin
EpgSyncJobService.setUpPeriodicSync( context, inputId, ComponentName(context, SampleJobService::class.java) )
Java
EpgSyncJobService.setUpPeriodicSync(context, inputId, new ComponentName(context, SampleJobService.class));
La libreria companion TIF fornisce un ulteriore metodo di sovraccarico requestImmediateSync()
che ti consente di specificare la durata dei dati del canale da sincronizzare in millisecondi. Il metodo predefinito sincronizza
i dati del canale relativi al valore di un'ora.
La libreria companion TIF fornisce anche un ulteriore metodo di sovraccarico setUpPeriodicSync()
che consente di specificare la durata dei dati dei canali da sincronizzare e la frequenza della sincronizzazione periodica. Il metodo predefinito sincronizza 48 ore di dati del canale ogni 12 ore.
Per maggiori dettagli sui dati dei canali e sull'EPG, consulta Utilizzare i dati dei canali.
Gestire le richieste di ottimizzazione e la riproduzione di contenuti multimediali
Quando un utente seleziona un canale specifico, l'app TV di sistema utilizza un
Session
, creato dalla tua app, per sintonizzarsi sul canale richiesto
e riprodurre i contenuti. La libreria companion TIF offre diverse classi che puoi estendere per gestire le chiamate a canali e sessioni dal sistema.
La sottoclasse BaseTvInputService
crea sessioni che gestiscono le richieste di ottimizzazione. Esegui l'override del metodo onCreateSession()
, crea una sessione estesa dalla classe BaseTvInputService.Session
e chiama super.sessionCreated()
con la nuova sessione. Nel seguente esempio, onCreateSession()
restituisce un oggetto RichTvInputSessionImpl
che estende BaseTvInputService.Session
:
Kotlin
override fun onCreateSession(inputId: String): Session = RichTvInputSessionImpl(this, inputId).apply { setOverlayViewEnabled(true) }
Java
@Override public final Session onCreateSession(String inputId) { RichTvInputSessionImpl session = new RichTvInputSessionImpl(this, inputId); session.setOverlayViewEnabled(true); return session; }
Quando l'utente utilizza l'app TV di sistema per iniziare a visualizzare uno dei tuoi canali,
il sistema chiama il metodo onPlayChannel()
della sessione. Esegui l'override di questo metodo se devi eseguire un'inizializzazione speciale di canale prima che il programma inizi a essere riprodotto.
Il sistema recupera quindi il programma attualmente pianificato e chiama il metodo onPlayProgram()
della sessione, specificando le informazioni sul programma e l'ora di inizio in millisecondi. Utilizza l'interfaccia di TvPlayer
per iniziare a riprodurre il programma.
Il codice del media player deve implementare TvPlayer
per gestire eventi di riproduzione specifici. La classe TvPlayer
gestisce funzionalità come i controlli del time-shifting senza aggiungere complessità alla tua implementazione di BaseTvInputService
.
Nel metodo getTvPlayer()
della sessione, restituisci
il media player che implementa TvPlayer
. L'app di esempio
TV Input Service implementa un media player che utilizza ExoPlayer.
Creare un servizio di input TV utilizzando il framework di input TV
Se il tuo servizio di input TV non può utilizzare la libreria companion TIF, devi implementare i seguenti componenti:
TvInputService
fornisce disponibilità a lunga esecuzione e in background per l'input TVTvInputService.Session
mantiene lo stato dell'ingresso TV e comunica con l'app di hostingTvContract
descrive i canali e i programmi disponibili per l'ingresso TVTvContract.Channels
rappresenta le informazioni su un canale TVTvContract.Programs
descrive un programma TV con dati quali titolo e ora di inizio del programmaTvTrackInfo
rappresenta una traccia audio, video o di sottotitoliTvContentRating
descrive una classificazione dei contenuti e consente schemi di classificazione dei contenuti personalizzatiTvInputManager
fornisce un'API all'app di sistema per TV e gestisce l'interazione con app e ingressi TV
Devi inoltre procedere nel seguente modo:
- Dichiara il tuo servizio di input TV nel file manifest, come descritto nella sezione Dichiarare il servizio di input TV nel file manifest.
- Crea il file dei metadati del servizio.
- Crea e registra le informazioni sul tuo canale e sul programma.
- Crea l'attività di configurazione.
Definisci il servizio di input TV
Per il tuo servizio, estendi il corso TvInputService
. Un'implementazione TvInputService
è un servizio associato in cui il servizio di sistema è il client associato. I metodi del ciclo di vita dei servizi da implementare sono illustrati nella Figura 1.
Il metodo onCreate()
inizializza e avvia HandlerThread
, che fornisce un thread di processo separato dal thread dell'interfaccia utente per gestire le azioni basate sul sistema. Nell'esempio seguente, il metodo onCreate()
inizializza CaptioningManager
e si prepara a gestire le azioni ACTION_BLOCKED_RATINGS_CHANGED
e ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED
. Queste azioni descrivono gli intent di sistema attivati quando l'utente modifica le impostazioni del Controllo genitori e quando viene apportata una modifica all'elenco delle classificazioni bloccate.
Kotlin
override fun onCreate() { super.onCreate() handlerThread = HandlerThread(javaClass.simpleName).apply { start() } dbHandler = Handler(handlerThread.looper) handler = Handler() captioningManager = getSystemService(Context.CAPTIONING_SERVICE) as CaptioningManager setTheme(android.R.style.Theme_Holo_Light_NoActionBar) sessions = mutableListOf<BaseTvInputSessionImpl>() val intentFilter = IntentFilter().apply { addAction(TvInputManager.ACTION_BLOCKED_RATINGS_CHANGED) addAction(TvInputManager.ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED) } registerReceiver(broadcastReceiver, intentFilter) }
Java
@Override public void onCreate() { super.onCreate(); handlerThread = new HandlerThread(getClass() .getSimpleName()); handlerThread.start(); dbHandler = new Handler(handlerThread.getLooper()); handler = new Handler(); captioningManager = (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE); setTheme(android.R.style.Theme_Holo_Light_NoActionBar); sessions = new ArrayList<BaseTvInputSessionImpl>(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(TvInputManager .ACTION_BLOCKED_RATINGS_CHANGED); intentFilter.addAction(TvInputManager .ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED); registerReceiver(broadcastReceiver, intentFilter); }

Figura 1.Ciclo di vita di TVInputService.
Consulta la sezione
Controllare i contenuti per ulteriori informazioni su come gestire i contenuti bloccati e usufruire del controllo genitori. Visita la pagina TvInputManager
per scoprire altre azioni basate sul sistema
che potresti voler gestire nel servizio di input TV.
L'elemento TvInputService
crea una TvInputService.Session
che implementa Handler.Callback
per gestire le modifiche dello stato del player. Con
onSetSurface()
,
TvInputService.Session
imposta Surface
con i
contenuti video. Consulta la sezione Integrare il player con la piattaforma per ulteriori informazioni sull'utilizzo di Surface
per il rendering del video.
L'TvInputService.Session
gestisce l'evento onTune()
quando l'utente seleziona un canale e invia una notifica all'app di sistema per la TV in caso di modifiche ai contenuti e ai metadati dei contenuti. Questi metodi notify()
sono descritti in
Controllare contenuti e Gestire la selezione delle tracce
più avanti in questo corso di formazione.
Definisci l'attività di configurazione
L'app TV di sistema funziona con l'attività di configurazione definita per l'ingresso TV. L'attività di configurazione è obbligatoria e deve fornire almeno un record di canale per il database di sistema. L'app TV di sistema richiama l'attività di configurazione quando non riesce a trovare un canale per l'ingresso TV.
L'attività di configurazione descrive all'app TV di sistema i canali resi disponibili tramite l'ingresso TV, come mostrato nella lezione successiva, Creare e aggiornare i dati dei canali.