Un servizio di input TV rappresenta un'origine di stream multimediali e ti consente di presentare i contenuti multimediali in modo lineare, come la TV broadcast, sotto forma di 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 TV di sistema Android. Questa app controlla e presenta i contenuti dei canali sulla TV. L'app TV di sistema è sviluppata appositamente per il dispositivo e non può essere modificata da app di terze parti. Per saperne di più sull'architettura del framework di input TV (TIF) e sui suoi componenti, consulta Framework di input TV.
Creare un servizio di input TV utilizzando la libreria complementare TIF
La libreria complementare TIF è un framework che fornisce implementazioni estensibili delle funzionalità comuni dei servizi di input TV. È destinata all'uso da parte degli OEM per creare canali solo per Android 5.0 (livello API 21) fino ad Android 7.1 (livello API 25).
Aggiornare il progetto
La libreria complementare TIF è disponibile per l'uso legacy da parte degli OEM nel repository androidtv-sample-inputs. Consulta questo repository per un esempio di come includere la libreria in un'app.
Dichiarare il servizio di input TV nel manifest
La tua app deve fornire un servizio compatibile con TvInputService che il sistema utilizza per accedere all'app. La libreria complementare TIF fornisce la classe BaseTvInputService, che fornisce un'implementazione predefinita di TvInputService che puoi personalizzare. Crea una sottoclasse di BaseTvInputService e dichiarala nel manifest come servizio.
Nella dichiarazione del manifest, specifica l'autorizzazione BIND_TV_INPUT per consentire al servizio di collegare l'input TV al sistema. Un servizio di sistema esegue l'associazione e dispone dell'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. Dichiara anche i metadati del servizio come risorsa XML separata. La dichiarazione del servizio, il filtro per intent e la dichiarazione dei metadati del 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'input TV. Il file di metadati deve contenere anche un flag che indichi se gli utenti possono registrare i contenuti. Per saperne di più su come supportare la registrazione dei contenuti nella tua app, consulta Supportare la registrazione dei contenuti.
Il file dei metadati del servizio si trova nella directory delle risorse XML della tua app e deve corrispondere al nome della risorsa dichiarata nel manifest. Utilizzando le voci del manifest dell'esempio precedente, creerai il file XML in res/xml/richtvinputservice.xml con i seguenti contenuti:
<?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" />
Definire i canali e creare l'attività di configurazione
Il servizio di input TV deve definire almeno un canale a cui gli utenti accedono tramite l'app TV di sistema. Devi 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.
Innanzitutto, consenti alla tua app di leggere e scrivere nella Guida elettronica ai programmi (EPG) di sistema, i cui dati includono i canali e i programmi disponibili per l'utente. Per consentire alla tua app di eseguire queste azioni e di sincronizzarsi con l'EPG dopo il riavvio del dispositivo, aggiungi i seguenti elementi al 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" />
Poi, crea una classe che estenda la classe EpgSyncJobService. Questa classe astratta ti consente di creare un servizio di job che crea e aggiorna i canali nel database di sistema.
Nella sottoclasse, crea e restituisci l'elenco completo dei canali in getChannels. Se i canali provengono da un file XMLTV, utilizza la classe XmlTvParser. In caso contrario, genera i canali a livello di programmazione 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 una determinata finestra temporale sul canale. Restituisci un elenco di oggetti Program per il canale. Utilizza la classe XmlTvParser per ottenere i programmi da un file XMLTV o generali a livello di programmazione utilizzando la classe Program.Builder.
Per ogni oggetto Program, utilizza un oggetto InternalProviderData per impostare le informazioni del programma, ad esempio il tipo di video del programma. Se hai solo un numero limitato di programmi che vuoi che il canale ripeta in un loop, utilizza il metodo InternalProviderData.setRepeatable con un valore true quando imposti le informazioni sul programma.
Dopo aver implementato il servizio di 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 deve fornire un modo per sincronizzare i dati dei canali e dei programmi. Un modo per farlo è consentire all'utente di farlo utilizzando l'interfaccia utente nell'attività. Puoi anche fare in modo che l'app lo faccia automaticamente all'avvio dell'attività. Quando l'attività di configurazione deve sincronizzare le informazioni sui canali e sui programmi, l'app deve avviare il servizio di job:
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 di richiesta deve essere relativamente breve.
Utilizza il metodo setUpPeriodicSync per fare in modo che il servizio di job sincronizzi periodicamente i dati dei canali e dei programmi in background:
Kotlin
EpgSyncJobService.setUpPeriodicSync( context, inputId, ComponentName(context, SampleJobService::class.java) )
Java
EpgSyncJobService.setUpPeriodicSync(context, inputId, new ComponentName(context, SampleJobService.class));
La libreria complementare TIF fornisce un metodo di requestImmediateSync aggiuntivo con overload che ti consente di specificare la durata dei dati dei canali da sincronizzare in millisecondi. Il metodo predefinito sincronizza i dati dei canali per un'ora.
La libreria complementare TIF fornisce anche un metodo di setUpPeriodicSync aggiuntivo con overload che ti consente di specificare la durata dei dati dei canali da sincronizzare e la frequenza con cui deve avvenire la sincronizzazione periodica. Il metodo predefinito sincronizza i dati dei canali per 48 ore ogni 12 ore.
Per maggiori dettagli sui dati dei canali e sull'EPG, consulta Utilizzare i dati dei canali.
Gestire le richieste di sintonizzazione e la riproduzione dei contenuti multimediali
Quando un utente seleziona un canale specifico, l'app TV di sistema utilizza una Session, creata dalla tua app, per sintonizzarsi sul canale richiesto e riprodurre i contenuti. La libreria complementare TIF fornisce diverse classi che puoi estendere per gestire le chiamate di canali e sessioni dal sistema.
La sottoclasse BaseTvInputService crea sessioni che gestiscono le richieste di sintonizzazione. Esegui l'override del metodo onCreateSession, crea una sessione estesa dalla classe BaseTvInputService.Session e chiama super.sessionCreated con la nuova sessione. Nell'esempio seguente, 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 guardare uno dei tuoi canali, il sistema chiama il metodo onPlayChannel della sessione. Esegui l'override di questo metodo se devi eseguire un'inizializzazione speciale del canale prima dell'inizio della riproduzione del programma.
Il sistema ottiene quindi il programma attualmente pianificato e chiama il metodo onPlayProgram della sessione, specificando le informazioni del programma e l'ora di inizio in millisecondi. Utilizza l'interfaccia TvPlayer per avviare la riproduzione del programma.
Il codice del player multimediale deve implementare TvPlayer per gestire eventi di riproduzione specifici. La classe TvPlayer gestisce funzionalità come i controlli di time-shifting senza aggiungere complessità all'implementazione di BaseTvInputService.
Nel metodo getTvPlayer della sessione, restituisci
il player multimediale che implementa TvPlayer. L'
app di esempio del servizio di input TV implementa un player multimediale che utilizza
ExoPlayer.
Creare un servizio di input TV utilizzando il framework di input TV
Se il servizio di input TV non può utilizzare la libreria complementare TIF, devi implementare i seguenti componenti:
TvInputServicefornisce disponibilità a lunga esecuzione e in background per l'input TVTvInputService.Sessionmantiene lo stato dell'input TV e comunica con l'app di hostingTvContractdescrive i canali e i programmi disponibili per l'input TVTvContract.Channelsrappresenta le informazioni su un canale TVTvContract.Programsdescrive un programma TV con dati come il titolo del programma e l'ora di inizioTvTrackInforappresenta una traccia audio, video o di sottotitoliTvContentRatingdescrive una classificazione dei contenuti e consente schemi di classificazione dei contenuti personalizzatiTvInputManagerfornisce un'API all'app TV di sistema e gestisce l'interazione con gli input TV e le app
Devi anche eseguire le seguenti operazioni:
- Dichiara il servizio di input TV nel manifest, come descritto in Dichiarare il servizio di input TV nel manifest.
- Crea il file dei metadati del servizio.
- Crea e registra le informazioni sui canali e sui programmi.
- Crea l'attività di configurazione.
Definire il servizio di input TV
Per il tuo servizio, estendi la classe TvInputService. Un'implementazione di
TvInputService è un
servizio associato in cui il servizio di sistema
è il client che si associa a esso. I metodi del ciclo di vita del servizio che devi 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 parentale e quando si verifica una modifica nell'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.
Per saperne di più su come utilizzare i contenuti bloccati e fornire
il controllo parentale, consulta
Controllare i contenuti. Consulta TvInputManager per altre azioni basate sul sistema che potresti voler gestire nel tuo servizio di input TV.
The TvInputService crea un
TvInputService.Session che implementa Handler.Callback
per gestire le modifiche dello stato del player. Con
onSetSurface,
il TvInputService.Session imposta il Surface con i
contenuti video. Per saperne di più su come utilizzare Surface per il rendering dei video, consulta Integrare il player con la superficie.
TvInputService.Session gestisce l'evento onTune quando l'utente seleziona un canale e notifica all'app TV di sistema le modifiche ai contenuti e ai metadati dei contenuti. Questi metodi notify sono descritti in
Controllare i contenuti e Gestire ulteriormente la selezione delle tracce
in questo corso di formazione.
Definire l'attività di configurazione
L'app TV di sistema funziona con l'attività di configurazione definita per l'input 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'input TV.
L'attività di configurazione descrive all'app TV di sistema i canali resi disponibili tramite l'input TV, come mostrato nella lezione successiva, Creare e aggiornare i dati dei canali.