Sviluppare un servizio di ingresso TV

Un servizio di input TV rappresenta un'origine di stream multimediale e consente di presentare i contenuti multimediali in un la moda lineare, in ambito 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 ingresso TV funziona con l'app Android System TV. Questa app controlla e presenta i contenuti del canale sulla TV. L'app di sistema TV è sviluppata appositamente per il dispositivo e immutabile da app di terze parti. Per ulteriori informazioni sul TIF (TV Input Framework) dell'architettura e dei suoi componenti, Framework di input TV.

Creare un servizio di ingresso TV utilizzando la libreria complementare TIF

La libreria companion TIF è un framework che fornisce funzionalità implementazioni di funzionalità comuni dei servizi di input TV. È destinata agli OEM per creare disponibili solo per i canali Android dalla versione 5.0 (livello API 21) ad Android 7.1 (livello API 25).

Aggiorna il progetto

La libreria companion TIF è disponibile per l'utilizzo precedente da parte degli OEM nei input-di-esempio-androidtv repository Git. Guarda quel repository per un esempio di come includere la libreria in un'app.

Dichiara il tuo servizio di input TV nel file manifest

La tua app deve fornire una versione compatibile con TvInputService servizio utilizzato dal sistema per accedere alla tua app. Il TIF La libreria companion fornisce la classe BaseTvInputService, che fornisce un'implementazione predefinita di TvInputService che puoi personalizzare. Crea una sottoclasse BaseTvInputService, e dichiarare la sottoclasse nel file manifest come servizio.

Nella dichiarazione del file manifest, specifica l'autorizzazione BIND_TV_INPUT per consentire l'accesso a per collegare l'ingresso della TV al sistema. Un servizio di sistema esegue l'associazione e ha Autorizzazione BIND_TV_INPUT. L'app di sistema per la TV invia richieste ai servizi di ingresso della TV tramite l'interfaccia TvInputManager.

Nella dichiarazione del servizio, includi un filtro per intent che specifichi TvInputService come azione da eseguire con l'intento. Dichiara anche i metadati del servizio come risorsa XML separata. La vengono mostrate la dichiarazione del servizio, il filtro per intent e la dichiarazione dei metadati del servizio nel seguente esempio:

<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 servizio Il file XML dei metadati deve includere un'interfaccia di configurazione che descriva l'input della TV configurazione iniziale e scansione dei canali. Il file dei metadati deve contenere anche che indica se gli utenti sono in grado di registrare o meno i contenuti. Per ulteriori informazioni informazioni su come supportare la registrazione di contenuti nella tua app, consulta Supporto della registrazione di contenuti.

Il file dei metadati del servizio si trova nella directory delle risorse XML per la tua app e deve corrispondere al nome della risorsa che hai dichiarato del file manifest. Utilizzando le voci manifest dell'esempio precedente, crea il file XML all'indirizzo res/xml/richtvinputservice.xml, con 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" />

Definisci i canali e crea la tua attività di configurazione

Il tuo servizio di input TV deve definire almeno un canale a cui gli utenti l'accesso tramite l'app di sistema per la TV. Devi registrare i tuoi canali nel database di sistema e fornire un'attività di configurazione che il sistema quando non riesce a trovare un canale per la tua app.

Innanzitutto, abilita l'app a leggere e scrivere sul sistema Guida alla programmazione (EPG), i cui dati includono canali e programmi disponibili all'utente. Per consentire alla tua app di eseguire queste azioni ed eseguire la sincronizzazione con 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 Il Google Play Store come app che fornisce canali di contenuti su Android TV:

<uses-feature
    android:name="android.software.live_tv"
    android:required="true" />

Quindi, crea una classe che ampli EpgSyncJobService . Questa classe astratta semplifica la creazione di un servizio job che crea e aggiorna i canali nel database del sistema.

Nella sottoclasse, crea e restituisci l'elenco completo dei canali in getChannels(). Se i tuoi canali provengono da un file XMLTV, usa la classe XmlTvParser. Altrimenti, 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. Restituisce un elenco di Program oggetti per il canale. Utilizza il corso XmlTvParser per ottenere programmi da un XMLTV o generali in modo programmatico utilizzando il Program.Builder corso.

Per ogni oggetto Program, utilizza un'istruzione InternalProviderData per impostare le informazioni del programma, come tipo di video del programma. Se disponi solo di un numero limitato di programmi vuoi che il canale si ripeta in loop, usa InternalProviderData.setRepeatable() con il valore true quando imposti le informazioni sul programma.

Dopo aver implementato il servizio di job, aggiungilo al file 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 fornirti un modo per sincronizzare i dati del canale e del programma. Un modo per farlo è che l'utente lo faccia tramite l'interfaccia utente nell'attività. Potresti anche chiedere all'app di farlo automaticamente all'inizio dell'attività. Quando è necessario sincronizzare canale e attività di configurazione informazioni sul programma, l'app deve avviare il servizio 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));

Usa il metodo requestImmediateSync() per la sincronizzazione del job di job. L'utente deve attendere il completamento della sincronizzazione, quindi dovresti che il periodo di richiesta sia relativamente breve.

Utilizza il metodo setUpPeriodicSync() per richiedere il servizio job sincronizza periodicamente i dati del canale e del programma 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 offre un ulteriore metodo di sovraccarico di requestImmediateSync() che ti consente di specificare la durata dati del canale da sincronizzare in millisecondi. Il metodo predefinito sincronizza di dati del canale.

La libreria companion TIF fornisce anche un ulteriore metodo di sovraccarico di setUpPeriodicSync() che ti consente di specificare la durata i dati dei canali da sincronizzare e la frequenza della sincronizzazione periodica. La il metodo predefinito sincronizza 48 ore di dati del canale ogni 12 ore.

Per ulteriori dettagli sui dati del canale e sull'EPG, consulta Lavora con i dati del canale.

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 sintonizzarti sul canale richiesto e riprodurre contenuti. La libreria companion TIF offre diverse che puoi estendere per gestire le chiamate di canale e sessione dal sistema.

La sottoclasse BaseTvInputService crea sessioni che gestiscono richieste di ottimizzazione. Sostituisci il valore Metodo onCreateSession(), crea una sessione estesa da la classe BaseTvInputService.Session e richiama super.sessionCreated() con la nuova sessione. Nel seguente Ad esempio, onCreateSession() restituisce un Oggetto RichTvInputSessionImpl che si 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 di sistema TV per iniziare a visualizzare uno dei tuoi canali, il sistema chiama il metodo onPlayChannel() della tua sessione. Esegui override questo metodo se devi eseguire un'inizializzazione speciale del canale prima viene avviata la riproduzione del programma.

Il sistema ottiene quindi il programma attualmente in programma e chiama il tuo il metodo onPlayProgram() della sessione, specificando il programma informazioni e l'ora di inizio in millisecondi. Utilizza la Interfaccia TvPlayer per avviare la riproduzione del programma.

Per poter gestire il codice del media player, devi implementare TvPlayer specifici eventi di riproduzione. La classe TvPlayer gestisce le funzionalità come i controlli timeshift senza complicare le cose Implementazione di BaseTvInputService.

Nel metodo getTvPlayer() della tua sessione, torna il media player che implementa TvPlayer. La 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 ingresso TV non può utilizzare la libreria complementare TIF, devi avere per implementare i seguenti componenti:

  • TvInputService offre disponibilità a lungo termine e in background per l'ingresso TV
  • TvInputService.Session mantiene lo stato di ingresso della TV e comunica con l'app di hosting
  • TvContract descrive i canali e i programmi disponibili per la TV input
  • TvContract.Channels rappresenta informazioni su un canale TV
  • TvContract.Programs descrive un programma TV con dati come il programma titolo e ora di inizio
  • TvTrackInfo rappresenta una traccia audio, video o di sottotitoli
  • TvContentRating descrive una classificazione dei contenuti e consente contenuti personalizzati schemi di valutazione
  • TvInputManager fornisce un'API all'app TV di sistema e gestisce l'interazione con ingressi e app TV

Devi inoltre effettuare le seguenti operazioni:

  1. Dichiara il tuo servizio di input TV nel file manifest, come descritto nella sezione Dichiarare il servizio di ingresso TV nel del file manifest.
  2. Crea il file dei metadati del servizio.
  3. Crea e registra le informazioni sul tuo canale e sul programma.
  4. Crea la tua attività di configurazione.

Definisci il servizio di ingresso TV

Per il tuo servizio, estendi la classe TvInputService. R L'implementazione di TvInputService è servizio associato in cui il servizio di sistema è il client che vi vincola. Metodi del ciclo di vita dei servizi che devi implementare sono illustrati nella Figura 1.

Il metodo onCreate() inizializza e avvia il metodo HandlerThread, che fornisce un thread di processo separato dal thread dell'interfaccia utente a gestire le azioni basate sul sistema. Nell'esempio seguente, onCreate() inizializza CaptioningManager e si prepara a gestire ACTION_BLOCKED_RATINGS_CHANGED e ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED azioni. Questi descrivono gli intent di sistema attivati quando l'utente modifica le impostazioni del Controllo genitori e quando c'è una modifica nell'elenco delle valutazioni 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.

Vedi Controlla i contenuti per ulteriori informazioni su come gestire i contenuti bloccati e fornire Controllo genitori. Consulta TvInputManager per altre azioni basate sul sistema che che potresti voler gestire nel tuo servizio di input TV.

L'TvInputService crea un TvInputService.Session che implementa Handler.Callback per gestire le modifiche dello stato del player. Con onSetSurface(), TvInputService.Session imposta Surface con contenuti video. Vedi Integrare il player con la piattaforma per ulteriori informazioni sull'utilizzo di Surface per il rendering dei video.

TvInputService.Session gestisce onTune() evento quando l'utente seleziona un canale e avvisa l'app di sistema TV per eventuali modifiche ai contenuti e metadati dei contenuti. Questi notify() metodi sono descritti in Controllare i contenuti e Gestire la selezione delle tracce in questo corso di formazione.

Definisci l'attività di configurazione

L'app di sistema TV utilizza l'attività di configurazione che definisci per l'ingresso della TV. La l'attività di configurazione è obbligatoria e deve fornire almeno un record di canale per il database di sistema. La L'app per TV di sistema richiama l'attività di configurazione quando non riesce a trovare un canale per l'ingresso della TV.

L'attività di configurazione descrive all'app di sistema TV i canali resi disponibili tramite la TV come mostrato nella prossima lezione, Creare e aggiornare i dati del canale.

Riferimenti aggiuntivi