Usługa wejścia TV reprezentuje źródło strumienia multimediów i umożliwia prezentowanie treści multimedialnych w sposób linearny, podobny do transmisji telewizyjnej, jako kanały i programy. Dzięki usłudze wejścia TV możesz udostępniać kontrolę rodzicielską, informacje z przewodnika po programach i oceny treści. Usługa wejścia TV współpracuje z systemową aplikacją TV na Androida. Ta aplikacja ostatecznie kontroluje i prezentuje treści kanałów na telewizorze. Systemowa aplikacja TV jest opracowana specjalnie na urządzenie i nie może być zmieniana przez aplikacje innych firm. Więcej informacji o architekturze i komponentach TV Input Framework (TIF) znajdziesz w artykule TV Input Framework.
Tworzenie usługi wejścia TV za pomocą biblioteki TIF Companion Library
Biblioteka TIF Companion Library to framework, który udostępnia rozszerzalne implementacje typowych funkcji usługi wejścia TV. Jest przeznaczona do używania tylko przez producentów OEM do tworzenia kanałów na Androidzie od wersji 5.0 (poziom interfejsu API 21) do 7.1 (poziom interfejsu API 25).
Aktualizowanie projektu
Biblioteka TIF Companion Library jest dostępna do użytku przez producentów OEM w repozytorium androidtv-sample-inputs. W tym repozytorium znajdziesz przykład, jak dołączyć bibliotekę do aplikacji.
Deklarowanie usługi wejścia TV w pliku manifestu
Twoja aplikacja musi udostępniać usługę zgodną z TvInputService, której system używa do uzyskiwania dostępu do aplikacji. Biblioteka TIF
Companion Library udostępnia klasę BaseTvInputService, która
zawiera domyślną implementację TvInputService
, którą możesz dostosować. Utwórz podklasę 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 łączenie wejścia TV z systemem. Powiązanie wykonuje usługa systemowa, która ma uprawnienie BIND_TV_INPUT.
Systemowa aplikacja TV wysyła żądania do usług wejścia TV za pomocą interfejsu TvInputManager.
W deklaracji usługi umieść filtr intencji, który określa TvInputService jako działanie do wykonania za pomocą intencji. Zadeklaruj też metadane usługi jako osobny zasób XML. Deklaracja usługi, filtr intencji i deklaracja metadanych usługi są pokazane 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ę wskazującą, czy użytkownicy mogą nagrywać treści. Więcej informacji o tym, jak obsługiwać nagrywanie 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 mieć taką samą nazwę jak zasób zadeklarowany w pliku manifestu. Korzystając z wpisów w pliku manifestu z poprzedniego przykładu, utwórz plik XML w res/xml/richtvinputservice.xml o tej zawartoś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" />
Definiowanie kanałów i tworzenie aktywności konfiguracji
Usługa wejścia TV musi definiować co najmniej 1 kanał, do którego użytkownicy mają dostęp za pomocą systemowej aplikacji TV. Zarejestruj kanały w bazie danych systemu i udostępnij aktywność konfiguracji, którą system wywołuje, gdy nie może znaleźć kanału dla Twojej aplikacji.
Najpierw włącz w aplikacji możliwość odczytywania i zapisywania danych w systemowym elektronicznym przewodniku po programach (EPG), który zawiera informacje o kanałach i programach dostępnych dla użytkownika. Aby umożliwić aplikacji wykonywanie tych działań i synchronizowanie się z EPG 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 Twoja aplikacja wyświetlała się w Sklepie Google Play jako aplikacja, która udostępnia kanały treści w 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 umożliwia utworzenie usługi zadania, która tworzy i aktualizuje kanały w bazie danych systemu.
W podklasie utwórz i zwróć pełną listę kanałów w getChannels. Jeśli Twoje kanały pochodzą z pliku XMLTV, użyj klasy XmlTvParser. W przeciwnym razie wygeneruj kanały programowo za pomocą klasy Channel.Builder.
W przypadku każdego kanału system wywołuje getProgramsForChannel, gdy potrzebuje listy programów, które można obejrzeć w danym przedziale czasu na kanale. Zwróć listę obiektów Program dla kanału. Użyj klasy XmlTvParser, aby uzyskać programy z pliku XMLTV, lub wygeneruj je programowo za pomocą klasy Program.Builder.
W przypadku każdego obiektu Program użyj obiektu InternalProviderData, aby ustawić informacje o programie, takie jak jego typ. Jeśli masz tylko ograniczoną liczbę programów, które mają być odtwarzane w pętli, podczas ustawiania informacji o programie użyj metody InternalProviderData.setRepeatable z wartością true.
Po zaimplementowaniu usługi zadania 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ść konfiguracji. Aktywność konfiguracji powinna umożliwiać synchronizowanie danych kanałów i programów. Możesz to zrobić, umożliwiając użytkownikowi wykonanie tej czynności za pomocą interfejsu w aktywności. Możesz też skonfigurować aplikację tak, aby robiła to automatycznie po uruchomieniu aktywności. Gdy aktywność konfiguracji musi zsynchronizować informacje o kanałach i programach, 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ę zadania, użyj metody requestImmediateSync. Użytkownik musi poczekać na zakończenie synchronizacji, dlatego okres żądania powinien być stosunkowo krótki.
Aby usługa zadania okresowo synchronizowała dane kanałów i programów w tle, użyj metody setUpPeriodicSync:
Kotlin
EpgSyncJobService.setUpPeriodicSync( context, inputId, ComponentName(context, SampleJobService::class.java) )
Java
EpgSyncJobService.setUpPeriodicSync(context, inputId, new ComponentName(context, SampleJobService.class));
Biblioteka TIF Companion Library udostępnia dodatkową przeciążoną metodę requestImmediateSync, która umożliwia określenie czasu trwania danych kanału do zsynchronizowania w milisekundach. Domyślna metoda synchronizuje dane kanału z 1 godziny.
Biblioteka TIF Companion Library udostępnia też dodatkową przeciążoną metodę setUpPeriodicSync, która umożliwia określenie czasu trwania danych kanału do zsynchronizowania oraz częstotliwości synchronizacji okresowej. Domyślna metoda synchronizuje dane kanału z 48 godzin co 12 godzin.
Więcej informacji o danych kanału i EPG znajdziesz w artykule Praca z danymi kanału.
Obsługa żądań dostrajania i odtwarzania multimediów
Gdy użytkownik wybierze konkretny kanał, systemowa aplikacja TV używa
Session, utworzonej przez Twoją aplikację, aby dostroić się do żądanego kanału
i odtworzyć treści. Biblioteka TIF Companion Library udostępnia kilka klas, które możesz rozszerzyć, aby obsługiwać wywołania kanałów i sesji z systemu.
Podklasa BaseTvInputService tworzy sesje, które obsługują żądania dostrajania. Zastąp metodę onCreateSession, utwórz sesję rozszerzoną z klasy BaseTvInputService.Session i wywołaj super.sessionCreated z nową sesją. W tym przykładzie onCreateSession zwraca obiekt RichTvInputSessionImpl, który rozszerza 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 używa systemowej aplikacji TV, aby rozpocząć oglądanie jednego z Twoich kanałów, system wywołuje metodę onPlayChannel sesji. Zastąp tę metodę, jeśli przed rozpoczęciem odtwarzania programu musisz wykonać specjalną inicjację kanału.
Następnie system pobiera aktualnie zaplanowany program i wywołuje metodę onPlayProgram sesji, określając informacje o programie i czas rozpoczęcia w milisekundach. Aby rozpocząć odtwarzanie programu, użyj interfejsu TvPlayer.
Kod odtwarzacza multimediów powinien implementować TvPlayer, aby obsługiwać określone zdarzenia odtwarzania. Klasa TvPlayer obsługuje funkcje takie jak sterowanie przesunięciem w czasie bez dodawania złożoności do implementacji BaseTvInputService.
W metodzie getTvPlayer sesji zwróć
odtwarzacz multimediów, który implementuje TvPlayer. Przykładowa aplikacja
usługi wejścia TV implementuje odtwarzacz multimediów, który korzysta z
ExoPlayera.
Tworzenie usługi wejścia TV za pomocą TV Input Framework
Jeśli usługa wejścia TV nie może korzystać z biblioteki TIF Companion Library, musisz zaimplementować te komponenty:
TvInputServicezapewnia długotrwałą i działającą w tle dostępność dla wejścia TV.TvInputService.Sessionutrzymuje stan wejścia TV i komunikuje się z aplikacją hostującą.TvContractopisuje kanały i programy dostępne dla wejścia TV .TvContract.Channelsreprezentuje informacje o kanale TV.TvContract.Programsopisuje program TV z danymi takimi jak tytuł programu i czas rozpoczęcia.TvTrackInforeprezentuje ścieżkę audio, wideo lub napisów.TvContentRatingopisuje ocenę treści i umożliwia tworzenie niestandardowych schematów ocen .TvInputManagerudostępnia interfejs API systemowej aplikacji TV i zarządza interakcjami z wejściami TV i aplikacjami.
Musisz też wykonać te czynności:
- Zadeklaruj usługę wejścia TV w pliku manifestu, jak opisano w Deklarowanie usługi wejścia TV w pliku manifestu.
- Utwórz plik metadanych usługi.
- Utwórz i zarejestruj informacje o kanałach i programach.
- Utwórz aktywność konfiguracji.
Definiowanie usługi wejścia TV
W przypadku usługi rozszerzasz klasę TvInputService. Implementacja
TvInputService to
powiązana usługa, w której usługa systemowa
jest klientem, który się z nią wiąże. Metody cyklu życia usługi, które musisz zaimplementować, są przedstawione na ilustracji 1.
Metoda onCreate inicjuje i uruchamia HandlerThread, który udostępnia wątek procesu oddzielny od wątku UI do obsługi działań inicjowanych przez system. W tym przykładzie metoda onCreate inicjuje CaptioningManager i przygotowuje się do obsługi działań ACTION_BLOCKED_RATINGS_CHANGED i 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 na liście 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); }
Ilustracja 1.Cykl życia TvInputService.
Więcej informacji o pracy z zablokowanymi treściami i udostępnianiu
kontroli rodzicielskiej znajdziesz w artykule
Zarządzanie treściami. Więcej informacji o działaniach inicjowanych przez system, które możesz chcieć obsługiwać w usłudze wejścia TV, znajdziesz w artykule TvInputManager.
The TvInputService creates a
TvInputService.Session that implements Handler.Callback
aby obsługiwać zmiany stanu odtwarzacza. Za pomocą
onSetSurface,
usługa TvInputService.Session ustawia Surface z
treściami wideo. Więcej informacji o pracy z Surface w celu renderowania wideo znajdziesz w artykule Integrowanie odtwarzacza z powierzchnią.
TvInputService.Session obsługuje zdarzenie onTune, gdy użytkownik wybierze kanał, i powiadamia systemową aplikację TV o zmianach w treściach i metadanych treści. Te metody notify są opisane w dalszej części tego szkolenia w sekcjach
Zarządzanie treściami i Obsługa wyboru ścieżki.
Definiowanie aktywności konfiguracji
Systemowa aplikacja TV współpracuje z aktywnością konfiguracji, którą definiujesz dla wejścia TV. Aktywność konfiguracji jest wymagana i musi udostępniać co najmniej 1 rekord kanału w bazie danych systemu. Systemowa aplikacja TV wywołuje aktywność konfiguracji, gdy nie może znaleźć kanału dla wejścia TV.
Aktywność konfiguracji opisuje systemowej aplikacji TV kanały udostępniane przez wejście TV , jak pokazano w następnej lekcji Tworzenie i aktualizowanie danych kanału.