Usługa wejścia TV stanowi źródło strumienia multimediów i umożliwia prezentowanie treści multimedialnych w liniowy sposób nadawania telewizji jako kanały i programy. Dzięki usłudze wejścia TV możesz zapewnić kontrolę rodzicielską, informacje z przewodnika po programach i oceny treści. Usługa wejścia TV współpracuje z aplikacją systemową Android TV. Ta aplikacja steruje i wyświetla treści z kanału na telewizorze. Aplikacja systemowa TV została opracowana specjalnie dla urządzenia i niezmienna przez aplikacje innych firm. Więcej informacji o architekturze platformy wejściowej TV (TIF) i jej składnikach znajdziesz w artykule na temat platformy wejścia TV.
Tworzenie usługi wejścia TV za pomocą biblioteki towarzyszącej TIF
Biblioteka towarzysząca TIF to platforma, która umożliwia rozszerzalne implementacje popularnych funkcji usług wprowadzania danych telewizyjnych. Powinna być używana przez producentów OEM przy tworzeniu kanałów wyłącznie dla Androida od 5.0 (poziom interfejsu API 21) do 7.1 (poziom API 25).
Aktualizowanie projektu
Biblioteka towarzysząca TIF jest dostępna do użytku starszego typu przez producentów OEM w repozytorium androidtv-sample-inputs. W tym repozytorium znajdziesz przykład dodania biblioteki do aplikacji.
Zadeklarowanie usługi wejścia TV w pliku manifestu
Twoja aplikacja musi udostępniać usługę zgodną z TvInputService
, z której system uzyskuje dostęp do aplikacji. Biblioteka towarzysząca TIF udostępnia klasę BaseTvInputService
stanowiącą domyślną implementację tagu TvInputService
, którą możesz dostosować. Utwórz podklasę klasy BaseTvInputService
i zadeklaruj ją w pliku manifestu jako usługę.
W deklaracji w pliku manifestu określ uprawnienie BIND_TV_INPUT
, aby umożliwić usłudze połączenie wejścia TV z systemem. Usługa systemowa wykonuje powiązanie i ma uprawnienie BIND_TV_INPUT
.
Aplikacja systemowa TV wysyła żądania do usług wprowadzania danych TV przez interfejs TvInputManager
.
W deklaracji usługi umieść filtr intencji, który wskazuje TvInputService
jako działanie, które ma zostać wykonane z zamiarem. Zadeklaruj także metadane usługi jako oddzielny zasób XML. Deklaracja usługi, filtr intencji i deklaracja metadanych usługi znajdują się 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. Plik XML metadanych usługi musi zawierać interfejs konfiguracji, który opisuje początkową konfigurację wejścia TV i skanowanie kanałów. Plik metadanych powinien też zawierać flagę informującą, czy użytkownicy mogą nagrywać treści. Więcej informacji na temat nagrywania treści w aplikacji znajdziesz w artykule Obsługa nagrywania treści.
Plik metadanych usługi znajduje się w katalogu zasobów XML aplikacji i musi odpowiadać nazwie zasobu zadeklarowanego w pliku manifestu. Korzystając z wpisów w pliku manifestu z poprzedniego przykładu, utwórz plik XML pod adresem res/xml/richtvinputservice.xml
z następującą treścią:
<?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 zdefiniować co najmniej 1 kanał, do którego użytkownicy mają dostęp przez systemową aplikację TV. Rejestrowanie kanałów w bazie danych systemu i udostępnianie działania konfiguracji, które jest wywoływane przez system, gdy nie może znaleźć kanału dla aplikacji.
Najpierw włącz w aplikacji odczyt i zapis w systemie Electronic Programming Guide (EPG), którego dane obejmują kanały i programy dostępne dla użytkownika. Aby umożliwić aplikacji wykonywanie tych działań i synchronizowanie ich z EPG po ponownym uruchomieniu urządzenia, dodaj do manifestu aplikacji te elementy:
<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 pojawi się w Sklepie Google Play jako aplikacja udostępniająca kanały treści na Androidzie TV:
<uses-feature android:name="android.software.live_tv" android:required="true" />
Następnie utwórz klasę, która rozszerza klasę EpgSyncJobService
. Ta klasa abstrakcyjna ułatwia tworzenie usługi zadań, która tworzy i aktualizuje kanały w bazie danych systemu.
W podklasie utwórz i zwróć pełną listę kanałów w zadaniu getChannels()
. Jeśli Twoje kanały pochodzą z pliku XMLTV, użyj klasy XmlTvParser
. W przeciwnym razie generuj kanały automatycznie za pomocą klasy Channel.Builder
.
W przypadku każdego kanału system wywołuje funkcję getProgramsForChannel()
, gdy potrzebuje listy programów, które można wyświetlić w danym przedziale czasu na kanale. Zwraca listę obiektów Program
kanału. Użyj klasy XmlTvParser
, aby uzyskać programy z pliku XMLTV lub wygeneruj je automatycznie za pomocą klasy Program.Builder
.
W przypadku każdego obiektu Program
użyj obiektu InternalProviderData
, aby ustawić informacje o programie, takie jak typ filmu w programie. Jeśli masz ograniczoną liczbę programów i chcesz, aby kanał powtarzał w pętli, użyj metody InternalProviderData.setRepeatable()
z wartością true
podczas ustawiania informacji o programie.
Po zaimplementowaniu 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ą. Konfiguracja powinna umożliwiać synchronizację danych kanału i programu. Użytkownik może to zrobić na przykład za pomocą interfejsu użytkownika aktywności. Aplikacja może też robić to automatycznie po rozpoczęciu aktywności. Gdy aktywność związana z konfiguracją musi synchronizować informacje o kanale i programie, aplikacja powinna uruchomić usługę zadania:
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));
Aby zsynchronizować usługę zadań, użyj metody requestImmediateSync()
. Użytkownik musi poczekać na zakończenie synchronizacji, więc okres żądania powinien być stosunkowo krótki.
Użyj metody setUpPeriodicSync()
, aby usługa zadań okresowo synchronizowała dane kanału 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 udostępnia dodatkową, przeciążoną metodę requestImmediateSync()
, która umożliwia określenie w milisekundach czasu trwania synchronizacji danych kanału. Domyślna metoda synchronizuje
dane kanału z jednej godziny.
Biblioteka towarzysząca TIF udostępnia też dodatkową, przeciążoną metodę setUpPeriodicSync()
, która pozwala określić czas trwania synchronizacji danych kanału oraz częstotliwość synchronizacji. Metoda domyślna synchronizuje dane kanału z 48 godzin co 12 godzin.
Więcej informacji na temat danych kanału i EPG znajdziesz w artykule Praca z danymi kanału.
Obsługa żądań dostrajania i odtwarzania multimediów
Gdy użytkownik wybiera konkretny kanał, aplikacja systemowa TV korzysta z utworzonego przez Twoją aplikację elementu Session
, który dostraja się do tego kanału i odtwarza treści. Biblioteka towarzysząca TIF zawiera kilka zajęć, które możesz rozszerzyć o obsługę wywołań kanałów i sesji z systemu.
Klasa podrzędna BaseTvInputService
tworzy sesje, które obsługują żądania dostrajania. Zastąp metodę onCreateSession()
, utwórz sesję przedłużoną z klasy BaseTvInputService.Session
i wywołaj super.sessionCreated()
swoją nową sesją. W tym przykładzie onCreateSession()
zwraca obiekt RichTvInputSessionImpl
, który rozszerza zakres 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 rozpocznie oglądanie jednego z Twoich kanałów za pomocą systemowej aplikacji TV, system wywoła metodę onPlayChannel()
Twojej sesji. Zignoruj tę metodę, jeśli musisz zainicjować specjalne zainicjowanie kanału przed rozpoczęciem odtwarzania programu.
System pobiera obecnie zaplanowany program i wywołuje metodę onPlayProgram()
sesji, podając informacje o programie oraz czas rozpoczęcia w milisekundach. Aby rozpocząć odtwarzanie programu, użyj interfejsu TvPlayer
.
W kodzie odtwarzacza multimediów powinien być implementowany obiekt TvPlayer
do obsługi określonych zdarzeń odtwarzania. Klasa TvPlayer
obsługuje takie funkcje jak elementy sterujące przesuwaniem w czasie, nie zwiększając złożoności implementacji BaseTvInputService
.
W metodzie getTvPlayer()
sesji zwróć odtwarzacz, który korzysta z metody TvPlayer
. Przykładowa
usługa wprowadzania danych TV zawiera odtwarzacz, który korzysta z ExoPlayer.
Utwórz usługę wejścia TV za pomocą schematu wejścia TV
Jeśli usługa wejścia TV nie obsługuje biblioteki towarzyszącej TIF, musisz zaimplementować te komponenty:
TvInputService
zapewnia długotrwałe działanie i dostępność wejścia TV w tleTvInputService.Session
utrzymuje stan wejścia TV i komunikuje się z aplikacją hostującąTvContract
opisuje kanały i programy dostępne dla wejścia TVTvContract.Channels
reprezentuje informacje o kanale telewizyjnymTvContract.Programs
opisuje program telewizyjny za pomocą takich danych jak tytuł i godzina rozpoczęciaTvTrackInfo
reprezentuje ścieżkę audio, wideo lub napisyTvContentRating
opisuje ocenę treści i umożliwia stosowanie niestandardowych schematów oceny treści.TvInputManager
udostępnia interfejs API dla systemowej aplikacji TV i zarządza interakcją z wejściami i aplikacjami telewizora
Musisz też wykonać te czynności:
- Zadeklaruj w pliku manifestu usługę wejścia TV zgodnie z opisem w sekcji Deklarowanie usługi wejścia TV w pliku manifestu.
- Utwórz plik metadanych usługi.
- Utwórz i zarejestruj informacje o kanale i programie.
- Utwórz aktywność związaną z konfiguracją.
Określ usługę wejścia TV
W przypadku swojej usługi wydłużasz zajęcia TvInputService
. Implementacja TvInputService
to powiązana usługa, w której usługą systemową jest powiązany z nią klient. Metody cyklu życia usługi, które należy wdrożyć, zostały pokazane na ilustracji 1.
Metoda onCreate()
inicjuje i uruchamia HandlerThread
, który udostępnia wątek procesu niezależny od wątku UI do obsługi działań zależnych od systemu. W poniższym przykładzie metoda onCreate()
inicjuje CaptioningManager
i przygotowuje się do obsługi działań ACTION_BLOCKED_RATINGS_CHANGED
oraz ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED
. Te działania opisują intencje systemowe wywoływane, gdy użytkownik zmienia ustawienia kontroli rodzicielskiej oraz gdy następuje zmiana listy zablokowanych ocen.
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); }
Więcej informacji o pracy z zablokowanymi treściami i zapewnianiu kontroli rodzicielskiej znajdziesz w artykule
Kontrola nad treściami. Więcej informacji o działaniach systemowych, które możesz wykorzystać w usłudze wejściowej telewizora, znajdziesz w sekcji TvInputManager
.
TvInputService
tworzy tag TvInputService.Session
, który implementuje Handler.Callback
do obsługi zmian stanu odtwarzacza. W przypadku onSetSurface()
właściwość TvInputService.Session
ustawia treść wideo na potrzeby elementu Surface
. Więcej informacji o renderowaniu filmów za pomocą komponentu Surface
znajdziesz w artykule Integrowanie odtwarzacza z platformą.
Gdy użytkownik wybierze kanał, TvInputService.Session
obsługuje zdarzenie onTune()
, a także powiadamia aplikację systemową na telewizory o zmianach w treściach i metadanych treści. Te metody notify()
zostały opisane w sekcjach
Kontrolowanie treści i Wybór ścieżki w dalszej części tego szkolenia.
Zdefiniuj aktywność związaną z konfiguracją
Aplikacja systemowa TV obsługuje zdefiniowane przez Ciebie działanie związane z konfiguracją wejścia TV. Działanie konfiguracyjne jest wymagane i musi zapewnić co najmniej jeden rekord kanału dla bazy danych systemu. Aplikacja systemowa TV wywołuje działanie konfiguracyjne, gdy nie może znaleźć kanału dla wejścia TV.
Ćwiczenie związane z konfiguracją opisuje systemową aplikację TV kanały udostępnione przez wejście na telewizor, co pokazano w następnej lekcji: Tworzenie i aktualizowanie danych kanału.