Opracowanie usługi wejścia TV

Usługa wejścia TV reprezentuje źródło strumienia multimediów i umożliwia prezentowanie treści multimedialnych linearnych, naziemnych kanałów i programów. Usługa wejścia TV umożliwia kontrola rodzicielska, informacje w przewodniku po programie i oceny treści. Usługa wejścia TV działa w aplikacji systemowej Android TV. Ta aplikacja ostatecznie kontroluje i prezentuje zawartość kanału na telewizorze. Systemowa aplikacja TV została opracowana specjalnie dla danego urządzenia i nie można przez aplikacje innych firm. Więcej informacji o platformie wejściowej TV (TIF) architektury i jej komponentów, zobacz Platforma wejścia TV.

Tworzenie usługi wejścia TV przy użyciu biblioteki towarzyszącej TIF

Biblioteka towarzysząca TIF to platforma, która udostępnia implementacji typowych funkcji usługi wejścia TV. Ma być wykorzystywana przez OEM do tworzenia i tylko na urządzeniach z Androidem w wersji od 5.0 (poziom interfejsu API 21) do 7.1 (poziom interfejsu API 25).

Zaktualizuj projekt

Biblioteka towarzysząca TIF jest dostępna do starszych wersji przez producentów OEM w androidtv-sample-inputs z repozytorium. Znajdziesz w nim przykład, jak umieścić bibliotekę w aplikacji.

Zadeklaruj w pliku manifestu usługę wejścia TV

Aplikacja musi udostępniać interfejs zgodny z TvInputService usługa, za pomocą której system uzyskuje dostęp do aplikacji. TIF-y Biblioteka towarzysząca udostępnia klasę BaseTvInputService, która zapewnia domyślną implementację tagu TvInputService które możesz dostosować. Utwórz podklasę BaseTvInputService, i zadeklaruj w pliku manifestu podklasę jako usługę.

W deklaracji pliku manifestu podaj BIND_TV_INPUT, aby zezwolić na służą do podłączenia wejścia TV do systemu. Usługa systemowa wykonuje wiązanie i ma Uprawnienie BIND_TV_INPUT. Systemowa aplikacja TV wysyła żądania do usług wejścia TV w interfejsie TvInputManager.

W deklaracji dotyczącej usługi umieść filtr intencji, który określa TvInputService jako działanie do wykonania z intencji. Zadeklaruj także metadane usługi jako oddzielny zasób XML. wyświetlana jest deklaracja dotycząca usługi, filtr intencji i deklaracja metadanych usługi w tym przykładzie:

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

Zdefiniuj metadane usługi w osobnym pliku XML. Usługa Plik XML metadanych musi zawierać interfejs konfiguracyjny opisujący konfigurację początkową i skanowanie kanałów. Plik metadanych powinien też zawierać atrybut z informacją, czy użytkownicy mogą nagrywać treści. Więcej na temat obsługi nagrywania treści w aplikacji można znaleźć w artykule Obsługa nagrywania treści.

Plik metadanych usługi znajduje się w katalogu zasobów XML dla Twojej aplikacji i musi być zgodna z nazwą zasobu zadeklarowanego w pliku manifestu. Korzystając z wpisów w pliku manifestu z poprzedniego przykładu: utworzymy plik XML pod adresem res/xml/richtvinputservice.xml, z klasą ta treść:

<?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" />

Zdefiniuj kanały i utwórz aktywność związaną z konfiguracją

Usługa wejścia TV musi definiować co najmniej jeden kanał, na którym użytkownicy za pomocą systemowej aplikacji TV. Zarejestruj swoje kanały w bazie danych systemu i udostępnić działanie konfiguracyjne, wywołuje, gdy nie może znaleźć kanału dla Twojej aplikacji.

Najpierw zezwól aplikacji na odczyt i zapis w systemie elektronicznym Przewodnik dla programistów (EPG), którego dane obejmują dostępne kanały i programy po stronie użytkownika. Aby umożliwić aplikacji wykonywanie tych działań, i przeprowadź synchronizację z Po ponownym uruchomieniu urządzenia dodaj te elementy do pliku manifestu aplikacji:

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

Dodaj ten element, aby mieć pewność, że Twoja aplikacja będzie widoczna w Sklep Google Play jako aplikacja do udostępniania kanałów z treściami na Androidzie TV:

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

Następnie utwórz zajęcia, które rozszerzą EpgSyncJobService zajęcia. Ta klasa abstrakcyjna ułatwia utworzenie usługi zadań, która tworzy i aktualizuje kanały w systemowej bazie danych.

W podklasie utwórz i zwróć pełną listę kanałów w getChannels() Jeśli kanały pochodzą z pliku XMLTV, użyj klasy XmlTvParser. W przeciwnym razie wygeneruj kanałów automatycznie za pomocą klasy Channel.Builder.

W przypadku każdego kanału system wywołuje funkcję getProgramsForChannel() gdy potrzebna jest lista programów, które można wyświetlić w danym przedziale czasu. na kanale. Zwraca listę obiektów Program dla argumentu kanał. Używaj klasy XmlTvParser, aby uzyskiwać programy z XMLTV ani wygenerować go automatycznie przy użyciu Program.Builder zajęcia.

W przypadku każdego obiektu Program użyj InternalProviderData, aby ustawić informacje o programie, takie jak typu wideo programu. Jeśli masz tylko ograniczoną liczbę programów, chcesz, aby kanał powtarzał się w pętli, użyj Metoda InternalProviderData.setRepeatable() o wartości true podczas podawania informacji o programie.

Po wdrożeniu usługi zadań dodaj ją do pliku manifestu aplikacji:

<service
    android:name=".sync.SampleJobService"
    android:permission="android.permission.BIND_JOB_SERVICE"
    android:exported="true" />

Na koniec utwórz aktywność związaną z konfiguracją. Aktywność związana z konfiguracją powinna dać Ci możliwość aby zsynchronizować dane dotyczące kanału i programu. Użytkownik może to zrobić np. za pomocą interfejsu użytkownika w ramach aktywności. Możliwe też, że aplikacja robi to automatycznie. po rozpoczęciu aktywności. Kiedy aktywność związana z konfiguracją musi zsynchronizować kanał informacje o programie, aplikacja powinna uruchamiać usługę zadań:

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

Do synchronizacji używaj metody requestImmediateSync() z usługą zadań. Użytkownik musi poczekać na zakończenie synchronizacji, więc staraj się utrzymać względnie krótki okres przesyłania zgłoszeń.

Aby udostępnić usługę zadania, użyj metody setUpPeriodicSync() okresowo synchronizują dane dotyczące kanałów i programu w tle:

Kotlin

EpgSyncJobService.setUpPeriodicSync(
        context,
        inputId,
        ComponentName(context, SampleJobService::class.java)
)

Java

EpgSyncJobService.setUpPeriodicSync(context, inputId,
        new ComponentName(context, SampleJobService.class));

Biblioteka towarzysząca TIF zapewnia dodatkową, przeciążoną metodę requestImmediateSync(), który pozwala określić czas trwania do synchronizacji danych kanału w milisekundach. Domyślna metoda synchronizuje 1 godzinę na podstawie danych kanału.

Biblioteka towarzysząca TIF zapewnia również dodatkową, przeciążoną metodę setUpPeriodicSync(), który pozwala określić czas trwania dane o kanale, które mają być synchronizowane, oraz jak często ma być przeprowadzana synchronizacja okresowa. Domyślna metoda synchronizuje dane kanału z 48 godzin co 12 godzin.

Więcej informacji o danych kanału i EPG znajdziesz na stronie Praca z danymi kanału.

Obsługa żądań dostrajania i odtwarzania multimediów

Gdy użytkownik wybierze określony kanał, systemowa aplikacja TV użyje Session, utworzone przez Twoją aplikację, aby dostroić wybrany kanał i odtwarzać treści. Biblioteka towarzysząca TIF obejmuje kilka klas, które można rozszerzyć na obsługę wywołań kanałów i sesji z systemu.

Twoja podklasa BaseTvInputService tworzy sesje, które obsługują żądań dostrajania. Zastąp onCreateSession(), utwórz sesję rozszerzoną z klasę BaseTvInputService.Session i wywołanie super.sessionCreated() z nową sesją. W następujących przykład onCreateSession() zwraca RichTvInputSessionImpl obiekt, który rozciąga się 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;
}

Gdy użytkownik zacznie oglądać jeden z Twoich kanałów w systemowej aplikacji TV, system wywołuje metodę onPlayChannel() sesji. Zastąp Jeśli musisz zainicjować jakiś kanał specjalnie przed rozpocznie się odtwarzanie programu.

Następnie system pobiera aktualnie zaplanowany program i wywołuje metody onPlayProgram() sesji, określającą program i czas rozpoczęcia w milisekundach. Użyj TvPlayer, aby rozpocząć odtwarzanie programu.

Kod odtwarzacza powinien implementować TvPlayer, aby obsługiwać określonych zdarzeń związanych z odtwarzaniem. Klasa TvPlayer obsługuje funkcje np. elementy sterujące przesuwaniem w czasie, które nie zwiększą złożoności BaseTvInputService.

W metodzie getTvPlayer() sesji funkcję zwracaj odtwarzacz, który obsługuje TvPlayer. Przykładowa aplikacja związana z usługą wejścia TV implementuje odtwarzacz multimedialny, który używa ExoPlayer,

Utwórz usługę wejścia TV przy użyciu struktury wejścia TV

Jeśli usługa wejścia TV nie może korzystać z biblioteki towarzyszącej TIF, wymagane jest do implementacji tych komponentów:

  • TvInputService zapewnia długoterminową dostępność i dostępność w tle dla wejście TV
  • TvInputService.Session utrzymuje stan wejścia TV i komunikuje się z aplikacją hostującą
  • TvContract opisuje kanały i programy dostępne na telewizorze. dane wejściowe
  • TvContract.Channels podaje informacje o kanale telewizyjnym
  • TvContract.Programs opisuje program telewizyjny z takimi danymi jak program tytuł i godzina rozpoczęcia
  • TvTrackInfo oznacza ścieżkę audio, wideo lub napisy.
  • TvContentRating opisuje ocenę treści, dopuszcza własne treści systemy ocen
  • TvInputManager udostępnia interfejs API systemowej aplikacji TV i zarządza interakcje z wejściami i aplikacjami TV

Musisz też wykonać te czynności:

  1. W pliku manifestu zadeklaruj usługę wejścia TV jako opisane w sekcji Zadeklaruj usługę wejścia TV w pliku manifestu.
  2. Utwórz plik metadanych usługi.
  3. Utwórz i zarejestruj informacje o kanale i programie.
  4. Utwórz aktywność związaną z konfiguracją.

Zdefiniuj usługę wejścia TV

W przypadku swojej usługi przedłużasz klasę TvInputService. O Implementacja TvInputService jest powiązana usługa, w której usługa systemowa to klient, który z nią wiąże. Metody cyklu życia usługi który trzeba wdrożyć, przedstawiono na rysunku 1.

Metoda onCreate() inicjuje i uruchamia HandlerThread, który zapewnia wątek procesu oddzielny od wątku UI do i obsługiwać działania systemowe. W poniższym przykładzie onCreate() inicjuje CaptioningManager i przygotowuje się do obsługi ACTION_BLOCKED_RATINGS_CHANGED i ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED czynności. Te działania opisują intencje systemowe uruchamiane, gdy użytkownik zmieni ustawienia kontroli rodzicielskiej oraz kiedy lista zablokowanych ocen uległa zmianie.

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

Rysunek 1. Cykl życia usługi TvInputService.

Zobacz Zarządzaj treściami, aby uzyskać więcej informacji o pracy z zablokowanymi treściami i udostępnianiu kontrolę rodzicielską. Na stronie TvInputManager znajdziesz więcej działań opartych na systemie, które może być obsługiwane w usłudze wejścia TV.

TvInputService tworzy TvInputService.Session z implementacją Handler.Callback do obsługi zmian stanu odtwarzacza. Na onSetSurface(), TvInputService.Session ustawia Surface z treści wideo. Patrz artykuł Integrowanie odtwarzacza z platformą. , aby dowiedzieć się więcej o używaniu tagu Surface do renderowania filmu.

TvInputService.Session obsługuje onTune() gdy użytkownik wybierze kanał i powiadomi systemową aplikację TV o zmianach w treści oraz metadanych treści. Te metody notify() zostały opisane tutaj: Kontrolowanie treści i wyboru ścieżki obsługi w dalszej części tego szkolenia.

Zdefiniuj aktywność związaną z konfiguracją

Systemowa aplikacja TV korzysta z określonych przez Ciebie czynności związanych z konfiguracją wejścia TV. aktywność związana z konfiguracją jest wymagana i musi zapewniać co najmniej 1 rekord kanału dla systemowej bazy danych. Aplikacja systemowa TV wywołuje aktywność konfiguracyjne, gdy nie może znaleźć kanału dla wejścia TV.

Działanie związane z konfiguracją opisuje w systemowej aplikacji TV kanały udostępnione na telewizorze jak widać w następnej lekcji – Tworzenie i edytowanie danych, i zaktualizuj dane o kanałach.

Dodatkowe materiały referencyjne