Kanały na ekranie głównym

Ekran główny Androida TV zawiera interfejs, w którym polecane treści są wyświetlane w tabeli kanałów i programów. Każdy wiersz to kanał. Kanał zawiera karty wszystkich programów dostępnych na tym kanale:

Ekran główny Androida TV
Ekran główny Androida TV

Z tego dokumentu dowiesz się, jak dodawać kanały i programy do ekranu głównego, aktualizować treści, obsługiwać działania użytkowników i zapewniać im jak najlepsze wrażenia. (Jeśli chcesz dowiedzieć się więcej o interfejsie API, wypróbuj codelab dotyczący ekranu głównego i obejrzyj sesję I/O 2017 dotyczącą Androida TV)

Interfejs ekranu głównego

Aplikacje mogą tworzyć nowe kanały, dodawać, usuwać i aktualizować programy na kanale oraz kontrolować kolejność programów na kanale. Aplikacja może na przykład utworzyć kanał o nazwie „Co nowego” i wyświetlać karty nowo dostępnych programów.

Aplikacje nie mogą kontrolować kolejności, w jakiej kanały pojawiają się na ekranie głównym. Gdy aplikacja utworzy nowy kanał, ekran główny doda go na końcu listy kanałów. Użytkownik może zmieniać kolejność kanałów, ukrywać je i wyświetlać.

Kanał Warte obejrzenia

Kanał Warte obejrzenia to drugi wiersz, który pojawia się na ekranie głównym po wierszu aplikacji. Ten kanał jest tworzony i utrzymywany przez system. Twoja aplikacja może dodawać programy do kanału Warte obejrzenia. Więcej informacji znajdziesz w sekcji Dodawanie programów do kanału Warte obejrzenia.

Kanały aplikacji

Wszystkie kanały tworzone przez Twoją aplikację mają ten sam cykl życia:

  1. Użytkownik znajduje kanał w Twojej aplikacji i prosi o dodanie go do ekranu głównego.
  2. Aplikacja tworzy kanał i dodaje go do TvProvider (w tym momencie kanał nie jest widoczny).
  3. Aplikacja prosi system o wyświetlenie kanału.
  4. System prosi użytkownika o zatwierdzenie nowego kanału.
  5. Nowy kanał pojawia się w ostatnim wierszu ekranu głównego.

Kanał domyślny

Twoja aplikacja może oferować dowolną liczbę kanałów, które użytkownik może dodać do ekranu głównego. Zanim kanał pojawi się na ekranie głównym, użytkownik musi go zwykle wybrać i zatwierdzić. Każda aplikacja ma możliwość utworzenia 1 domyślnego kanału. Kanał domyślny jest wyjątkowy, ponieważ automatycznie pojawia się na ekranie głównym. Użytkownik nie musi o niego prosić.

Wymagania wstępne

Ekran główny Androida TV używa interfejsów API TvProvider Androida do zarządzania kanałami i programami tworzonymi przez Twoją aplikację. Aby uzyskać dostęp do danych dostawcy, dodaj do pliku manifestu aplikacji to uprawnienie:

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

Biblioteka pomocy TvProvider ułatwia korzystanie z dostawcy. Dodaj ją do zależności w pliku build.gradle:

Dynamiczny

implementation 'androidx.tvprovider:tvprovider:1.0.0'

Kotlin

implementation("androidx.tvprovider:tvprovider:1.0.0")

Aby pracować z kanałami i programami, pamiętaj, aby w programie uwzględnić te instrukcje importu biblioteki pomocy:

Kotlin

import android.support.media.tv.Channel
import android.support.media.tv.TvContractCompat
import android.support.media.tv.ChannelLogoUtils
import android.support.media.tv.PreviewProgram
import android.support.media.tv.WatchNextProgram

Java

import android.support.media.tv.Channel;
import android.support.media.tv.TvContractCompat;
import android.support.media.tv.ChannelLogoUtils;
import android.support.media.tv.PreviewProgram;
import android.support.media.tv.WatchNextProgram;

Kanały

Pierwszy kanał utworzony przez Twoją aplikację staje się jej kanałem domyślnym. Kanał domyślny automatycznie pojawia się na ekranie głównym. Zanim inne utworzone przez Ciebie kanały pojawią się na ekranie głównym, użytkownik musi je wybrać i zaakceptować.

Tworzenie kanału

Aplikacja powinna prosić system o wyświetlanie nowo dodanych kanałów tylko wtedy, gdy działa na pierwszym planie. Zapobiega to wyświetlaniu przez aplikację okna z prośbą o zgodę na dodanie kanału, gdy użytkownik korzysta z innej aplikacji. Jeśli spróbujesz dodać kanał, gdy aplikacja działa w tle, metoda onActivityResult() działania zwróci kod stanu RESULT_CANCELED.

Aby utworzyć kanał:

  1. Utwórz narzędzie do tworzenia kanałów i ustaw jego atrybuty. Pamiętaj, że typ kanału musi być TYPE_PREVIEW. W razie potrzeby dodaj więcej atrybutów.

    Kotlin

    val builder = Channel.Builder()
    // Every channel you create must have the type `TYPE_PREVIEW`
    builder.setType(TvContractCompat.Channels.TYPE_PREVIEW)
            .setDisplayName("Channel Name")
            .setAppLinkIntentUri(uri)
    

    Java

    Channel.Builder builder = new Channel.Builder();
    // Every channel you create must have the type `TYPE_PREVIEW`
    builder.setType(TvContractCompat.Channels.TYPE_PREVIEW)
            .setDisplayName("Channel Name")
            .setAppLinkIntentUri(uri);
    
  2. Wstaw kanał do dostawcy:

    Kotlin

    var channelUri = context.contentResolver.insert(
            TvContractCompat.Channels.CONTENT_URI, builder.build().toContentValues())
    

    Java

    Uri channelUri = context.getContentResolver().insert(
            TvContractCompat.Channels.CONTENT_URI, builder.build().toContentValues());
    
  3. Aby później dodać programy do kanału, musisz zapisać identyfikator kanału. Wyodrębnij identyfikator kanału ze zwróconego URI:

    Kotlin

    var channelId = ContentUris.parseId(channelUri)
    

    Java

    long channelId = ContentUris.parseId(channelUri);
    
  4. Musisz dodać logo kanału. Użyj Uri lub Bitmap. Ikona logo powinna mieć wymiary 80 dp × 80 dp i musi być nieprzezroczysta. Jest wyświetlana pod okrągłą maską:

    Maska ikony ekranu głównego telewizora

    Kotlin

    // Choose one or the other
    storeChannelLogo(context: Context, channelId: Long, logoUri: Uri) // also works if logoUri is a URL
    storeChannelLogo(context: Context, channelId: Long, logo: Bitmap)
    

    Java

    // Choose one or the other
    storeChannelLogo(Context context, long channelId, Uri logoUri); // also works if logoUri is a URL
    storeChannelLogo(Context context, long channelId, Bitmap logo);
    
  5. Utwórz kanał domyślny (opcjonalnie): gdy aplikacja utworzy pierwszy kanał, możesz ustawić go jako domyślny kanał, aby pojawił się na ekranie głównym od razu, bez żadnej interakcji użytkownika. Inne utworzone przez Ciebie kanały nie będą widoczne, dopóki użytkownik ich jawnie nie wybierze.

    Kotlin

    TvContractCompat.requestChannelBrowsable(context, channelId)
    

    Java

    TvContractCompat.requestChannelBrowsable(context, channelId);
    
  6. Spraw, aby kanał domyślny pojawił się przed otwarciem aplikacji. Aby to zrobić, dodaj BroadcastReceiver, który nasłuchuje działania android.media.tv.action.INITIALIZE_PROGRAMS. Ekran główny wysyła to działanie po zainstalowaniu aplikacji:

    <receiver
      android:name=".RunOnInstallReceiver"
      android:exported="true">
        <intent-filter>
          <action android:name="android.media.tv.action.INITIALIZE_PROGRAMS" />
          <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </receiver>
    

    Podczas instalowania aplikacji z nieoficjalnego źródła w trakcie programowania możesz przetestować ten krok, wywołując intencję za pomocą adb. W tym przypadku your.package.name/.YourReceiverName to BroadcastReceiver Twojej aplikacji:

    adb shell am broadcast -a android.media.tv.action.INITIALIZE_PROGRAMS -n \
        your.package.name/.YourReceiverName
    

    W rzadkich przypadkach aplikacja może otrzymać transmisję w tym samym czasie, gdy użytkownik ją uruchamia. Upewnij się, że Twój kod nie próbuje dodać kanału domyślnego więcej niż raz.

Aktualizowanie kanału

Aktualizowanie kanałów jest bardzo podobne do ich tworzenia.

Użyj innego narzędzia Channel.Builder, aby ustawić atrybuty, które wymagają zmiany.

Aby zaktualizować kanał, użyj ContentResolver. Użyj identyfikatora kanału, który został zapisany podczas dodawania kanału:

Kotlin

context.contentResolver.update(
        TvContractCompat.buildChannelUri(channelId),
        builder.build().toContentValues(),
        null,
        null
)

Java

context.getContentResolver().update(TvContractCompat.buildChannelUri(channelId),
    builder.build().toContentValues(), null, null);

Aby zaktualizować logo kanału, użyj storeChannelLogo().

Usuwanie kanału

Kotlin

context.contentResolver.delete(TvContractCompat.buildChannelUri(channelId), null, null)

Java

context.getContentResolver().delete(TvContractCompat.buildChannelUri(channelId), null, null);

Programy

Programy to poszczególne karty treści wyświetlane na kanale. Możesz publikować programy zarówno na niestandardowych kanałach aplikacji, jak i na zarządzanym przez system kanale Warte obejrzenia.

Dodawanie programów do kanału aplikacji

Utwórz narzędzie PreviewProgram.Builder i ustaw jego atrybuty:

Kotlin

val builder = PreviewProgram.Builder()
builder.setChannelId(channelId)
        .setType(TvContractCompat.PreviewPrograms.TYPE_CLIP)
        .setTitle("Title")
        .setDescription("Program description")
        .setPosterArtUri(uri)
        .setIntentUri(uri)
        .setInternalProviderId(appProgramId)

Java

PreviewProgram.Builder builder = new PreviewProgram.Builder();
builder.setChannelId(channelId)
        .setType(TvContractCompat.PreviewPrograms.TYPE_CLIP)
        .setTitle("Title")
        .setDescription("Program description")
        .setPosterArtUri(uri)
        .setIntentUri(uri)
        .setInternalProviderId(appProgramId);

Dodaj więcej atrybutów w zależności od typu programu. (Atrybuty dostępne dla każdego typu programu znajdziesz w tabelach poniżej.)

Wstaw program do dostawcy:

Kotlin

var programUri = context.contentResolver.insert(TvContractCompat.PreviewPrograms.CONTENT_URI,
        builder.build().toContentValues())

Java

Uri programUri = context.getContentResolver().insert(TvContractCompat.PreviewPrograms.CONTENT_URI,
      builder.build().toContentValues());

Pobierz identyfikator programu, aby móc się do niego później odwoływać:

Kotlin

val programId = ContentUris.parseId(programUri)

Java

long programId = ContentUris.parseId(programUri);

Dodawanie programów do kanału Warte obejrzenia

Aby wstawić programy do kanału Warte obejrzenia, przeczytaj sekcję Dodawanie programów do kanału Warte obejrzenia.

Aktualizowanie programu

Możesz zmienić informacje o programie. Możesz na przykład zaktualizować cenę wypożyczenia filmu lub pasek postępu pokazujący, ile programu użytkownik obejrzał.

Użyj narzędzia PreviewProgram.Builder, aby ustawić atrybuty, które chcesz zmienić, a następnie wywołaj getContentResolver().update, aby zaktualizować program. Określ identyfikator programu, który został zapisany podczas dodawania programu:

Kotlin

context.contentResolver.update(
        TvContractCompat.buildPreviewProgramUri(programId),
                builder.build().toContentValues(), null, null
)

Java

context.getContentResolver().update(TvContractCompat.buildPreviewProgramUri(programId),
    builder.build().toContentValues(), null, null);

Usuwanie programu

Kotlin

context.contentResolver
        .delete(TvContractCompat.buildPreviewProgramUri(programId), null, null)

Java

context.getContentResolver().delete(TvContractCompat.buildPreviewProgramUri(programId), null, null);

Obsługa działań użytkowników

Twoja aplikacja może pomóc użytkownikom w odkrywaniu treści, udostępniając interfejs do wyświetlania i dodawania kanałów. Aplikacja powinna też obsługiwać interakcje z Twoimi kanałami po ich pojawieniu się na ekranie głównym.

Odkrywanie i dodawanie kanałów

Twoja aplikacja może udostępniać element interfejsu, który umożliwia użytkownikowi wybieranie i dodawanie kanałów (np. przycisk z prośbą o dodanie kanału).

Gdy użytkownik poprosi o konkretny kanał, wykonaj ten kod, aby uzyskać jego zgodę na dodanie kanału do interfejsu ekranu głównego:

Kotlin

val intent = Intent(TvContractCompat.ACTION_REQUEST_CHANNEL_BROWSABLE)
intent.putExtra(TvContractCompat.EXTRA_CHANNEL_ID, channelId)
try {
  activity.startActivityForResult(intent, 0)
} catch (e: ActivityNotFoundException) {
  // handle error
}

Java

Intent intent = new Intent(TvContractCompat.ACTION_REQUEST_CHANNEL_BROWSABLE);
intent.putExtra(TvContractCompat.EXTRA_CHANNEL_ID, channelId);
try {
   activity.startActivityForResult(intent, 0);
} catch (ActivityNotFoundException e) {
  // handle error
}

System wyświetla okno z prośbą o zatwierdzenie kanału. Obsłuż wynik żądania w metodzie onActivityResult działania (Activity.RESULT_CANCELED lub Activity.RESULT_OK).

Zdarzenia ekranu głównego Androida TV

Gdy użytkownik wchodzi w interakcję z programami i kanałami opublikowanymi przez aplikację, ekran główny wysyła do aplikacji intencje:

  • Gdy użytkownik wybierze logo kanału, ekran główny wyśle do aplikacji adres Uri zapisany w atrybucie APP_LINK_INTENT_URI kanału. Aplikacja powinna po prostu uruchomić swój główny interfejs lub widok związany z wybranym kanałem.
  • Gdy użytkownik wybierze program, ekran główny wyśle do aplikacji adres Uri zapisany w atrybucie INTENT_URI programu. Aplikacja powinna odtworzyć wybraną treść.
  • Użytkownik może wskazać, że nie jest już zainteresowany programem i chce go usunąć z interfejsu ekranu głównego. System usuwa program z interfejsu i wysyła do aplikacji, która jest właścicielem programu, intencję (android.media.tv.ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED lub android.media.tv.ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED) z identyfikatorem programu. Aplikacja powinna usunąć program z dostawcy i NIE powinna go ponownie wstawiać.

Pamiętaj, aby utworzyć filtry intencji dla wszystkich Uris, które ekran główny wysyła w przypadku interakcji użytkownika. Przykład:

<receiver
   android:name=".WatchNextProgramRemoved"
   android:enabled="true"
   android:exported="true">
   <intent-filter>
       <action android:name="android.media.tv.ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED" />
   </intent-filter>
</receiver>

Uwagi dodatkowe

  • Wiele aplikacji telewizyjnych wymaga, aby użytkownicy się logowali. W takim przypadku BroadcastReceiver, który nasłuchuje android.media.tv.action.INITIALIZE_PROGRAMS, powinien sugerować treści kanału użytkownikom, którzy nie są uwierzytelnieni. Aplikacja może na przykład początkowo wyświetlać najlepsze lub obecnie popularne treści. Po zalogowaniu się użytkownika może wyświetlać treści spersonalizowane. To świetna okazja dla aplikacji, aby zachęcić użytkowników do zakupu przed zalogowaniem.
  • Gdy aplikacja nie jest na pierwszym planie i musisz zaktualizować kanał lub program, użyj JobScheduler, aby zaplanować pracę (patrz JobScheduler i JobService).
  • Jeśli aplikacja działa nieprawidłowo (np. ciągle wysyła do dostawcy spam z danymi), system może cofnąć jej uprawnienia dostawcy. Pamiętaj, aby otoczyć kod, który uzyskuje dostęp do dostawcy, klauzulami try-catch, aby obsługiwać wyjątki związane z bezpieczeństwem.
  • Zanim zaktualizujesz programy i kanały, zapytaj dostawcę o dane, które chcesz zaktualizować, i uzgodnij je. Nie ma na przykład potrzeby aktualizowania programu, który użytkownik chce usunąć z interfejsu. Użyj zadania w tle, które wstawia lub aktualizuje dane w dostawcy po zapytaniu o istniejące dane i poproszeniu o zatwierdzenie kanałów. Możesz uruchamiać to zadanie, gdy aplikacja się uruchamia i gdy musi zaktualizować swoje dane.

Kotlin

context.contentResolver
      .query(
          TvContractCompat.buildChannelUri(channelId),
              null, null, null, null).use({
                  cursor-> if (cursor != null and cursor.moveToNext()) {
                                val channel = Channel.fromCursor(cursor)
                                if (channel.isBrowsable()) {
                                    //update channel's programs
                                }
                            }
              })

Java

try (Cursor cursor = context.getContentResolver()
          .query(
              TvContractCompat.buildChannelUri(channelId),
              null,
              null,
              null,
              null)) {
                  if (cursor != null &amp;&amp; cursor.moveToNext()) {
                      Channel channel = Channel.fromCursor(cursor);
                      if (channel.isBrowsable()) {
                          //update channel's programs
                      }
                  }
              }
  • Używaj unikalnych adresów URI dla wszystkich obrazów (logo, ikon, obrazów treści). Pamiętaj, aby podczas aktualizowania obrazu używać innego adresu URI. Wszystkie obrazy są buforowane. Jeśli nie zmienisz adresu URI podczas zmiany obrazu, stary obraz będzie nadal się wyświetlać.

  • Pamiętaj, że klauzule WHERE są niedozwolone, a wywołania dostawców z klauzulami WHERE spowodują zgłoszenie wyjątku związanego z bezpieczeństwem.

Atrybuty

W tej sekcji opisujemy osobno atrybuty kanału i programu.

Atrybuty kanału

W przypadku każdego kanału musisz określić te atrybuty:

Atrybut Uwagi
TYP ustaw na TYPE_PREVIEW.
DISPLAY_NAME ustaw na nazwę kanału.
APP_LINK_INTENT_URI Gdy użytkownik wybierze logo kanału, system wyśle intencję uruchomienia działania, które prezentuje treści związane z kanałem. Ustaw ten atrybut na adres URI używany w filtrze intencji dla tego działania.

Kanał ma też 6 pól zarezerwowanych do użytku wewnętrznego aplikacji. Te pola mogą służyć do przechowywania kluczy lub innych wartości, które mogą pomóc aplikacji w mapowaniu kanału na jego wewnętrzną strukturę danych:

  • INTERNAL_PROVIDER_ID
  • INTERNAL_PROVIDER_DATA
  • INTERNAL_PROVIDER_FLAG1
  • INTERNAL_PROVIDER_FLAG2
  • INTERNAL_PROVIDER_FLAG3
  • INTERNAL_PROVIDER_FLAG4

Atrybuty programu

Informacje o atrybutach każdego typu programu znajdziesz na poszczególnych stronach:

Przykładowy kod

Aby dowiedzieć się więcej o tworzeniu aplikacji, które wchodzą w interakcje z ekranem głównym i dodają kanały oraz programy do ekranu głównego Androida TV, zapoznaj się z naszym codelabem dotyczącym ekranu głównego .