Tworzenie aplikacji do multimediów do aut

Android Auto i Android Automotive OS pomagają przenieść treści z aplikacji do multimediów użytkowników w samochodach. Aplikacja do multimediów dla samochodów musi udostępniać usługę przeglądarki multimediów do systemu Android Auto i Androida Automotive lub do innej aplikacji z multimediami przeglądarka może wykryć i wyświetlić Twoje treści.

W tym przewodniku przyjęto założenie, że masz już aplikację do multimediów, która odtwarza dźwięk na i czy jest ona zgodna z aplikacją do multimediów Androida .

W tym przewodniku opisano wymagane komponenty MediaBrowserService i MediaSession, których potrzebuje Twoja aplikacja, aby działać na Androidzie Auto lub Androidzie Automotive OS. Po ukończeniu podstawowej infrastruktury medialnej możesz obsługę Androida Auto i wsparcie dotyczące: system operacyjny Android Automotive do multimediów .

Zanim zaczniesz

  1. Zapoznaj się z dokumentacją interfejsu Android Media API.
  2. Przeczytaj artykuł Tworzenie aplikacji do multimediów. .
  3. Przeczytaj najważniejsze terminy i koncepcje wymienione w tej sekcji.

Najważniejsze terminy i koncepcje

Usługa przeglądarki multimediów
Usługa na Androida zaimplementowana przez aplikację do multimediów zgodną z MediaBrowserServiceCompat. API. Aplikacja używa tej usługi do udostępniania swoich treści.
Przeglądarka multimediów
Interfejs API używany przez aplikacje do multimediów do wykrywania i wyświetlania usług przeglądarki multimediów swoje treści. Android Auto i system operacyjny Android Automotive używają przeglądarki multimediów do znajdź usługę przeglądarki multimediów w aplikacji.
Element multimedialny

Przeglądarka multimediów porządkuje zawartość w drzewie MediaItem obiektów. Element multimedialny może mieć jeden z tych flag albo oba:

  • FLAG_PLAYABLE: wskazuje, że element to liść na drzewie treści. Element reprezentuje pojedynczy strumień dźwięku, np. utwór z albumu, rozdział w audiobooku lub odcinek podcastu.
  • FLAG_BROWSABLE: wskazuje, że element jest węzłem w drzewie treści i że ma dzieci. Na przykład element reprezentuje album, a jego elementy podrzędne są utworów z albumu.

Element multimedialny, który można przeglądać i odtwarzać, działa jak playlista. Dostępne opcje i wybierz ten element, aby bawić się wszystkimi jego dziećmi, lub przejrzyj jego zawartość dzieci.

Zoptymalizowane pod kątem pojazdów

Działanie dla aplikacji na system operacyjny Android Automotive zgodnej z Wytyczne projektowe dotyczące systemu operacyjnego Android Automotive Interfejs tych aktywności nie jest rysowany przez system operacyjny Android Automotive, dlatego musi być zgodna z wytycznymi dotyczącymi projektowania. Zwykle zawiera większe docelowe elementy dotykowe i rozmiary czcionek, obsługuje tryb dzienny i nocny. i zwiększyć kontrast.

Interfejsy zoptymalizowane pod kątem pojazdów można wyświetlać tylko wtedy, gdy Ograniczenia dotyczące wygody użytkowników nie obowiązują, ponieważ może wymagać szerszej uwagi lub interakcji ze strony użytkownika. CUXR nie działają, gdy samochód jest zatrzymywany lub zaparkowany, ale zawsze jest aktywny; gdy samochód jest w ruchu.

Nie musisz projektować działań dla Androida Auto, własny interfejs zoptymalizowany pod kątem pojazdu wykorzystuje informacje w usłudze przeglądarki multimediów.

Skonfiguruj pliki manifestu aplikacji

Zanim utworzysz usługę przeglądarki multimediów, musisz skonfigurować pliki manifestu aplikacji.

Zadeklarowanie usługi przeglądarki multimediów

Zarówno Android Auto, jak i system operacyjny Android Automotive łączą się z Twoją aplikacją przez w usłudze przeglądarki multimediów do przeglądania elementów multimedialnych. Deklarowanie multimediów usługa przeglądarki w pliku manifestu, aby umożliwić systemom operacyjnym Android Auto i Android Automotive znaleźć usługę i połączyć się z aplikacją.

Fragment kodu poniżej pokazuje, jak zadeklarować usługę przeglądarki multimediów pliku manifestu. Umieść ten kod w pliku manifestu swojej Moduł systemu operacyjnego Android Automotive oraz w pliku manifestu aplikacji na telefon.

<application>
    ...
    <service android:name=".MyMediaBrowserService"
             android:exported="true">
        <intent-filter>
            <action android:name="android.media.browse.MediaBrowserService"/>
        </intent-filter>
    </service>
    ...
</application>

Określ ikony aplikacji

Musisz określić ikony aplikacji, które mogą być dostępne na Androidzie Auto i Androidzie Automotive będzie reprezentować aplikację w interfejsie systemu. Wymagane są 2 rodzaje ikon:

  • Ikona programu uruchamiającego
  • Ikona informacji
.

Ikona programu uruchamiającego

Ikona Menu z aplikacjami reprezentuje Twoją aplikację w interfejsie systemowym, np. w Menu z aplikacjami i w panelu z ikonami. Możesz określić, czy ikona z Twoja aplikacja mobilna do reprezentowania aplikacji multimedialnej w samochodzie przy użyciu tego pliku manifestu deklaracja:

<application
    ...
    android:icon="@mipmap/ic_launcher"
    ...
/>

Aby użyć innej ikony niż w aplikacji mobilnej, ustaw właściwość android:icon w elemencie <service> usługi przeglądarki multimediów w pliku manifestu:

<application>
    ...
    <service
        ...
        android:icon="@mipmap/auto_launcher"
        ...
    />
</application>

Ikona informacji

Rysunek 1. Ikona informacji o autorze na karcie multimediów.

Ikona atrybucji jest używana w miejscach, gdzie pierwszeństwo mają treści multimedialne, np. na kartach multimedialnych. Rozważ ponowne wykorzystanie małej ikony używanej w powiadomieniach. Ta ikona musi być monochromatyczna. Możesz wybrać ikonę, która będzie reprezentować aplikację, korzystając z tej deklaracji w pliku manifestu:

<application>
    ...
    <meta-data
        android:name="androidx.car.app.TintableAttributionIcon"
        android:resource="@drawable/ic_status_icon" />
    ...
</application>

Tworzenie usługi przeglądarki multimediów

Usługę przeglądarki multimediów można utworzyć przez rozszerzenie MediaBrowserServiceCompat zajęcia. Zarówno Android Auto, jak i system operacyjny Android Automotive będą mogły korzystać z Twojej usługi wykonaj następujące czynności:

  • Przejrzyj hierarchię treści aplikacji, aby wyświetlić menu użytkownikowi.
  • Uzyskiwanie tokena MediaSessionCompat aplikacji do sterowania odtwarzaniem dźwięku.

Możesz też użyć usługi przeglądarki multimediów, aby umożliwić innym klientom dostęp do treści multimedialnych z aplikacji Te klienty multimediów mogą być innymi aplikacjami przez telefon użytkownika lub mogą być innymi klientami zdalnymi.

Przepływ pracy w usłudze przeglądarki multimediów

Z tej sekcji dowiesz się, jak systemy operacyjne Android Automotive i Android Automotive Korzystaj z usługi przeglądarki multimediów automatycznie w trakcie typowego przepływu pracy użytkownika.

  1. Użytkownik uruchamia Twoją aplikację na Androidzie Automotive lub na Androidzie Auto.
  2. System operacyjny Android Automotive lub Android Auto kontaktuje się z przeglądarką multimediów w Twojej aplikacji usługi za pomocą onCreate() . W Twojej implementacji usługi onCreate() musisz utworzyć i zarejestrować MediaSessionCompat i jego obiekt wywołania zwrotnego.
  3. System operacyjny Android Automotive lub Android Auto wywołuje numer onGetRoot() Twojej usługi. aby uzyskać główny element multimedialny w hierarchii treści. Główny element multimedialny nie jest wyświetlana. jest używany do pobierania dodatkowych treści z aplikacji.
  4. System operacyjny Android Automotive lub Android Auto wywołuje numer Twojej usługi onLoadChildren() metody pobierania elementów podrzędnych głównego elementu multimedialnego. system operacyjny Android Automotive Android Auto wyświetla te elementy multimedialne jako elementy treści najwyższego poziomu. Zobacz Aby uzyskać więcej informacji, utwórz strukturę menu głównego na tej stronie z informacjami o oczekiwaniach systemu na tym poziomie.
  5. Jeśli użytkownik wybierze element multimedialny, który można przeglądać, onLoadChildren() jest wywoływana ponownie, by pobrać elementy podrzędne wybranego elementu menu.
  6. Jeśli użytkownik wybierze element multimedialny z możliwością odtwarzania, system operacyjny Android Automotive lub Android Automatycznie wywołuje odpowiednią metodę wywołania zwrotnego sesji multimediów, aby wykonać to działanie.
  7. Jeśli aplikacja obsługuje tę funkcję, użytkownik może też wyszukiwać Twoje treści. W tym etui na system operacyjny Android Automotive lub Android Auto onSearch() .

Tworzenie hierarchii treści

Android Auto i Android Automotive OS nawiązują połączenie z usługą przeglądarki multimediów w Twojej aplikacji, aby aby dowiedzieć się, jakie treści są dostępne. Musisz wdrożyć 2 metody w ramach usługa przeglądarki multimediów, która obsługuje tę funkcję: onGetRoot() oraz onLoadChildren()

Wdróż onGetRoot

onGetRoot() Twojej usługi zwraca informacje o węźle głównym hierarchii treści. Android Auto i Android Automotive OS używają tego węzła głównego, aby zażądać pozostałej części za pomocą onLoadChildren() .

Ten fragment kodu pokazuje prostą implementację Metoda onGetRoot():

Kotlin

override fun onGetRoot(
    clientPackageName: String,
    clientUid: Int,
    rootHints: Bundle?
): BrowserRoot? =
    // Verify that the specified package is allowed to access your
    // content. You'll need to write your own logic to do this.
    if (!isValid(clientPackageName, clientUid)) {
        // If the request comes from an untrusted package, return null.
        // No further calls will be made to other media browsing methods.

        null
    } else MediaBrowserServiceCompat.BrowserRoot(MY_MEDIA_ROOT_ID, null)

Java

@Override
public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
    Bundle rootHints) {

    // Verify that the specified package is allowed to access your
    // content. You'll need to write your own logic to do this.
    if (!isValid(clientPackageName, clientUid)) {
        // If the request comes from an untrusted package, return null.
        // No further calls will be made to other media browsing methods.

        return null;
    }

    return new MediaBrowserServiceCompat.BrowserRoot(MY_MEDIA_ROOT_ID, null);
}

Bardziej szczegółowy przykład tej metody znajdziesz tutaj: onGetRoot() w przykładowej aplikacji Universal Android Music Player na GitHubie.

Dodaj weryfikację pakietu dla onGetRoot()

Po nawiązaniu połączenia z numerem onGetRoot() usługi pakiet wywołujący przekazuje do Twojej usługi informacje identyfikacyjne. Twoje na podstawie tych informacji decyduje, czy pakiet ma dostęp do treści. Możesz np. ograniczyć dostęp do treści aplikacji do listy zatwierdzonych pakietów, porównując clientPackageNamez listą dozwolonych i weryfikację certyfikatu użytego do podpisania pliku APK pakietu. Jeśli pakiet nie może zostaną zweryfikowane, wróć do null, by odmówić dostępu do treści.

Aby udostępnić aplikacje systemowe, takie jak Android Auto czy system operacyjny Android Automotive, z dostępem do Twoich treści, usługa musi zawsze zwracać wartość inną niż zero BrowserRoot, gdy te aplikacje systemowe wywołują onGetRoot() . Podpis aplikacji systemu operacyjnego Android Automotive może się różnić w zależności od marki i modelu samochodu, musisz więc zezwalać na połączenia do sprawnej obsługi systemu operacyjnego Android Automotive.

Fragment kodu poniżej pokazuje, jak za pomocą usługi możesz sprawdzić, czy Pakiet do wykonywania połączeń to aplikacja systemowa:

fun isKnownCaller(
    callingPackage: String,
    callingUid: Int
): Boolean {
    ...
    val isCallerKnown = when {
       // If the system is making the call, allow it.
       callingUid == Process.SYSTEM_UID -> true
       // If the app was signed by the same certificate as the platform
       // itself, also allow it.
       callerSignature == platformSignature -> true
       // ... more cases
    }
    return isCallerKnown
}

Ten fragment kodu jest cytatem z PackageValidator w przykładowej aplikacji Universal Android Music Player na GitHubie. Wyświetl te zajęcia . onGetRoot() .

Oprócz zezwalania na aplikacje systemowe musisz też zezwolić Asystentowi Google połączyć się z urządzeniem MediaBrowserService. Pamiętaj, że Asystent Google ma osobne nazwy pakietów na telefon (w tym Androida Auto) i system operacyjny Android Automotive.

Wdróż onLoadChildren()

Po otrzymaniu obiektu węzła głównego, Androida Auto i systemu operacyjnego Android Automotive i utwórz menu najwyższego poziomu, dzwoniąc pod numer onLoadChildren() na obiekcie węzła głównego, aby pobrać jego elementy podrzędne. Aplikacje klienckie tworzą podmenu według tę samą metodę przy użyciu obiektów węzłów podrzędnych.

Każdy węzeł w hierarchii treści jest reprezentowany przez MediaBrowserCompat.MediaItem obiektu. Każdy z tych elementów multimedialnych jest identyfikowany za pomocą unikalnego ciągu identyfikatora. Klient aplikacje traktują te ciągi identyfikatorów jako nieprzezroczyste tokeny. Gdy aplikacja kliencka chce przeglądać internet do menu podrzędnego lub odtwarzania elementu multimedialnego, przekazuje token. To Twoja aplikacja jest odpowiedzialna Powiązanie tokena z odpowiednim elementem multimedialnym.

Ten fragment kodu pokazuje prostą implementację atrybutu onLoadChildren() :

Kotlin

override fun onLoadChildren(
    parentMediaId: String,
    result: Result<List<MediaBrowserCompat.MediaItem>>
) {
    // Assume for example that the music catalog is already loaded/cached.

    val mediaItems: MutableList<MediaBrowserCompat.MediaItem> = mutableListOf()

    // Check whether this is the root menu:
    if (MY_MEDIA_ROOT_ID == parentMediaId) {

        // Build the MediaItem objects for the top level
        // and put them in the mediaItems list.
    } else {

        // Examine the passed parentMediaId to see which submenu we're at
        // and put the children of that menu in the mediaItems list.
    }
    result.sendResult(mediaItems)
}

Java

@Override
public void onLoadChildren(final String parentMediaId,
    final Result<List<MediaBrowserCompat.MediaItem>> result) {

    // Assume for example that the music catalog is already loaded/cached.

    List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<>();

    // Check whether this is the root menu:
    if (MY_MEDIA_ROOT_ID.equals(parentMediaId)) {

        // Build the MediaItem objects for the top level
        // and put them in the mediaItems list.
    } else {

        // Examine the passed parentMediaId to see which submenu we're at
        // and put the children of that menu in the mediaItems list.
    }
    result.sendResult(mediaItems);
}

Pełny przykład tej metody znajdziesz w onLoadChildren() w przykładowej aplikacji Universal Android Music Player na GitHubie.

Uporządkuj menu główne

Rysunek 2. Treść główna wyświetlana jako karty nawigacyjne.

Android Auto i Android Automotive OS mają określone ograniczenia dotyczące do struktury menu głównego. Są one przekazywane do MediaBrowserService za pomocą wskazówek pierwiastkowych, które można odczytać za pomocą argumentu Bundle przekazywanego do onGetRoot(). Stosując się do tych wskazówek, system optymalnie wyświetla zawartość główną jako kart nawigacyjnych. Jeśli nie zastosujesz się do tych wskazówek, niektóre treści główne mogą zostaną usunięte lub staną się mniej widoczne dla systemu. Wysyłane są 2 podpowiedzi:

.

Użyj tego kodu, aby odczytać odpowiednie wskazówki dotyczące poziomu głównego:

Kotlin

import androidx.media.utils.MediaConstants

// Later, in your MediaBrowserServiceCompat.
override fun onGetRoot(
    clientPackageName: String,
    clientUid: Int,
    rootHints: Bundle
): BrowserRoot {

  val maximumRootChildLimit = rootHints.getInt(
      MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT,
      /* defaultValue= */ 4)
  val supportedRootChildFlags = rootHints.getInt(
      MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS,
      /* defaultValue= */ MediaItem.FLAG_BROWSABLE)

  // Rest of method...
}

Java

import androidx.media.utils.MediaConstants;

// Later, in your MediaBrowserServiceCompat.
@Override
public BrowserRoot onGetRoot(
    String clientPackageName, int clientUid, Bundle rootHints) {

    int maximumRootChildLimit = rootHints.getInt(
        MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT,
        /* defaultValue= */ 4);
    int supportedRootChildFlags = rootHints.getInt(
        MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS,
        /* defaultValue= */ MediaItem.FLAG_BROWSABLE);

    // Rest of method...
}

Możesz zastosować rozgałęzienie logiki w strukturze hierarchii treści opartych na wartościach tych wskazówek, zwłaszcza jeśli Twoja hierarchia różni się Integracje z MediaBrowser poza systemem operacyjnym Android Auto i Androidem Automotive. Jeśli na przykład zwykle wyświetlasz główny element gry, możesz go zagnieździć. ze względu na wartość obsługiwanych flag wskazówkę.

Oprócz podstawowych wskazówek warto stosować się do kilku dodatkowych wskazówek aby zapewnić optymalne renderowanie kart:

  • Dla każdego elementu karty dodaj monochromatyczne, najlepiej białe ikony.
  • Każdy element na karcie powinien mieć krótkie, ale przydatne etykiety. Krótkie etykiety zmniejsza ryzyko obcięcia ciągu.

Wyświetl grafikę multimedialną

Grafika elementów multimedialnych musi być przekazywana jako lokalny identyfikator URI za pomocą jednej z tych metod ContentResolver.SCHEME_CONTENT lub ContentResolver.SCHEME_ANDROID_RESOURCE. Ten lokalny identyfikator URI musi wskazywać format bitmapy lub wektorowy obiekt rysowalny w i zasobach aplikacji. Dla obiektów MediaDescriptionCompat reprezentujących elementy w w hierarchii treści, przekaż identyfikator URI za pomocą setIconUri(). W przypadku obiektów MediaMetadataCompat reprezentujących aktualnie odtwarzany element, przekaż parametr Identyfikator URI do putString(), przy użyciu dowolnego z tych kluczy:

Poniższe kroki opisują, jak pobrać grafikę z internetowego identyfikatora URI i udostępnić za pomocą lokalnego identyfikatora URI. Aby uzyskać pełniejszy przykład, zobacz implementacja openFile() oraz metody otoczenia w Universal Android Music Przykładowa aplikacja odtwarzacza.

  1. Utwórz identyfikator URI content:// odpowiadający identyfikatorowi URI sieci. Przeglądarka multimediów i sesji multimediów, które przekazują ten identyfikator URI treści do Androida Auto, system operacyjny Android Automotive.

    Kotlin

    fun Uri.asAlbumArtContentURI(): Uri {
      return Uri.Builder()
        .scheme(ContentResolver.SCHEME_CONTENT)
        .authority(CONTENT_PROVIDER_AUTHORITY)
        .appendPath(this.getPath()) // Make sure you trust the URI
        .build()
    }
    

    Java

    public static Uri asAlbumArtContentURI(Uri webUri) {
      return new Uri.Builder()
        .scheme(ContentResolver.SCHEME_CONTENT)
        .authority(CONTENT_PROVIDER_AUTHORITY)
        .appendPath(webUri.getPath()) // Make sure you trust the URI!
        .build();
    }
    
  2. W implementacji ContentProvider.openFile() sprawdź, czy plik dla odpowiedniego identyfikatora URI. Jeśli nie, pobierz plik obrazu i zapisz go w pamięci podręcznej. ten fragment kodu używa Glide.

    Kotlin

    override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
      val context = this.context ?: return null
      val file = File(context.cacheDir, uri.path)
      if (!file.exists()) {
        val remoteUri = Uri.Builder()
            .scheme("https")
            .authority("my-image-site")
            .appendPath(uri.path)
            .build()
        val cacheFile = Glide.with(context)
            .asFile()
            .load(remoteUri)
            .submit()
            .get(DOWNLOAD_TIMEOUT_SECONDS, TimeUnit.SECONDS)
    
        cacheFile.renameTo(file)
        file = cacheFile
      }
      return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)
    }
    

    Java

    @Nullable
    @Override
    public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode)
        throws FileNotFoundException {
      Context context = this.getContext();
      File file = new File(context.getCacheDir(), uri.getPath());
      if (!file.exists()) {
        Uri remoteUri = new Uri.Builder()
            .scheme("https")
            .authority("my-image-site")
            .appendPath(uri.getPath())
            .build();
        File cacheFile = Glide.with(context)
            .asFile()
            .load(remoteUri)
            .submit()
            .get(DOWNLOAD_TIMEOUT_SECONDS, TimeUnit.SECONDS);
    
        cacheFile.renameTo(file);
        file = cacheFile;
      }
      return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
    }
    

Szczegółowe informacje o dostawcach treści znajdziesz w sekcji Tworzenie treści Google Cloud Platform.

Zastosuj style treści

Po zbudowaniu hierarchii treści za pomocą elementów, które można przeglądać lub grać, mogą stosować style treści, które określają sposób wyświetlania tych elementów w samochodzie.

Możesz używać tych stylów treści:

Pozycje na liście

Ten styl treści traktuje priorytetowo tytuły i metadane niż obrazy.

Elementy siatki

Ten styl treści traktuje obrazy priorytetowo, a nie tytuły i metadane.

Ustaw domyślne style treści

Możesz ustawić globalne domyślne ustawienia wyświetlania elementów multimedialnych, dodając określone stałe w pakiecie dodatków BrowserRoot Twojej usługi onGetRoot(). . Android Auto i system operacyjny Android Automotive odczytują ten pakiet i szukają aby określić właściwy styl.

W pakiecie jako klucze można użyć tych elementów:

Klucze mogą być mapowane na następujące stałe wartości całkowite, aby wpływać na prezentację tych elementów:

  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM: odpowiednie elementy są wyświetlane jako elementy listy.
  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM: odpowiednie elementy są wyświetlane jako elementy siatki.
  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM: odpowiednie produkty są wyświetlane jako „kategoria” elementów listy. Są to takie same jak zwykłe elementy listy, ale marginesy są nakładane tych elementów bo małe ikony wyglądają lepiej. Ikony muszą być obiektami rysowalnymi wektorowo z możliwością zabarwienia. Ta wskazówka powinna być dostarczana tylko dla elementów, które można przeglądać.
  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM: odpowiednie produkty są wyświetlane jako „kategoria” elementów siatki. Są to takie same jak w zwykłych elementach siatki, z tym że marginesy są nakładane tych elementów bo małe ikony wyglądają lepiej. Ikony muszą być obiektami rysowalnymi wektorowo z możliwością zabarwienia. Ta wskazówka powinna być dostarczana tylko dla elementów, które można przeglądać.

Poniższy fragment kodu pokazuje, jak ustawić domyślny styl treści dla elementów, które można przeglądać, do siatek lub elementów gier, aby utworzyć listy:

Kotlin

import androidx.media.utils.MediaConstants

@Nullable
override fun onGetRoot(
    @NonNull clientPackageName: String,
    clientUid: Int,
    @Nullable rootHints: Bundle
): BrowserRoot {
    val extras = Bundle()
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM)
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM)
    return BrowserRoot(ROOT_ID, extras)
}

Java

import androidx.media.utils.MediaConstants;

@Nullable
@Override
public BrowserRoot onGetRoot(
    @NonNull String clientPackageName,
    int clientUid,
    @Nullable Bundle rootHints) {
    Bundle extras = new Bundle();
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM);
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM);
    return new BrowserRoot(ROOT_ID, extras);
}

Ustawianie stylów treści dla poszczególnych elementów

Interfejs Content Style API umożliwia zastąpienie domyślnego stylu treści elementów multimedialnych możliwych do przeglądania, a także samego elementu multimedialnego.

Aby zastąpić domyślne ustawienia w przypadku elementów podrzędnych elementu multimedialnego, które można przeglądać, utwórz pakietu dodatków w MediaDescription elementu multimedialnego, a następnie dodać tę samą wartość wspomnianych wcześniej wskazówek. DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE dotyczy gier potomnych danego elementu, a DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE ma zastosowanie do: które dzieci mogą oglądać.

Aby zastąpić ustawienia domyślne samego konkretnego elementu multimedialnego, nie jego dzieci, utwórz pakiet dodatków w elemencie MediaDescription elementu multimedialnego i dodaj wskazówkę z kluczem DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM Aby określić sposób prezentacji elementu, użyj tych samych wartości co w poprzednim kroku.

Ten fragment kodu pokazuje, jak utworzyć możliwy do przeglądania element MediaItem, który zastępuje domyślny styl treści zarówno sobie, jak i jego elementów podrzędnych. Styl jako element listy kategorii, jego elementy podrzędne, które można przeglądać, a elementy listy, gry dziecięce jako elementy siatki:

Kotlin

import androidx.media.utils.MediaConstants

private fun createBrowsableMediaItem(
    mediaId: String,
    folderName: String,
    iconUri: Uri
): MediaBrowser.MediaItem {
    val mediaDescriptionBuilder = MediaDescription.Builder()
    mediaDescriptionBuilder.setMediaId(mediaId)
    mediaDescriptionBuilder.setTitle(folderName)
    mediaDescriptionBuilder.setIconUri(iconUri)
    val extras = Bundle()
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM)
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM)
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM)
    mediaDescriptionBuilder.setExtras(extras)
    return MediaBrowser.MediaItem(
        mediaDescriptionBuilder.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE)
}

Java

import androidx.media.utils.MediaConstants;

private MediaBrowser.MediaItem createBrowsableMediaItem(
    String mediaId,
    String folderName,
    Uri iconUri) {
    MediaDescription.Builder mediaDescriptionBuilder = new MediaDescription.Builder();
    mediaDescriptionBuilder.setMediaId(mediaId);
    mediaDescriptionBuilder.setTitle(folderName);
    mediaDescriptionBuilder.setIconUri(iconUri);
    Bundle extras = new Bundle();
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM);
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM);
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM);
    mediaDescriptionBuilder.setExtras(extras);
    return new MediaBrowser.MediaItem(
        mediaDescriptionBuilder.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE);
}

Grupuj produkty za pomocą wskazówek dotyczących tytułów

Aby pogrupować powiązane elementy multimedialne, musisz używać wskazówek dotyczących poszczególnych elementów. Każdy element multimedialny w grupie musi zadeklarować w interfejsie MediaDescription pakiet dodatków, zawiera mapowanie z kluczem DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE. i identyczną wartość ciągu. Zlokalizuj ten ciąg znaków, który jest używany jako nazwę grupy.

Poniższy fragment kodu pokazuje, jak utworzyć MediaItem z podgrupą. nagłówek "Songs":

Kotlin

import androidx.media.utils.MediaConstants

private fun createMediaItem(
    mediaId: String,
    folderName: String,
    iconUri: Uri
): MediaBrowser.MediaItem {
    val mediaDescriptionBuilder = MediaDescription.Builder()
    mediaDescriptionBuilder.setMediaId(mediaId)
    mediaDescriptionBuilder.setTitle(folderName)
    mediaDescriptionBuilder.setIconUri(iconUri)
    val extras = Bundle()
    extras.putString(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE,
        "Songs")
    mediaDescriptionBuilder.setExtras(extras)
    return MediaBrowser.MediaItem(
        mediaDescriptionBuilder.build(), /* playable or browsable flag*/)
}

Java

import androidx.media.utils.MediaConstants;

private MediaBrowser.MediaItem createMediaItem(String mediaId, String folderName, Uri iconUri) {
   MediaDescription.Builder mediaDescriptionBuilder = new MediaDescription.Builder();
   mediaDescriptionBuilder.setMediaId(mediaId);
   mediaDescriptionBuilder.setTitle(folderName);
   mediaDescriptionBuilder.setIconUri(iconUri);
   Bundle extras = new Bundle();
   extras.putString(
       MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE,
       "Songs");
   mediaDescriptionBuilder.setExtras(extras);
   return new MediaBrowser.MediaItem(
       mediaDescriptionBuilder.build(), /* playable or browsable flag*/);
}

Aplikacja musi przekazywać wszystkie elementy multimedialne, które chcesz zgrupować jako sąsiadujące ze sobą bloki. Załóżmy na przykład, że chcesz wyświetlić dwie grupy elementów multimedialnych, „Utwory” i „Albumy”, w tej kolejności, a aplikacja przekazuje pięć elementów multimedialnych w takiej kolejności:

  1. Element multimedialny A o nazwie extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  2. Element multimedialny B z extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
  3. Element multimedialny C z extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  4. Element multimedialny D z: extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  5. Element multimedialny E z: extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")

Ponieważ elementy multimedialne dla utworu „Utwory” grupa i „Albumy” grupa nie jest zachowywana w ciągłych blokach: Androida Auto i systemu operacyjnego Android Automotive. interpretuje to jako 4 następujące grupy:

  • Grupa 1 o nazwie „Utwory” zawierający element multimedialny A
  • Grupa 2 o nazwie „Albumy” zawierający element multimedialny B
  • Grupa 3 o nazwie „Utwory” z elementami multimedialnymi C i D
  • Grupa 4 o nazwie „Albumy” zawierający element multimedialny E

Aby wyświetlić te elementy w 2 grupach, aplikacja musi przekazać te elementy w w tej kolejności:

  1. Element multimedialny A o nazwie extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  2. Element multimedialny C z extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  3. Element multimedialny D z: extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  4. Element multimedialny B z extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
  5. Element multimedialny E z: extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")

Wyświetlanie dodatkowych wskaźników metadanych

Możesz też dołączyć dodatkowe wskaźniki metadanych, aby ułatwić przegląd informacji informacje o treści w drzewie przeglądarki multimedialnej i podczas odtwarzania. W ciągu przeglądaj drzewo, Android Auto i system operacyjny Android Automotive odczytują powiązane z nim dodatki danego elementu i szukać określonych stałych, by określić, które wskaźniki wyświetlacz. Podczas odtwarzania multimediów Android Auto i system operacyjny Android Automotive odczytują metadanych sesji multimedialnej i określić pewne stałe wskaźników do wyświetlenia.

Rysunek 3. Widok odtwarzania z metadanymi identyfikującymi utwór i wykonawcy, a także ikonę wskazującą na treści dla dorosłych.

Rysunek 4. Widok przeglądania z kropką oznaczającą nieodtworzone treści na pierwszy element i pasek postępu w przypadku częściowo odtworzonych treści drugiego elementu.

Tych stałych można używać zarówno w dodatku MediaItem tekstu, jak i Dodatki (MediaMetadata):

Te stałe mogą być używane tylko w MediaItem dodatku tekstu reklamy:

Aby wyświetlać wskaźniki, które pojawiają się, gdy użytkownik przegląda przeglądanie multimediów utwórz pakiet dodatków zawierający co najmniej jedną z tych stałych i przekaż go do metody MediaDescription.Builder.setExtras().

Ten fragment kodu pokazuje, jak wyświetlać wskaźniki dotyczące treści dla dorosłych element ukończony w 70%:

Kotlin

import androidx.media.utils.MediaConstants

val extras = Bundle()
extras.putLong(
    MediaConstants.METADATA_KEY_IS_EXPLICIT,
    MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT)
extras.putInt(
    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS,
    MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED)
extras.putDouble(
    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.7)
val description =
    MediaDescriptionCompat.Builder()
        .setMediaId(/*...*/)
        .setTitle(resources.getString(/*...*/))
        .setExtras(extras)
        .build()
return MediaBrowserCompat.MediaItem(description, /* flags */)

Java

import androidx.media.utils.MediaConstants;

Bundle extras = new Bundle();
extras.putLong(
    MediaConstants.METADATA_KEY_IS_EXPLICIT,
    MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT);
extras.putInt(
    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS,
    MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED);
extras.putDouble(
    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.7);
MediaDescriptionCompat description =
    new MediaDescriptionCompat.Builder()
        .setMediaId(/*...*/)
        .setTitle(resources.getString(/*...*/))
        .setExtras(extras)
        .build();
return new MediaBrowserCompat.MediaItem(description, /* flags */);

Aby wyświetlić wskaźniki aktualnie odtwarzanego elementu multimedialnego, możesz: zadeklaruj wartości Long dla METADATA_KEY_IS_EXPLICIT lub EXTRA_DOWNLOAD_STATUS w MediaMetadataCompat na mediaSession. Nie można wyświetlić DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS lub Wskaźniki DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE w widoku odtwarzania.

Poniższy fragment kodu pokazuje, jak wskazać, że bieżący utwór w że widok odtwarzania zawiera treści dla pełnoletnich i pobrane:

Kotlin

import androidx.media.utils.MediaConstants

mediaSession.setMetadata(
    MediaMetadataCompat.Builder()
        .putString(
            MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, "Song Name")
        .putString(
            MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Artist name")
        .putString(
            MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI,
            albumArtUri.toString())
        .putLong(
            MediaConstants.METADATA_KEY_IS_EXPLICIT,
            MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT)
        .putLong(
            MediaDescriptionCompat.EXTRA_DOWNLOAD_STATUS,
            MediaDescriptionCompat.STATUS_DOWNLOADED)
        .build())

Java

import androidx.media.utils.MediaConstants;

mediaSession.setMetadata(
    new MediaMetadataCompat.Builder()
        .putString(
            MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, "Song Name")
        .putString(
            MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Artist name")
        .putString(
            MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI,
            albumArtUri.toString())
        .putLong(
            MediaConstants.METADATA_KEY_IS_EXPLICIT,
            MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT)
        .putLong(
            MediaDescriptionCompat.EXTRA_DOWNLOAD_STATUS,
            MediaDescriptionCompat.STATUS_DOWNLOADED)
        .build());

Aktualizuj pasek postępu w widoku przeglądania podczas odtwarzania treści

Jak już wspomnieliśmy, możesz korzystać z DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE aby wyświetlić pasek postępu w przypadku częściowo odtworzonej treści, widoku przeglądania. Jeśli użytkownik będzie nadal odtwarzać częściowo odtwarzane treści, z systemu operacyjnego Android Auto lub Android Automotive, ten wskaźnik zmieni się niedokładne.

Na Androida Auto i Androida Automotive aby aktualizować pasek postępu, możesz uzupełnić informacje w MediaMetadataCompat i PlaybackStateCompat, aby połączyć bieżące treści elementów multimedialnych w widoku przeglądania. W przypadku: element multimedialny, aby miał automatycznie aktualizowany pasek postępu:

Fragment kodu poniżej pokazuje, jak wskazać, że aktualnie odtwarzany element jest powiązany z elementem w widoku przeglądania:

Kotlin

import androidx.media.utils.MediaConstants

// When the MediaItem is constructed to show in the browse view.
// Suppose the item was 25% complete when the user launched the browse view.
val mediaItemExtras = Bundle()
mediaItemExtras.putDouble(
    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.25)
val description =
    MediaDescriptionCompat.Builder()
        .setMediaId("my-media-id")
        .setExtras(mediaItemExtras)
        // ...and any other setters.
        .build()
return MediaBrowserCompat.MediaItem(description, /* flags */)

// Elsewhere, when the user has selected MediaItem for playback.
mediaSession.setMetadata(
    MediaMetadataCompat.Builder()
        .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, "my-media-id")
        // ...and any other setters.
        .build())

val playbackStateExtras = Bundle()
playbackStateExtras.putString(
    MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID, "my-media-id")
mediaSession.setPlaybackState(
    PlaybackStateCompat.Builder()
        .setExtras(playbackStateExtras)
        // ...and any other setters.
        .build())

Java

import androidx.media.utils.MediaConstants;

// When the MediaItem is constructed to show in the browse view.
// Suppose the item was 25% complete when the user launched the browse view.
Bundle mediaItemExtras = new Bundle();
mediaItemExtras.putDouble(
    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.25);
MediaDescriptionCompat description =
    new MediaDescriptionCompat.Builder()
        .setMediaId("my-media-id")
        .setExtras(mediaItemExtras)
        // ...and any other setters.
        .build();
return MediaBrowserCompat.MediaItem(description, /* flags */);

// Elsewhere, when the user has selected MediaItem for playback.
mediaSession.setMetadata(
    new MediaMetadataCompat.Builder()
        .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, "my-media-id")
        // ...and any other setters.
        .build());

Bundle playbackStateExtras = new Bundle();
playbackStateExtras.putString(
    MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID, "my-media-id");
mediaSession.setPlaybackState(
    new PlaybackStateCompat.Builder()
        .setExtras(playbackStateExtras)
        // ...and any other setters.
        .build());

Rysunek 5. Widok odtwarzania z opcją „Wyniki wyszukiwania” dla: wyświetlanie elementów multimedialnych związanych z wyszukiwaniem głosowym użytkownika.

Aplikacja może oferować kontekstowe wyniki wyszukiwania wyświetlane użytkownikom, inicjują zapytanie. Pokaz Androida Auto i Androida Automotive za pomocą interfejsów zapytań lub afordancji, które przestawiają w przypadku zapytań wysłanych wcześniej w tej sesji. Aby dowiedzieć się więcej, przeczytaj Sekcja Obsługa komend głosowych w tym przewodniku.

Aby wyświetlić możliwe do przeglądania wyniki wyszukiwania, dołącz klawisz stały BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED w pakiecie dodatkowych usług onGetRoot() z mapowaniem na wartość logiczną true.

Ten fragment kodu pokazuje, jak włączyć obsługę w onGetRoot() :

Kotlin

import androidx.media.utils.MediaConstants

@Nullable
fun onGetRoot(
    @NonNull clientPackageName: String,
    clientUid: Int,
    @Nullable rootHints: Bundle
): BrowserRoot {
    val extras = Bundle()
    extras.putBoolean(
        MediaConstants.BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED, true)
    return BrowserRoot(ROOT_ID, extras)
}

Java

import androidx.media.utils.MediaConstants;

@Nullable
@Override
public BrowserRoot onGetRoot(
    @NonNull String clientPackageName,
    int clientUid,
    @Nullable Bundle rootHints) {
    Bundle extras = new Bundle();
    extras.putBoolean(
        MediaConstants.BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED, true);
    return new BrowserRoot(ROOT_ID, extras);
}

Aby zacząć podawać wyniki wyszukiwania, zastąp onSearch() w usłudze przeglądarki multimediów. Systemy operacyjne Android Auto i Android Automotive Przekieruj do tej metody hasła wyszukiwane przez użytkownika za każdym razem, gdy użytkownik wywoła wyszukiwanie interfejsu zapytań i afordancji „Wyniki wyszukiwania”.

Możesz uporządkować wyszukiwanie wyników z metody onSearch() Twojej usługi przy użyciu elementów tytułów aby użytkownicy mogli je przeglądać. Jeśli na przykład aplikacja odtwarza muzykę, możesz Porządkuj wyniki wyszukiwania według albumu, wykonawcy i utworu.

Ten fragment kodu pokazuje prostą implementację atrybutu onSearch() :

Kotlin

fun onSearch(query: String, extras: Bundle) {
  // Detach from results to unblock the caller (if a search is expensive).
  result.detach()
  object:AsyncTask() {
    internal var searchResponse:ArrayList
    internal var succeeded = false
    protected fun doInBackground(vararg params:Void):Void {
      searchResponse = ArrayList()
      if (doSearch(query, extras, searchResponse))
      {
        succeeded = true
      }
      return null
    }
    protected fun onPostExecute(param:Void) {
      if (succeeded)
      {
        // Sending an empty List informs the caller that there were no results.
        result.sendResult(searchResponse)
      }
      else
      {
        // This invokes onError() on the search callback.
        result.sendResult(null)
      }
      return null
    }
  }.execute()
}
// Populates resultsToFill with search results. Returns true on success or false on error.
private fun doSearch(
    query: String,
    extras: Bundle,
    resultsToFill: ArrayList
): Boolean {
  // Implement this method.
}

Java

@Override
public void onSearch(final String query, final Bundle extras,
                        Result<List<MediaItem>> result) {

  // Detach from results to unblock the caller (if a search is expensive).
  result.detach();

  new AsyncTask<Void, Void, Void>() {
    List<MediaItem> searchResponse;
    boolean succeeded = false;
    @Override
    protected Void doInBackground(Void... params) {
      searchResponse = new ArrayList<MediaItem>();
      if (doSearch(query, extras, searchResponse)) {
        succeeded = true;
      }
      return null;
    }

    @Override
    protected void onPostExecute(Void param) {
      if (succeeded) {
       // Sending an empty List informs the caller that there were no results.
       result.sendResult(searchResponse);
      } else {
        // This invokes onError() on the search callback.
        result.sendResult(null);
      }
    }
  }.execute()
}

/** Populates resultsToFill with search results. Returns true on success or false on error. */
private boolean doSearch(String query, Bundle extras, ArrayList<MediaItem> resultsToFill) {
    // Implement this method.
}

Niestandardowe działania przeglądania

Pojedyncze niestandardowe działanie przeglądania.

Rysunek 6. Pojedyncze niestandardowe działanie przeglądania

Niestandardowe działania przeglądania umożliwiają dodawanie niestandardowych ikon i etykiet do MediaItem obiektów w aplikacji do multimediów w samochodzie i obsługa interakcji użytkownika z tych działań. W ten sposób można rozszerzyć funkcje na różne sposoby, np. za pomocą funkcji „Pobierz”, „Dodaj do kolejki”, „Włącz radio” „Ulubione” lub „Usuń” .

Rozszerzone menu niestandardowych działań przeglądania.

Rysunek 7. Rozszerzone menu czynności przeglądania

Jeśli jest więcej działań niestandardowych niż pozwala na to producent OEM, użytkownik zobaczy rozszerzone menu.

Jak to działa?

Każde niestandardowe działanie przeglądania jest zdefiniowane za pomocą:

  • identyfikator działania (unikalny identyfikator w postaci ciągu znaków),
  • Etykieta działania (tekst wyświetlany użytkownikowi)
  • Identyfikator URI ikony działania (element rysowalny wektorowo, który można zabarwić)

Listę niestandardowych działań przeglądania definiujecie globalnie jako część BrowseRoot Następnie możesz dołączyć podzbiór tych działań do poszczególnych kont MediaItem.

Gdy użytkownik wejdzie w interakcję z niestandardowym działaniem przeglądania, aplikacja otrzyma wywołanie zwrotne w usłudze onCustomAction(). Możesz wykonać to działanie i zaktualizować listę w razie potrzeby – a w razie potrzeby – dla komponentu MediaItem. Jest to przydatne w przypadku działań stanowych np. „Ulubione” i „Pobierz”. W przypadku działań, które nie wymagają aktualizacji, np. „Odtwarzanie” Radio”, nie musisz aktualizować listy działań.

Niestandardowe działania przeglądania w katalogu głównym węzła przeglądania.

Rysunek 8. Pasek narzędzi niestandardowych działań przeglądania

Niestandardowe działania przeglądania możesz też dołączyć do katalogu głównego węzła przeglądania. Te działania wyświetla się na dodatkowym pasku narzędzi pod głównym paskiem narzędzi.

Jak zaimplementować niestandardowe działania przeglądania

Aby dodać do projektu niestandardowe działania przeglądania:

  1. Zastąp dwie metody w tagu MediaBrowserServiceCompat implementacja:
  2. Przeanalizuj limity działań w czasie działania:
  3. Utwórz globalną listę niestandardowych działań przeglądania:
    • Dla każdej czynności utwórz obiekt Bundle z tymi kluczami: * EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID: identyfikator działania * EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL: etykieta działania * EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI: identyfikator URI ikony działania * Dodaj do listy wszystkie obiekty Bundle działania.
  4. Dodaj listę globalną do BrowseRoot:
  5. Dodaj działania do obiektów MediaItem:
    • Możesz dodawać działania do poszczególnych obiektów MediaItem, umieszczając w nich element lista identyfikatorów działań w dodatkach MediaDescriptionCompat korzystających z klucza DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST. Ta lista musi być podzbiorem globalnej listy działań zdefiniowanej przez Ciebie BrowseRoot.
  6. Wykonuj działania i zwracaj postępy lub wyniki:

Aby rozpocząć, możesz wprowadzić te zmiany w: BrowserServiceCompat za pomocą niestandardowych działań przeglądania.

Zastąp BrowserServiceCompat

Musisz zastąpić poniższe metody w MediaBrowserServiceCompat.

public void onLoadItem(String itemId, @NonNull Result<MediaBrowserCompat.MediaItem> result)

public void onCustomAction(@NonNull String action, Bundle extras, @NonNull Result<Bundle> result)

Limit działań analizy

Sprawdź, ile niestandardowych działań przeglądania jest obsługiwanych.

public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, Bundle rootHints) {
    rootHints.getInt(
            MediaConstants.BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT, 0)
}

Tworzenie niestandardowego działania przeglądania

Każde działanie musi zostać umieszczone w osobnym pliku Bundle.

  • Identyfikator działania
    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID,
                    "<ACTION_ID>")
    
  • Etykieta działania
    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL,
                    "<ACTION_LABEL>")
    
  • Identyfikator URI ikony działania
    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI,
                    "<ACTION_ICON_URI>")
    

Dodaj niestandardowe działania przeglądania do kampanii Parceable ArrayList

Dodaj wszystkie obiekty Bundle niestandardowej czynności przeglądania do elementu ArrayList.

private ArrayList<Bundle> createCustomActionsList(
                                        CustomBrowseAction browseActions) {
    ArrayList<Bundle> browseActionsBundle = new ArrayList<>();
    for (CustomBrowseAction browseAction : browseActions) {
        Bundle action = new Bundle();
        action.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID,
                browseAction.mId);
        action.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL,
                getString(browseAction.mLabelResId));
        action.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI,
                browseAction.mIcon);
        browseActionsBundle.add(action);
    }
    return browseActionsBundle;
}

Dodaj listę niestandardowych działań przeglądania do katalogu głównego przeglądania

public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid,
                             Bundle rootHints) {
    Bundle browserRootExtras = new Bundle();
    browserRootExtras.putParcelableArrayList(
            BROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST,
            createCustomActionsList()));
    mRoot = new BrowserRoot(ROOT_ID, browserRootExtras);
    return mRoot;
}

Dodaj działania do: MediaItem

MediaDescriptionCompat buildDescription (long id, String title, String subtitle,
                String description, Uri iconUri, Uri mediaUri,
                ArrayList<String> browseActionIds) {

    MediaDescriptionCompat.Builder bob = new MediaDescriptionCompat.Builder();
    bob.setMediaId(id);
    bob.setTitle(title);
    bob.setSubtitle(subtitle);
    bob.setDescription(description);
    bob.setIconUri(iconUri);
    bob.setMediaUri(mediaUri);

    Bundle extras = new Bundle();
    extras.putStringArrayList(
          DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST,
          browseActionIds);

    bob.setExtras(extras);
    return bob.build();
}
MediaItem mediaItem = new MediaItem(buildDescription(...), flags);

Kompilacja onCustomAction wyniku

  • Analizuj identyfikator mediów z pola Bundle extras:
    @Override
    public void onCustomAction(
              @NonNull String action, Bundle extras, @NonNull Result<Bundle> result){
      String mediaId = extras.getString(MediaConstans.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID);
    }
    
  • W przypadku wyników asynchronicznych odłącz wynik. result.detach()
  • Pakiet wyników kompilacji
    • Wiadomość dla użytkownika
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE,
                mContext.getString(stringRes))
      
    • Aktualizuj element(służy do aktualizowania działań w elemencie)
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM, mediaId);
      
    • Otwórz widok odtwarzania
      //Shows user the PBV without changing the playback state
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_SHOW_PLAYING_ITEM, null);
      
    • Aktualizowanie węzła przeglądania
      //Change current browse node to mediaId
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE, mediaId);
      
  • Jeśli wystąpi błąd, zadzwoń pod numer result.sendError(resultBundle).
  • W przypadku aktualizacji postępu zadzwoń pod numer result.sendProgressUpdate(resultBundle).
  • Dokończ, dzwoniąc pod numer result.sendResult(resultBundle).

Aktualizowanie stanu działania

Używając metody result.sendProgressUpdate(resultBundle) z parametrem EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM. możesz zaktualizować klucz MediaItem, aby odzwierciedlić nowy stan działania. Ten pozwalają przekazywać użytkownikom informacje o postępach w czasie rzeczywistym w wyniku ich działań.

Przykład: pobieranie

Oto przykład, w jaki sposób można użyć tej funkcji do implementacji działania pobierania z 3 stanami:

  1. Pobierz: to jest początkowy stan działania. Gdy użytkownik wybierze to działanie, możesz zamienić je na „Pobieranie” i zadzwoń sendProgressUpdate, aby zaktualizować interfejs użytkownika.
  2. Pobieranie: ten stan oznacza, że trwa pobieranie. Dostępne opcje użyj tego stanu, aby wyświetlić pasek postępu lub inny wskaźnik.
  3. Pobrano: ten stan oznacza, że pobieranie zostało zakończone. Gdy Gdy zakończy się pobieranie, możesz zmienić „Pobieranie” opcja „Pobrane”; i zadzwoń sendResult z EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM. w celu wskazania, że element powinien zostać odświeżony. Dodatkowo możesz użyć EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE aby wyświetlić użytkownikowi komunikat o powodzeniu.

Dzięki temu możesz przekazać użytkownikowi jasne informacje na temat pobieranego pliku. a jego obecny stan. Możesz dodać więcej szczegółów za pomocą ikon, które będą wyświetlane 25%, 50%, 75% stanu pobierania.

Przykład: ulubione akcje

Innym przykładem jest ulubione działanie z dwoma stanami:

  1. Ulubione: to działanie jest wyświetlane przy elementach, które nie znajdują się w na liście ulubionych użytkowników. Gdy użytkownik wybierze to działanie, możesz je zamienić z „dodane do ulubionych” i zadzwoń do: sendResult, używając EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM. do aktualizacji interfejsu użytkownika.
  2. Dodano do ulubionych: to działanie jest wyświetlane w przypadku elementów, które znajdują się w folderze listę ulubionych. Gdy użytkownik wybierze to działanie, możesz je zamienić na „Ulubione” i zadzwoń do: sendResult, używając EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM. do aktualizacji interfejsu użytkownika.

Takie podejście zapewnia użytkownikom jasny i spójny sposób zarządzania ulubionych elementów.

Te przykłady pokazują elastyczność niestandardowych działań przeglądania oraz pokazują, jak które pozwalają wdrożyć różne funkcje i uzyskiwać informacje zwrotne w czasie rzeczywistym dla: i zwiększyć wygodę użytkowników w aplikacji do multimediów w samochodzie.

Pełną, przykładową implementację tej funkcji znajdziesz w TestMediaApp. w projekcie.

Włącz sterowanie odtwarzaniem

Android Auto i Android Automotive OS wysyłają polecenia sterowania odtwarzaniem za pomocą MediaSessionCompat Twojej usługi. Musisz zarejestrować sesję i zaimplementować powiązane z nią metody wywołania zwrotnego.

.

Rejestrowanie sesji multimediów

W usłudze onCreate() usługi przeglądarki multimediów utwórz MediaSessionCompat, zarejestruj sesję multimediów, wywołując setSessionToken().

Ten fragment kodu pokazuje, jak utworzyć i zarejestrować sesję multimediów:

Kotlin

override fun onCreate() {
    super.onCreate()
    ...
    // Start a new MediaSession.
    val session = MediaSessionCompat(this, "session tag").apply {
        // Set a callback object that implements MediaSession.Callback
        // to handle play control requests.
        setCallback(MyMediaSessionCallback())
    }
    sessionToken = session.sessionToken
    ...
}

Java

public void onCreate() {
    super.onCreate();
    ...
    // Start a new MediaSession.
    MediaSessionCompat session = new MediaSessionCompat(this, "session tag");
    setSessionToken(session.getSessionToken());

    // Set a callback object that implements MediaSession.Callback
    // to handle play control requests.
    session.setCallback(new MyMediaSessionCallback());
    ...
}

Przy tworzeniu obiektu sesji multimediów ustawiasz obiekt wywołania zwrotnego, który jest używany obsługi żądań sterowania odtwarzaniem. Tworzysz ten obiekt wywołania zwrotnego przez zapewnia implementację interfejsu MediaSessionCompat.Callback dla Twojej aplikacji. W następnej sekcji opisujemy, jak wdrożyć ten obiekt.

Wdrażanie poleceń odtwarzania

Gdy użytkownik poprosi o włączenie elementu multimedialnego w aplikacji, Android Automotive System operacyjny i Android Auto używają interfejsu MediaSessionCompat.Callback zajęcia z poziomu MediaSessionCompat w Twojej aplikacji obiekt uzyskany z przeglądarki multimediów w aplikacji. Gdy użytkownik chce sterować odtwarzaniem treści, np. wstrzymać odtwarzanie lub przejść do kolejną ścieżkę, system operacyjny Android Auto i Android Automotive wywołują jedno z wywołań zwrotnych. za pomocą metod obiektu.

Aby obsługiwać odtwarzanie treści, aplikacja musi obejmować rozszerzenie MediaSessionCompat.Callback i zaimplementuj metody obsługiwane przez Twoją aplikację.

Wdróż wszystkie poniższe metody wywołania zwrotnego, które mają sens w przypadku typu treści dostępnych w aplikacji:

onPrepare()
Wywoływana po zmianie źródła multimediów. System operacyjny Android Automotive wywołuje też od razu po uruchomieniu. Aplikacja do multimediów musi zaimplementować tę funkcję .
onPlay()
Wywoływane, gdy użytkownik zdecyduje się na grę bez wybrania konkretnego przedmiotu. Twoje musi odtworzyć domyślną treść lub, jeśli odtwarzanie zostało wstrzymane na onPause(), Twój wznowi odtwarzanie.

Uwaga: aplikacja nie powinna automatycznie rozpoczynać odtwarzania muzyki gdy system operacyjny Android Automotive lub Android Auto połączy się z przeglądarką multimediów. posprzedażna. Więcej informacji można znaleźć w sekcji na temat ustawienie początkowego stanu odtwarzania.

onPlayFromMediaId()
Wywoływane, gdy użytkownik chce odtworzyć określony element. Metoda jest przekazywana identyfikator przypisany przez usługę przeglądarki multimediów z elementem multimedialnym w hierarchii treści.
onPlayFromSearch()
Wywoływane, gdy użytkownik chce odtworzyć film z poziomu zapytania. Aplikacja musi: dokonać odpowiedniego wyboru na podstawie przekazanego ciągu wyszukiwania.
onPause()
Wywoływane, gdy użytkownik wstrzymuje odtwarzanie.
onSkipToNext()
Wywoływane, gdy użytkownik przejdzie do następnego elementu.
onSkipToPrevious()
Wywoływane, gdy użytkownik zdecyduje się przejść do poprzedniego elementu.
onStop()
Wywoływane, gdy użytkownik zatrzymuje odtwarzanie.

Zastąp te metody w aplikacji, aby udostępnić wymagane funkcje. Ty nie muszą implementować metody, jeśli jej funkcjonalność nie jest obsługiwana przez aplikację. Dla: np. jeśli aplikacja prowadzi transmisję na żywo (np. transmisję sportową), nie muszą implementować metody onSkipToNext(). Możesz użyć domyślnego implementacji interfejsu onSkipToNext().

Aplikacja nie wymaga żadnych specjalnych mechanizmów logicznych do odtwarzania treści głośników. Gdy aplikacja otrzyma prośbę o włączenie treści, może odtworzyć dźwięk. w taki sam sposób, w jaki odtwarza treści z głośników telefonu lub słuchawek dousznych. Systemy operacyjne Android Auto i Android Automotive będzie automatycznie wysyłać treści audio do systemu samochodowego, aby odtwarzać je na na głośnikach samochodu.

Więcej informacji o odtwarzaniu materiałów audio znajdziesz w artykule MediaPlayer – omówienie, Omówienie aplikacji audio, oraz omówieniu odtwarzacza ExoPlayer.

Ustawianie standardowych działań dotyczących odtwarzania

Android Auto i system operacyjny Android Automotive wyświetlają elementy sterujące odtwarzaniem na podstawie działania włączone w PlaybackStateCompat obiektu.

Domyślnie aplikacja musi obsługiwać te działania:

Aplikacja może dodatkowo obsługiwać te działania, jeśli dotyczą zawartość aplikacji:

Dodatkowo możesz utworzyć kolejkę odtwarzania, która będzie wyświetlana użytkownika, ale nie jest to wymagane. Aby to zrobić, wywołaj metodę setQueue() i setQueueTitle() włącz ACTION_SKIP_TO_QUEUE_ITEM i zdefiniuj wywołanie zwrotne onSkipToQueueItem().

Dodaliśmy też obsługę ikony Co jest grane, która wskazuje, aktualnie odtwarzane. Aby to zrobić, wywołaj metodę setActiveQueueItemId() i przekazuje identyfikator aktualnie odtwarzanego elementu w kolejce. Czynności, które musisz wykonać aktualizuj aplikację setActiveQueueItemId() za każdym razem, gdy zmienia się kolejka.

Przyciski wyświetlane w systemie operacyjnym Android Auto i Android Automotive w przypadku każdego włączonego działania oraz kolejki odtwarzania. Gdy przyciski są zostanie kliknięty, system wywoła odpowiednie wywołanie zwrotne MediaSessionCompat.Callback

Zarezerwuj niewykorzystane miejsce

Android Auto i Android Automotive OS rezerwują miejsce w interfejsie na Działania: ACTION_SKIP_TO_PREVIOUS i ACTION_SKIP_TO_NEXT. Jeśli Twoja aplikacja nie obsługują żadnej z tych funkcji, używają Androida Auto i Androida Automotive w którym będą wyświetlane tworzone przez Ciebie działania niestandardowe.

Jeśli nie chcesz wypełniać tych miejsc działaniami niestandardowymi, możesz zarezerwować aby Android Auto i Android Automotive OS pozostawiły puste miejsce gdy aplikacja nie obsługuje odpowiedniej funkcji. W tym celu wywołaj setExtras() z pakietem dodatków zawierającym stałe odpowiadające argumentowi zarezerwowane funkcje. SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT odpowiada ACTION_SKIP_TO_NEXT, a SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV odpowiada ACTION_SKIP_TO_PREVIOUS. Użyj tych stałych jako kluczy pakietu i jako wartości logicznej używać true.

Ustaw początkowy stan odtwarzania

Gdy Android Auto i system operacyjny Android Automotive komunikują się z przeglądarką multimediów , sesja multimediów przekazuje stan odtwarzania treści za pomocą PlaybackStateCompat. Aplikacja nie powinna automatycznie rozpoczynać odtwarzania muzyki, gdy system operacyjny Android Automotive lub Android Auto i połącz się z przeglądarką multimediów. Zamiast tego zdaj się na Androida Auto i system operacyjny Android Automotive, aby wznowić lub rozpocząć odtwarzanie na podstawie czy działania użytkownika.

Aby to zrobić, ustaw początkowy PlaybackStateCompat Twojej sesji multimedialnej, STATE_STOPPED, STATE_PAUSED, STATE_NONE lub STATE_ERROR.

Sesje multimedialne w Androidzie Auto i systemie operacyjnym Android Automotive trwają tylko przez cały czas jego trwania, więc użytkownicy często rozpoczynają i zatrzymują te sesje. Do ułatwiają płynne przechodzenie między przejazdami i śledzenie poprzednich stanu sesji. Gdy aplikacja do multimediów otrzyma użytkownik może automatycznie wznowić pracę od miejsca, w którym ją przerwał wyłączony – na przykład ostatnio odtwarzany element multimedialny, PlaybackStateCompat, i kolejka.

Dodawanie niestandardowych działań związanych z odtwarzaniem

Możesz dodać niestandardowe działania związane z odtwarzaniem, aby wyświetlić dodatkowe działania wykonywane przez obsługiwane przez aplikację do multimediów. Jeśli pozwala na to miejsce (i nie jest zarezerwowane), Android dodaje komponent niestandardowe działania do elementów sterujących transportem. W przeciwnym razie działania niestandardowe wyświetlić w rozszerzonym menu. Działania niestandardowe są wyświetlane w kolejności, w jakiej są wyświetlane zostaną dodane do PlaybackStateCompat.

Użyj działań niestandardowych, by zapewnić zachowanie inne niż standardowe działań. Nie zastępuj ani nie powielaj treści standardowych .

Działania niestandardowe możesz dodawać za pomocą interfejsu addCustomAction() w PlaybackStateCompat.Builder zajęcia.

Fragment kodu poniżej pokazuje, jak dodać niestandardowy element „Uruchom kanał radiowy” działanie:

Kotlin

stateBuilder.addCustomAction(
    PlaybackStateCompat.CustomAction.Builder(
        CUSTOM_ACTION_START_RADIO_FROM_MEDIA,
        resources.getString(R.string.start_radio_from_media),
        startRadioFromMediaIcon
    ).run {
        setExtras(customActionExtras)
        build()
    }
)

Java

stateBuilder.addCustomAction(
    new PlaybackStateCompat.CustomAction.Builder(
        CUSTOM_ACTION_START_RADIO_FROM_MEDIA,
        resources.getString(R.string.start_radio_from_media),
        startRadioFromMediaIcon)
    .setExtras(customActionExtras)
    .build());

Bardziej szczegółowy przykład tej metody znajdziesz tutaj: setCustomAction() w przykładowej aplikacji Universal Android Music Player na GitHubie.

Po utworzeniu działania niestandardowego sesja multimediów może na nie reagować zastępując onCustomAction() .

Ten fragment kodu pokazuje, jak aplikacja może reagować na Działanie „Uruchom kanał radiowy”:

Kotlin

override fun onCustomAction(action: String, extras: Bundle?) {
    when(action) {
        CUSTOM_ACTION_START_RADIO_FROM_MEDIA -> {
            ...
        }
    }
}

Java

@Override
public void onCustomAction(@NonNull String action, Bundle extras) {
    if (CUSTOM_ACTION_START_RADIO_FROM_MEDIA.equals(action)) {
        ...
    }
}

Bardziej szczegółowy przykład tej metody znajdziesz tutaj: onCustomAction w przykładowej aplikacji Universal Android Music Player na GitHubie.

Ikony działań niestandardowych

Każde działanie niestandardowe, które tworzysz, wymaga zasobu ikony. Aplikacje w samochodach mogą działają na ekranach o różnych rozmiarach i gęstości, dlatego ikony muszą być obiektami rysowalnymi wektorowo. O obiekt rysowalny wektorowo umożliwia skalowanie zasobów bez utraty szczegółów. Wektor rysowalność ułatwia wyrównywanie krawędzi i rogów z granicami pikseli i mniejszej rozdzielczości.

Jeśli działanie niestandardowe jest stanowe – na przykład powoduje włączenie ustawienia odtwarzania lub wyłączone—udostępnianie różnych ikon dla różnych stanów, zobaczy zmianę, gdy wybierze działanie.

Dodaj alternatywne style ikon dla wyłączonych działań

Jeśli działanie niestandardowe jest niedostępne w bieżącym kontekście, zastąp niestandardową ikonę działania, z ikoną alternatywną, która wskazuje, że działanie jest wyłączona.

Rysunek 6. Przykłady nieszablonowych ikon działań niestandardowych.

Wskaż format audio

Aby wskazać, że aktualnie odtwarzane multimedia używają specjalnego formatu dźwięku: możesz określić ikony wyświetlane w samochodach obsługujących tę funkcję. Ty może ustawić KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI oraz KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI w pakiecie dodatków obecnie odtwarzanego elementu multimedialnego (przekazywanego do MediaSession.setMetadata()). Pamiętaj, aby ustawić obie tych dodatków, aby dostosować je do różnych układów.

Możesz także ustawić dodatkowe pole KEY_IMMERSIVE_AUDIO aby poinformować producentów samochodów, że jest to dźwięk absurdalny. Powinni oni być bardzo ostrożni przy podejmowaniu decyzji, czy zastosować efekty dźwiękowe, które mogą zakłócać wciągające treści.

Odtwarzany element multimedialny możesz skonfigurować tak, aby jego podtytuł, opis lub oba są linkami do innych elementów multimedialnych. Dzięki temu użytkownik może szybko przejść podobne produkty; na przykład mogą przeskakiwać do innych utworów tego samego wykonawcy, innych odcinków tego podcastu itd. Jeśli samochód obsługuje tę funkcję, może kliknąć link, aby przejść do tych treści.

Aby dodać linki, skonfiguruj Metadane KEY_SUBTITLE_LINK_MEDIA_ID (aby dodać link z podtytułu) lub KEY_DESCRIPTION_LINK_MEDIA_ID (aby linkować z opis). Szczegółowe informacje znajdziesz w dokumentacji tych metadanych.

Obsługa komend głosowych

Aplikacja do multimediów musi obsługiwać komendy głosowe, aby kierowcy mogli i wygodę, która minimalizuje rozpraszanie uwagi. Jeśli na przykład aplikacja odtwarza jeden element multimedialny, użytkownik może powiedzieć „Włącz [tytuł utworu]” i poprosi o włączenie innego utworu bez dotykania wyświetlacz. Użytkownicy mogą inicjować zapytania, klikając odpowiednie przyciski na kierownicą lub słowami-kluczami „OK Google”.

.

Gdy Android Auto lub system operacyjny Android Automotive wykryje i zinterpretuje głos, komenda głosowa jest przesyłana do aplikacji przez onPlayFromSearch() Po otrzymaniu tego wywołania zwrotnego aplikacja znajduje treści pasujące do: query i rozpocznie odtwarzanie.

Użytkownicy mogą w zapytaniu określić różne kategorie haseł: gatunek, wykonawca, album, tytuł utworu, stację radiową lub playlistę. Podczas tworzenia obsługi wyszukiwania, uwzględnij wszystkie kategorie, które mają sens w przypadku Twojej aplikacji. Jeśli Android Auto lub system operacyjny Android Automotive wykryje, że dane zapytanie pasuje do dla określonych kategorii, dodaje dodatki w parametrze extras. możemy wysłać następujące dodatkowe materiały:

Konto zawiera pusty ciąg tekstowy query, który może zostać wysłany przez Android Auto lub system operacyjny Android Automotive, jeśli użytkownik nie określi zapytania. Na przykład gdy użytkownik powie „Włącz jakąś muzykę”. W takim przypadku aplikacja może odtworzyć ostatnio odtwarzany lub niedawno sugerowany utwór.

Jeśli wyszukiwanie nie może zostać szybko przetworzone, nie blokuj go w onPlayFromSearch(). Zamiast tego ustaw stan odtwarzania na STATE_CONNECTING i przeprowadzić wyszukiwanie w wątku asynchronicznym.

Po rozpoczęciu odtwarzania możesz wypełnić kolejkę sesji multimediów powiązane treści. Jeśli na przykład użytkownik poprosi o odtworzenie albumu, aplikacja może zapełnić kolejkę listą utworów z albumu. Warto też rozważyć wdrożenie obsługę wyników wyszukiwania, które użytkownik może przeglądać inną ścieżkę pasującą do zapytania.

Oprócz „play” zapytań, systemu operacyjnego Android Auto i Androida Automotive rozpoznawaj zapytania głosowe, aby sterować odtwarzaniem, np. „wstrzymaj muzykę” i „Dalej utwór" i dopasujesz te polecenia do odpowiednich wywołań zwrotnych sesji multimediów, na przykład onPause() i onSkipToNext().

Szczegółowy przykład implementacji komend głosowych w aplikacji, przeczytaj artykuł na temat aplikacji Asystent Google i aplikacje do multimediów.

Stosuj środki ostrożności, które rozpraszają uwagę

Ponieważ podczas korzystania z Androida telefon użytkownika jest połączony z głośnikami samochodu Automatycznie, musisz podjąć dodatkowe środki ostrożności, aby nie rozpraszać uwagi kierowcy.

Wycisz alarmy w samochodzie

Aplikacje do multimediów na Androida Auto nie mogą odtwarzać dźwięku przez głośniki samochodu chyba że użytkownik rozpocznie odtwarzanie, np. naciskając przycisk odtwarzania. Nie może się uruchamiać nawet alarm zaplanowany przez użytkownika z aplikacji do multimediów odtwarzam muzykę przez głośniki w samochodzie.

Aby spełnić to wymaganie, można użyć: CarConnection jako sygnału przed odtworzeniem jakiegokolwiek dźwięku. Aplikacja może sprawdzić, czy telefon wyświetlając obraz na ekranie w samochodzie, obserwując sygnał LiveData dla połączenia w samochodzie typ i sprawdzam, czy jest równy CONNECTION_TYPE_PROJECTION

Jeśli telefon użytkownika przesyła dźwięk, aplikacje do multimediów, które obsługują alarmy, muszą to robić z następujących elementów:

  • Wyłącz alarm.
  • Odtwórz alarm na STREAM_ALARM i udostępnić na ekranie interfejs do wyłączenia alarmu.

Obsługa reklam medialnych

Domyślnie Android Auto wyświetla powiadomienie o zmianie metadanych multimediów podczas sesji odtwarzania dźwięku. Gdy aplikacja do multimediów przełącza się z odtwarzania muzyki do uruchomienia reklamy może rozpraszać uwagę, powiadomienia. Aby uniemożliwić Androidowi Auto wyświetlanie powiadomień W takim przypadku musisz ustawić klucz metadanych multimediów METADATA_KEY_IS_ADVERTISEMENT do METADATA_VALUE_ATTRIBUTE_PRESENT, Jak widać w tym fragmencie kodu:

Kotlin

import androidx.media.utils.MediaConstants

override fun onPlayFromMediaId(mediaId: String, extras: Bundle?) {
    MediaMetadataCompat.Builder().apply {
        if (isAd(mediaId)) {
            putLong(
                MediaConstants.METADATA_KEY_IS_ADVERTISEMENT,
                MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT)
        }
        // ...add any other properties you normally would.
        mediaSession.setMetadata(build())
    }
}

Java

import androidx.media.utils.MediaConstants;

@Override
public void onPlayFromMediaId(String mediaId, Bundle extras) {
    MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
    if (isAd(mediaId)) {
        builder.putLong(
            MediaConstants.METADATA_KEY_IS_ADVERTISEMENT,
            MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT);
    }
    // ...add any other properties you normally would.
    mediaSession.setMetadata(builder.build());
}

Obsługa błędów ogólnych

Gdy w aplikacji wystąpi błąd, ustaw stan odtwarzania na STATE_ERROR i podaj komunikat o błędzie, korzystając z setErrorMessage() . Zobacz PlaybackStateCompat . Komunikaty o błędach muszą być widoczne dla użytkownika i zlokalizowane zgodnie z język. Android Auto i Android Automotive mogą wyświetlać błąd. wiadomość do użytkownika.

Jeśli na przykład treści nie są dostępne w obecnym regionie użytkownika, możesz skorzystaj z funkcji ERROR_CODE_NOT_AVAILABLE_IN_REGION kod błędu podczas ustawiania komunikatu o błędzie.

Kotlin

mediaSession.setPlaybackState(
    PlaybackStateCompat.Builder()
        .setState(PlaybackStateCompat.STATE_ERROR)
        .setErrorMessage(PlaybackStateCompat.ERROR_CODE_NOT_AVAILABLE_IN_REGION, getString(R.string.error_unsupported_region))
        // ...and any other setters.
        .build())

Java

mediaSession.setPlaybackState(
    new PlaybackStateCompat.Builder()
        .setState(PlaybackStateCompat.STATE_ERROR)
        .setErrorMessage(PlaybackStateCompat.ERROR_CODE_NOT_AVAILABLE_IN_REGION, getString(R.string.error_unsupported_region))
        // ...and any other setters.
        .build());

Więcej informacji o stanach błędu znajdziesz w artykule Korzystanie z sesji multimediów: stany i błędy.

Jeśli użytkownik Androida Auto musi otworzyć aplikację na telefonie, aby rozwiązać problem: podać je użytkownikowi w wiadomości. Na przykład: komunikat może brzmieć „Zaloguj się w [nazwa aplikacji]”. zamiast „Zaloguj się”.

Inne materiały