Android Auto i Android Automotive OS pomagają dostarczać treści z aplikacji multimedialnych użytkownikom w samochodzie. Aplikacja multimedialna do samochodów musi udostępniać usługę przeglądarki multimedialnej, aby Android Auto i system operacyjny Android Automotive lub inna aplikacja z przeglądarką multimedialną mogły wykrywać i wyświetlać Twoje treści.
W tym przewodniku zakładamy, że masz już aplikację multimedialną, która odtwarza dźwięk na telefonie, i że jest ona zgodna z architekturą aplikacji multimedialnych na Androida.
W tym przewodniku opisujemy wymagane komponenty MediaBrowserService
i MediaSession
, których aplikacja potrzebuje do działania w Android Auto lub systemie operacyjnym Android Automotive. Po zakończeniu konfigurowania podstawowej infrastruktury multimediów możesz dodać obsługę Androida Auto i dodać obsługę systemu operacyjnego Android Automotive do swojej aplikacji multimedialnej.
Zanim zaczniesz
- Zapoznaj się z dokumentacją interfejsu API do multimediów na Androida.
- Aby uzyskać wskazówki dotyczące projektowania, zapoznaj się z artykułem Tworzenie aplikacji multimedialnych.
- Zapoznaj się z kluczowymi terminami i koncepcjami wymienionymi w tej sekcji.
Kluczowe terminy i pojęcia
- Usługa przeglądarki multimediów
- Usługa na Androida zaimplementowana przez Twoją aplikację multimedialną, która jest zgodna z interfejsem API
MediaBrowserServiceCompat
. Twoja aplikacja korzysta z tej usługi, aby udostępniać treści. - Przeglądarka multimediów
- Interfejs API używany przez aplikacje multimedialne do znajdowania usług przeglądarek multimedialnych i wyświetlania ich treści. Android Auto i Android Automotive OS używają przeglądarki multimediów do znajdowania usługi przeglądarki multimediów aplikacji.
- Element multimedialny
Przeglądarka multimediów porządkuje treści w drzewie obiektów
MediaItem
. Element multimediów może mieć jedną lub obie z tych flag:FLAG_PLAYABLE
: oznacza, że element jest elementem końcowym w drzewie treści. Element reprezentuje pojedynczy strumień dźwięku, np. utwór na albumie, rozdział w książce audio lub odcinek podcastu.FLAG_BROWSABLE
: oznacza, że element jest węzłem w drzewie treści i ma elementy podrzędne. Na przykład element reprezentuje album, a jego elementy podrzędne to utwory na albumie.
Element multimedialny, który można przeglądać i odtwarzać, działa jak playlista. Możesz wybrać sam element, aby odtworzyć wszystkie jego elementy podrzędne, lub przejrzeć jego elementy podrzędne.
- Optymalizacja pod kątem pojazdu
Aktywność w aplikacji na system operacyjny Android Automotive, która jest zgodna z wytycznymi dotyczącymi projektowania na ten system. Interfejs tych czynności nie jest generowany przez system operacyjny Android Automotive, dlatego musisz zadbać o to, aby Twoja aplikacja była zgodna ze wskazówkami dotyczącymi projektowania. Zazwyczaj obejmuje to większe docelowe elementy dotykowe i rozmiary czcionek, obsługę trybu dziennego i nocnego oraz wyższe współczynniki kontrastu.
Interfejsy zoptymalizowane pod kątem pojazdów mogą być wyświetlane tylko wtedy, gdy ograniczenia dotyczące wrażeń użytkownika w samochodzie (CUXR) nie są aktywne, ponieważ mogą wymagać większej uwagi lub interakcji ze strony użytkownika. CUXRs nie są aktywne, gdy samochód jest zaparkowany lub zatrzymuje się, ale są zawsze aktywne, gdy samochód jest w ruchu.
Nie musisz projektować działań dla Androida Auto, ponieważ Android Auto tworzy własny interfejs zoptymalizowany pod kątem samochodu, korzystając z informacji z Twojej usługi przeglądarki multimedialnej.
Konfigurowanie plików manifestu aplikacji
Zanim utworzysz usługę przeglądarki multimediów, musisz skonfigurować pliki manifestu aplikacji.
Zdefiniuj usługę przeglądarki multimedialnej
Zarówno Android Auto, jak i Android Automotive OS łączą się z Twoją aplikacją przez usługę przeglądarki multimediów, aby przeglądać elementy multimediów. Zadeklaruj usługę przeglądarki multimedialnej w pliku manifestu, aby umożliwić Androidowi Auto i systemowi operacyjnemu Android Automotive jej wykrycie i połączenie z Twoją aplikacją.
Poniższy fragment kodu pokazuje, jak zadeklarować usługę przeglądarki multimediów w pliku manifestu. Uwzględnij ten kod w pliku manifestu modułu systemu operacyjnego Android Automotive i 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ślanie ikon aplikacji
Musisz określić ikony aplikacji, których Android Auto i system operacyjny Android Automotive mogą używać do reprezentowania aplikacji w interfejsie systemu. Wymagane są 2 typy ikon:
- Ikona programu uruchamiającego
- Ikona atrybucji
Ikona programu uruchamiającego
Ikona programu uruchamiającego reprezentuje aplikację w interfejsie systemu, np. w menu z aplikacją i w panelu z ikonami. Możesz określić, że chcesz użyć ikony z aplikacji mobilnej, aby reprezentować aplikację multimedialną w samochodzie, za pomocą tej deklaracji w pliku manifestu:
<application
...
android:icon="@mipmap/ic_launcher"
...
/>
Aby użyć innej ikony niż ikona aplikacji mobilnej, w pliku manifestu ustaw właściwość android:icon
elementu <service>
usługi przeglądarki multimediów:
<application>
...
<service
...
android:icon="@mipmap/auto_launcher"
...
/>
</application>
Ikona atrybucji
Ikona atrybucji jest używana w miejscach, w których treści multimedialne mają pierwszeństwo, takich jak karty multimediów. Rozważ ponowne użycie małej ikony używanej w powiadomieniach. Ikona musi być monochromatyczna. Ikona reprezentująca aplikację może być określona w deklaracji pliku manifestu w ten sposób:
<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 tworzysz, rozszerzając klasę MediaBrowserServiceCompat
. Usługa może być używana przez Androida Auto i Androida Automotive do:
- Przeglądaj hierarchię treści aplikacji, aby wyświetlić użytkownikowi menu.
- Aby sterować odtwarzaniem dźwięku, pobierz token obiektu
MediaSessionCompat
aplikacji.
Możesz też użyć usługi przeglądarki multimediów, aby umożliwić innym klientom dostęp do treści multimedialnych z Twojej aplikacji. Mogą to być inne aplikacje na telefonie użytkownika lub inne zdalne aplikacje.
Przepływ pracy usługi przeglądarki multimedialnej
W tej sekcji opisano, jak Android Automotive OS i Android Auto współpracują z Twoją usługą przeglądarki multimediów podczas typowej procedury użytkownika.
- Użytkownik uruchamia aplikację na systemie operacyjnym Android Automotive lub w aplikacji Android Auto.
- System operacyjny Android Automotive lub Android Auto kontaktuje się z przeglądarką multimediów aplikacji za pomocą metody
onCreate()
. W implementacji metodyonCreate()
musisz utworzyć i zarejestrować obiektMediaSessionCompat
oraz jego obiekt wywołania zwrotnego. - System operacyjny Android Automotive lub Android Auto wywołuje metodę
onGetRoot()
Twojej usługi, aby pobrać element multimedialny wyższego poziomu w hierarchii treści. Element multimedialny wyższego poziomu nie jest wyświetlany. Zamiast tego służy do pobierania dodatkowych treści z aplikacji. - System operacyjny Android Automotive lub Android Auto wywołuje metodę
onLoadChildren()
Twojej usługi, aby uzyskać elementy podrzędne elementu multimedialnego wyższego poziomu. System operacyjny Android Automotive i Android Auto wyświetlają te elementy multimedialne jako najwyższy poziom elementów treści. Więcej informacji o tym, czego system oczekuje na tym poziomie, znajdziesz na stronie Struktura menu głównego. - Jeśli użytkownik wybierze przeglądalny element multimedialny, metoda
onLoadChildren()
Twojej usługi zostanie wywołana ponownie, aby pobrać podrzędne wybranego elementu menu. - Jeśli użytkownik wybierze odtwarzany element multimediów, system operacyjny Android Automotive lub Android Auto wywoła odpowiednią metodę wywołania sesji multimediów, aby wykonać to działanie.
- Jeśli jest to obsługiwane przez Twoją aplikację, użytkownik może też wyszukiwać treści. W tym przypadku system operacyjny Android Automotive lub Android Auto wywołuje metodę
onSearch()
usługi.
Tworzenie hierarchii treści
Android Auto i system operacyjny Android Automotive wywołują usługę przeglądarki multimediów w aplikacji, aby dowiedzieć się, jakie treści są dostępne. Aby obsługiwać tę funkcję, musisz zaimplementować w swojej usłudze przeglądarki multimediów 2 metody: onGetRoot()
i onLoadChildren()
.
Implementacja metody onGetRoot
Metoda onGetRoot()
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 żądać reszty Twoich treści za pomocą metody onLoadChildren()
.
Ten fragment kodu pokazuje prostą implementację metody 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); }
Przykład tej metody znajdziesz w metodzie onGetRoot()
w przykładowej aplikacji Universal Android Music Player na GitHub.
Dodaj weryfikację pakietu dla funkcji onGetRoot()
Gdy użytkownik wyśle Ci wiadomość za pomocą metody onGetRoot()
, pakiet wywołania przekaże Twojej usłudze informacje identyfikacyjne. Usługa może użyć tych informacji, aby zdecydować, czy pakiet może uzyskać dostęp do Twoich treści. Możesz na przykład ograniczyć dostęp do treści aplikacji do listy zatwierdzonych pakietów, porównując clientPackageName
z listą dozwolonych i sprawdzając certyfikat użyty do podpisania pliku APK pakietu. Jeśli nie można zweryfikować pakietu, kliknij null
, aby odmówić dostępu do treści.
Aby zapewnić aplikacjom systemowym, takim jak Android Auto i Android Automotive, dostęp do treści, usługa musi zawsze zwracać wartość niezerową BrowserRoot
, gdy te aplikacje systemowe wywołują metodę onGetRoot()
. Sygnatura aplikacji systemowej Android Automotive może się różnić w zależności od marki i modelu samochodu, dlatego musisz zezwolić na połączenia ze wszystkich aplikacji systemowych, aby zapewnić pełną obsługę systemu operacyjnego Android Automotive.
Ten fragment kodu pokazuje, jak usługa może sprawdzić, czy wywoływany pakiet jest aplikacją systemową:
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 to fragment klasy PackageValidator
z przykładowej aplikacji Universal Android Music Player na GitHub. Więcej informacji o implementowaniu weryfikacji pakietu w metodach onGetRoot()
usługi znajdziesz w tej klasie.
Oprócz zezwalania na aplikacje systemowe musisz też zezwolić Asystentowi Google na połączenie z urządzeniem MediaBrowserService
. Pamiętaj, że Asystent Google ma osobne nazwy pakietów na potrzeby telefonu (w tym Androida Auto) i Androida Automotive.
Implementacja funkcji onLoadChildren()
Po otrzymaniu obiektu wierzchołka systemu Android Auto i Android Automotive OS tworzą menu najwyższego poziomu, wywołując funkcję onLoadChildren()
obiektu wierzchołka, aby uzyskać jego elementy podrzędne. Aplikacje klienckie tworzą menu podrzędne, wywołując tę samą metodę za pomocą obiektów węzłów podrzędnych.
Każdy węzeł w hierarchii treści jest reprezentowany przez obiekt MediaBrowserCompat.MediaItem
. Każdy z tych elementów multimediów jest identyfikowany za pomocą unikalnego ciągu znaków identyfikatora. Aplikacje klienta traktują te ciągi identyfikatorów jako nieprzezroczyste tokeny. Gdy aplikacja klienta chce przejść do podmenu lub odtworzyć element multimedialny, przekazuje token. Twoja aplikacja jest odpowiedzialna za powiązanie tokena z odpowiednim elementem multimedialnym.
Ten fragment kodu pokazuje prostą implementację metody 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 metodzie onLoadChildren()
w przykładowej aplikacji Universal Android Music Player na GitHub.
Struktura menu głównego
Android Auto i Android Automotive OS mają określone ograniczenia dotyczące struktury menu głównego. Są one przekazywane do usługi MediaBrowserService
za pomocą wskazówek dotyczących głównego węzła, które można odczytać za pomocą argumentu Bundle
przekazanego do onGetRoot()
.
Dzięki tym wskazówkom system może optymalnie wyświetlać treści główne jako karty nawigacyjne. Jeśli nie zastosujesz tych wskazówek, niektóre treści z katalogu głównego mogą zostać usunięte lub uczynić je mniej wykrywalnymi przez system. Wysyłane są 2 wskazówki:
- Limit liczby elementów podrzędnych: w większości przypadków jest to 4. Oznacza to, że nie można wyświetlić więcej niż 4 karty.
- Obsługiwane flagi w przypadku podrzędnych elementów poziomu 0: wartość powinna wynosić
MediaItem#FLAG_BROWSABLE
. Oznacza to, że jako karty mogą być wyświetlane tylko przeglądalne elementy, a nie elementy, które można odtworzyć.
Aby odczytać odpowiednie wskazówki dotyczące serwera głównego, użyj tego kodu:
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 wybrać logikę struktury hierarchii treści na podstawie wartości tych wskazówek, zwłaszcza jeśli hierarchia różni się w przypadku integracji MediaBrowser
spoza Androida Auto i Androida Automotive.
Jeśli na przykład zwykle wyświetlasz główny element do grania, możesz go umieścić w elementach do przeglądania z poziomu głównego ze względu na wartość podpowiedzi obsługiwanych flag.
Oprócz wskazówek dotyczących wskazówek dotyczących katalogu głównego należy przestrzegać kilku dodatkowych wskazówek, aby zapewnić optymalne renderowanie kart:
- Do każdego elementu karty dołącz monochromatyczne, najlepiej białe, ikony.
- Dodaj krótkie, ale znaczące etykiety do każdego elementu karty. Krótkie etykiety zmniejszają ryzyko obcięcia ciągów tekstowych.
Wyświetlanie multimediów
Elementy graficzne w przypadku elementów multimedialnych muszą być przekazywane jako identyfikatory URI lokalne za pomocą wartości ContentResolver.SCHEME_CONTENT
lub ContentResolver.SCHEME_ANDROID_RESOURCE
.
Ten lokalny identyfikator URI musi wskazywać bitmapę lub wektor do rysowania w zasobach aplikacji. W przypadku obiektów MediaDescriptionCompat
reprezentujących elementy w hierarchii treści przekaż identyfikator URI za pomocą setIconUri()
.
W przypadku obiektów MediaMetadataCompat
reprezentujących odtwarzany obecnie element prześlij URI za pomocą putString()
, używając dowolnego z tych kluczy:
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI
MediaMetadataCompat.METADATA_KEY_ART_URI
MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI
W podanych niżej krokach opisano, jak pobrać grafikę z identyfikatora URI internetowego i ujawnić ją za pomocą identyfikatora URI lokalnego. Pełniejszy przykład znajdziesz w implementacji funkcji openFile()
i otaczających ją metod w przykładowej aplikacji Universal Android Music Player.
Utwórz identyfikator URI
content://
odpowiadający identyfikatorowi URI witryny. Usługa przeglądarki multimediów i sesja multimediów przekazują ten identyfikator URI treści do Androida Auto i systemu operacyjnego 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(); }
W implementacji
ContentProvider.openFile()
sprawdź, czy istnieje plik dla odpowiedniego identyfikatora URI. Jeśli nie, pobierz plik obrazu i prześlij go do pamięci podręcznej. Ten fragment kodu używa funkcji 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); }
Więcej informacji o dostawcach treści znajdziesz w artykule Tworzenie dostawcy treści.
Zastosuj style treści
Po utworzeniu hierarchii treści za pomocą elementów do przeglądania lub odtwarzania możesz zastosować 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
-
W tym stylu treści priorytetem są tytuły i metadane, a nie obrazy.
- Elementy siatki
-
W tym stylu treści priorytetem są obrazy, a nie tytuły i metadane.
Ustawianie domyślnych stylów treści
Możesz ustawić globalne ustawienia domyślne wyświetlania elementów multimedialnych, dodając określone stałe wartości do pakietu dodatkowych elementów BrowserRoot
metody onGetRoot()
Twojej usługi. Android Auto i system operacyjny Android Automotive odczytują ten pakiet i szukają w nim tych stałych wartości, aby określić odpowiedni styl.
Jako klucze w pakiecie można używać tych dodatków:
DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
: wskazuje podpowiedź dotyczącą wyświetlania wszystkich elementów, które można przeglądać w drzewie nawigacji.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
: wskazuje podpowiedź dotyczącą wszystkich odtwarzalnych elementów w drzewie wyszukiwania.
Klucze mogą być mapowane na te wartości liczb całkowitych, aby wpływać na sposób wyświetlania 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 elementy są wyświetlane jako elementy listy „Kategoria”. Są to te same elementy co zwykłe elementy listy, z tym wyjątkiem, że wokół ikon elementów stosuje się marginesy, ponieważ ikony lepiej wyglądają, gdy są małe. Ikony muszą być obiektami rysowalnymi wektorowo, które można zabarwiać. Ten podpowiedź powinien być udostępniany tylko w przypadku elementów, które można przeglądać.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM
:odpowiadające elementy są wyświetlane jako elementy siatki „Kategoria”. Są to te same elementy siatki co zwykle, z tą różnicą, że wokół ikon elementów są stosowane marginesy, ponieważ ikony wyglądają lepiej, gdy są małe. Ikony muszą być obiektami rysowalnymi wektorowo, które można zabarwiać. Ten podpowiedź powinien być udostępniany tylko w przypadku elementów, które można przeglądać.
Ten fragment kodu pokazuje, jak ustawić domyślny styl treści dla elementów do przeglądania w kratce i elementów do odtwarzania w listach:
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 produktów
Interfejs Content Style API umożliwia zastąpienie domyślnego stylu treści dla podrzędnych elementów dowolnego przeglądalnego elementu multimedialnego, a także samego elementu multimedialnego.
Aby zastąpić domyślne ustawienia elementów podrzędnych przeglądalnego elementu multimedialnego, utwórz pakiet dodatkowych elementów w MediaDescription
elementu multimedialnego i dodaj te same podpowiedzi, o których była mowa wcześniej. DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
ma zastosowanie do podrzędnych elementów do odtwarzania, a DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
– do podrzędnych elementów do przeglądania.
Aby zastąpić domyślne ustawienie konkretnego elementu multimedialnego właściwiego, a nie jego elementów podrzędnych, utwórz pakiet dodatkowych elementów w MediaDescription
elementu multimedialnego i dodaj podpowiedź z kluczem DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM
.
Aby określić sposób wyświetlania tego elementu, użyj tych samych wartości, które zostały opisane wcześniej.
Poniższy fragment kodu pokazuje, jak utworzyć przeglądalny element MediaItem
, który zastępuje domyślny styl treści zarówno dla siebie, jak i dla swoich elementów potomnych. Jest on stylizowany jako element listy kategorii, a jego przeglądalne elementy podrzędne jako elementy listy, a elementy podrzędne do odtworzenia 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); }
Grupowanie elementów za pomocą podpowiedzi dotyczących tytułów
Aby pogrupować powiązane elementy multimedialne, użyj wskazówki dotyczącej poszczególnych elementów. Każdy element multimedialny w grupie musi zadeklarować pakiet dodatkowych treści w sekcji MediaDescription
, która zawiera mapowanie z kluczem DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE
i identyczną wartością ciągu znaków. Zlokalizuj ten ciąg znaków, który jest używany jako tytuł grupy.
Ten fragment kodu pokazuje, jak utworzyć MediaItem
z nagłówkiem podgrupy "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 ciągły blok. Załóżmy na przykład, że chcesz wyświetlić 2 grupy elementów multimedialnych, „Songs” i „Albums”, w tej kolejności, a Twoja aplikacja przekazuje 5 elementów multimedialnych w tej kolejności:
- Element multimedialny A z
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- Element multimedialny B z
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
- Element multimedialny C z
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- Element multimedialny D z
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- Element multimedialny E z
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
Ponieważ elementy multimedialne w grupach „Utwory” i „Albumy” nie są przechowywane razem w ciągłych blokach, Android Auto i system operacyjny Android Automotive interpretują je jako 4 grupy:
- Grupa 1 o nazwie „Utwory” zawierająca element multimedialny A
- Grupa 2 o nazwie „Albumy” zawierająca element multimedialny B
- Grupa 3 o nazwie „Songs” zawierająca elementy multimedialne C i D
- Grupa 4 o nazwie „Albumy” zawierająca element multimedialny E
Aby wyświetlić te elementy w 2 grupach, aplikacja musi przekazywać elementy multimedialne w takim porządku:
- Element multimedialny A z
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- Element multimedialny C z
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- Element multimedialny D z
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- Element multimedialny B z
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
- Element multimedialny E z
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
Wyświetlanie dodatkowych wskaźników metadanych
Możesz dodać dodatkowe wskaźniki metadanych, aby wyświetlać informacje o treściach w drzewie przeglądarki multimediów i podczas odtwarzania. W drzewie przeglądania Android Auto i system operacyjny Android Automotive odczytują dodatkowe informacje powiązane z elementem i szukają określonych stałych, aby określić, które wskaźniki wyświetlić. Podczas odtwarzania multimediów Android Auto i Android Automotive OS odczytują metadane sesji multimediów i szukają określonych stałych wartości, aby określić, jakie wskaźniki mają być wyświetlane.
W obu dodatkowych elementach MediaItem
opisu i MediaMetadata
dodatkowych:
EXTRA_DOWNLOAD_STATUS
: wskazuje stan pobierania elementu. Użyj tej stałej jako klucza. Możliwe wartości to:STATUS_DOWNLOADED
: produkt został całkowicie pobrany.STATUS_DOWNLOADING
: element jest pobierany.STATUS_NOT_DOWNLOADED
: element nie został pobrany.
METADATA_KEY_IS_EXPLICIT
: wskazuje, czy produkt zawiera treści dla dorosłych. Aby wskazać, że element jest jawny, użyj tej stałej jako klucza, a długiej wartościMETADATA_VALUE_ATTRIBUTE_PRESENT
.
W dodatkowych elementach tekstu reklamy MediaItem
można stosować tylko te stałe:
DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS
: wskazuje stan ukończenia długich treści, takich jak odcinki podcastów lub audiobooki. Użyj tej stałej jako klucza. Możliwe wartości to:DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED
: produkt nie został w ogóle odtworzony.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED
: element został częściowo odtworzony, a bieżąca pozycja znajduje się gdzieś pośrodku.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED
: zadanie zostało ukończone.
DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
: wskazuje postęp w oglądaniu długich treści w postaci podwójnej precyzji z zakresu 0,0–1,0. Ta dodatkowa informacja zawiera więcej informacji o staniePARTIALLY_PLAYING
, dzięki czemu Android Auto lub system operacyjny Android Automotive wyświetla bardziej przydatny wskaźnik postępu, np. pasek postępu. Jeśli korzystasz z tego dodatku, zapoznaj się z sekcją Aktualizowanie paska postępu w widoku przeglądania podczas odtwarzania treści w tym przewodniku, aby dowiedzieć się, jak utrzymać ten wskaźnik w aktualnym stanie po jego pierwszym wyświetleniu.
Aby wyświetlać wskaźniki, które pojawiają się, gdy użytkownik przegląda drzewo wyszukiwania multimediów, utwórz pakiet dodatkowych informacji, który zawiera co najmniej jedną z tych stałych wartości, a następnie prześlij ten pakiet do metody MediaDescription.Builder.setExtras()
.
Ten fragment kodu pokazuje, jak wyświetlać wskaźniki dla treści dla dorosłych, które są w 70% ukończone:
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świetlać wskaźniki dla obecnie odtwarzanego elementu multimedialnego, możesz zadeklarować wartości Long
dla METADATA_KEY_IS_EXPLICIT
lub EXTRA_DOWNLOAD_STATUS
w MediaMetadataCompat
elementu mediaSession
. W widoku odtwarzania nie możesz wyświetlać wskaźników DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS
ani DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
.
Ten fragment kodu pokazuje, jak wskazać, że bieżąca piosenka w widoku odtwarzania jest wulgarna i pobrana:
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());
Aktualizowanie paska postępu w widoku przeglądania podczas odtwarzania treści
Jak już wspomnieliśmy, możesz użyć dodatku DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
, aby wyświetlić pasek postępu częściowo odtworzonych treści w widoku przeglądania. Jeśli jednak użytkownik będzie kontynuować odtwarzanie częściowo odsłuchanej treści z Androida Auto lub systemu operacyjnego Android Automotive, ten wskaźnik będzie z upływem czasu tracić na dokładności.
Aby utrzymać pasek postępu w aktualnym stanie, w przypadku Androida Auto i Androida Automotive OS możesz podać dodatkowe informacje w elementach MediaMetadataCompat
i PlaybackStateCompat
, aby połączyć bieżące treści z elementami multimediów w widoku przeglądania. Aby element multimedialny miał automatycznie aktualizowany pasek postępu, musi spełniać te wymagania:
- Podczas tworzenia
MediaItem
musi wysłaćDESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
w swoich dodatkach wartość z przedziału od 0, 0 do 1, 0 (włącznie). MediaMetadataCompat
musi wysyłaćMETADATA_KEY_MEDIA_ID
z wartością ciągu znaków równą identyfikatorowi media przekazanemu doMediaItem
.- Element
PlaybackStateCompat
musi zawierać dodatkowy element z kluczemPLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID
, który jest mapowany na wartość ciągu tekstowego równą identyfikatorowi multimediów przekazanemu do elementuMediaItem
.
Ten fragment kodu pokazuje, jak wskazać, że odtwarzany obecnie 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());
Wyświetlanie wyników wyszukiwania do przeglądania
Aplikacja może wyświetlać użytkownikom wyniki wyszukiwania kontekstowego po rozpoczęciu wyszukiwania. Android Auto i Android Automotive OS wyświetlają te wyniki za pomocą interfejsów wyszukiwania lub funkcji, które opierają się na zapytaniach wprowadzonych wcześniej w ramach sesji. Więcej informacji znajdziesz w sekcji Komendy głosowe w tym przewodniku.
Aby wyświetlać przeglądalne wyniki wyszukiwania, dodaj stały klucz
BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED
do pakietu dodatkowych funkcji metody onGetRoot()
usługi, mapując go na wartość logiczną true
.
Ten fragment kodu pokazuje, jak włączyć obsługę w metodie 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ąć dostarczać wyniki wyszukiwania, zastąpij metodę onSearch()
w usłudze przeglądarki multimediów. Android Auto i Android Automotive OS przekazują zapytania użytkownika do tej metody, gdy użytkownik wywoła interfejs zapytania wyszukiwania lub „Wyniki wyszukiwania”.
Aby ułatwić przeglądanie wyników wyszukiwania z metody onSearch()
w usłudze, możesz je uporządkować za pomocą elementów tytułu. Jeśli na przykład Twoja aplikacja odtwarza muzykę, możesz uporządkować wyniki wyszukiwania według albumu, wykonawcy i utworów.
Ten fragment kodu pokazuje prostą implementację metody 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 w przeglądarce
Niestandardowe działania przeglądania umożliwiają dodawanie niestandardowych ikon i etykietek do obiektów MediaItem
w aplikacji multimedialnej w samochodzie oraz obsługę interakcji użytkownika z tymi działaniami. Dzięki temu możesz rozszerzyć funkcjonalność aplikacji do multimediów na różne sposoby, np. dodając działania „Pobierz”, „Dodaj do kolejki”, „Odtwórz radio”, „Ulubione” lub „Usuń”.
Jeśli liczba działań niestandardowych jest większa niż dozwolona przez producenta, użytkownikowi zostanie wyświetlone menu przepełnienia.
Jak to działa?
Każde działanie niestandardowe związane z przeglądaniem jest definiowane za pomocą tych elementów:
- Identyfikator działania (unikalny ciąg znaków)
- Etykieta działania (tekst wyświetlany użytkownikowi)
- URI ikony działania (obiekt rysowalny wektorowo, który można zabarwić)
Listę niestandardowych działań związanych z przeglądaniem definiujesz globalnie w ramach BrowseRoot
. Następnie możesz przypisać poszczególne działania do poszczególnych MediaItem.
Gdy użytkownik wejdzie w interakcję z niestandardowym działaniem w ramach przeglądania, Twoja aplikacja otrzyma wywołanie zwrotne w onCustomAction()
. Następnie możesz wykonać działanie i w razie potrzeby zaktualizować listę działań dla MediaItem
. Jest to przydatne w przypadku działań zależnych od stanu, takich jak „Ustaw jako ulubiony” i „Pobierz”. W przypadku działań, które nie wymagają aktualizacji, takich jak „Odtwórz radio”, nie musisz aktualizować listy działań.
Możesz też dołączyć niestandardowe działania przeglądania do korzenia węzła przeglądania. Te działania będą widoczne na dodatkowym pasku narzędzi pod paskiem głównym.
Jak zaimplementować niestandardowe działania związane z przeglądaniem
Aby dodać do projektu niestandardowe działania przeglądania:
- Zastąp 2 metody w implementacji
MediaBrowserServiceCompat
: - Analizowanie limitów działań w czasie wykonywania:
- W
onGetRoot()
użyj kluczaBROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT
wrootHints
Bundle
, aby uzyskać maksymalną liczbę działań dozwolonych dla każdegoMediaItem
. Limit 0 oznacza, że funkcja nie jest obsługiwana przez system.
- W
- Utwórz globalną listę niestandardowych działań przeglądania:
- W przypadku każdego działania 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 wszystkie obiekty działańBundle
do listy.
- W przypadku każdego działania utwórz obiekt
- Dodaj listę globalną do
BrowseRoot
:- W sekcji
BrowseRoot
Dodatkowe informacjeBundle
dodaj listę działań jakoParcelable
Arraylist
za pomocą kluczaBROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST
.
- W sekcji
- Dodawanie działań do obiektów
MediaItem
:- Możesz dodawać działania do poszczególnych obiektów
MediaItem
, dodając listę identyfikatorów działań do dodatkówMediaDescriptionCompat
za pomocą kluczaDESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST
. Ta lista musi być podzbiorem globalnej listy działań zdefiniowanych wBrowseRoot
.
- Możesz dodawać działania do poszczególnych obiektów
- Obsługa działań i zwracanie postępów lub wyników:
- W
onCustomAction
obsłuż tę czynność na podstawie identyfikatora czynności i innych potrzebnych danych. IdentyfikatorMediaItem
, który wywołał działanie, możesz uzyskać z elementów dodatkowych za pomocą kluczaEXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID
. - Możesz zaktualizować listę działań w przypadku
MediaItem
, dodając kluczEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
do pakietu postępów lub wyników.
- W
Oto kilka zmian, które możesz wprowadzić w BrowserServiceCompat
, aby rozpocząć korzystanie z niestandardowych działań w przeglądarce.
Zastąpić BrowserServiceCompat
Musisz zastąpić te 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ń związanych z przeglądaniem 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 być zapakowane w osobną 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 czynności
bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI, "<ACTION_ICON_URI>")
Dodawanie niestandardowych działań związanych z przeglądaniem do Parceable
ArrayList
Dodaj wszystkie obiekty działania niestandardowego podczas przeglądania Bundle
do obiektu 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; }
Dodawanie listy niestandardowych działań przeglądania do katalogu głównego
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; }
Dodawanie działań do grupy reklam 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);
Wynik kompilacji onCustomAction
- Przeanalizuj mediaId z
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ść do użytkownika
mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE, mContext.getString(stringRes))
- Zaktualizuj element(użyj tej opcji, aby zaktualizować działania 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);
- Aktualizacja węzła przeglądania
//Change current browse node to mediaId mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE, mediaId);
- Wiadomość do użytkownika
- Jeśli wystąpił błąd, zadzwoń pod numer
result.sendError(resultBundle).
- Jeśli chcesz uzyskać informacje o postępach, zadzwoń pod numer
result.sendProgressUpdate(resultBundle)
. - Na koniec zadzwoń pod numer
result.sendResult(resultBundle)
.
Aktualizowanie stanu działania
Za pomocą metody result.sendProgressUpdate(resultBundle)
z kluczem EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
możesz zaktualizować element MediaItem
, aby odzwierciedlał nowy stan działania. Dzięki temu możesz przekazywać użytkownikowi w czasie rzeczywistym informacje o postępach i wynikach jego działań.
Przykład: działanie polegające na pobraniu
Oto przykład użycia tej funkcji do implementacji działania pobierania z 3 stanami:
- Pobieranie: jest to początkowy stan działania. Gdy użytkownik wybierze to działanie, możesz je zastąpić opcją „Pobieranie” i wywołać funkcję
sendProgressUpdate
, aby zaktualizować interfejs użytkownika. - Pobieranie: ten stan wskazuje, że pobieranie jest w toku. Za pomocą tego stanu możesz wyświetlić użytkownikowi pasek postępu lub inny wskaźnik.
- Pobrane: ten stan oznacza, że pobieranie zostało zakończone. Po zakończeniu pobierania możesz zastąpić „Pobieranie” elementem „Pobrane” i wywołać funkcję
sendResult
za pomocą klawiszaEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
, aby wskazać, że element powinien zostać odświeżony. Dodatkowo możesz użyć kluczaEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE
aby wyświetlić użytkownikowi wiadomość o udanym wykonaniu.
Dzięki temu możesz przekazywać użytkownikowi jasne informacje o procesie pobierania i jego bieżącym stanie. Możesz dodać jeszcze więcej szczegółów, używając ikon, które pokazują stany 25%, 50% i 75%.
Przykład: ulubione działanie
Innym przykładem jest ulubiona czynność z 2 stanami:
- Ulubione: to działanie jest wyświetlane w przypadku elementów, które nie znajdują się na liście ulubionych użytkownika. Gdy użytkownik wybierze to działanie, możesz je zastąpić działaniem „Ustaw jako ulubiony” i wywołać
sendResult
za pomocą klawiszaEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
, aby zaktualizować interfejs użytkownika. - Dodano do ulubionych: ta czynność jest wyświetlana w przypadku elementów znajdujących się na liście ulubionych użytkownika. Gdy użytkownik wybierze to działanie, możesz je zastąpić działaniem „Ulubione” i wywołać
sendResult
za pomocą klawiszaEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
, aby zaktualizować interfejs użytkownika.
Dzięki temu użytkownicy mają przejrzysty i spójny sposób zarządzania ulubionymi elementami.
Te przykłady pokazują elastyczność funkcji niestandardowych działań w przeglądarce i sposób ich stosowania do implementowania różnych funkcji z możliwością uzyskania informacji zwrotnych w czasie rzeczywistym, aby zwiększyć komfort korzystania z aplikacji multimedialnej w samochodzie.
Pełne przykładowe wdrożenie tej funkcji znajdziesz w projekcie TestMediaApp
.
Włączanie sterowania odtwarzaniem
Android Auto i Android Automotive wysyłają polecenia sterowania odtwarzaniem przez MediaSessionCompat
Twojej usługi.
Musisz zarejestrować sesję i zaimplementować powiązane z nią metody wywołania zwrotnego.
Rejestrowanie sesji multimediów
W metodzie onCreate()
usługi przeglądarki multimediów utwórz obiekt MediaSessionCompat
, a następnie zarejestruj sesję multimediów, wywołując funkcję 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()); ... }
Podczas tworzenia obiektu sesji multimediów ustawiasz obiekt wywołania zwrotnego, który jest używany do obsługi żądań sterowania odtwarzaniem. Tworzysz ten obiekt wywołania zwrotnego, podając implementację klasy MediaSessionCompat.Callback
w aplikacji. W następnej sekcji znajdziesz informacje o wdrażaniu tego obiektu.
Implementacja poleceń dotyczących odtwarzania
Gdy użytkownik poprosi o odtworzenie treści multimedialnych z Twojej aplikacji, Android Automotive OS i Android Auto użyją klasy MediaSessionCompat.Callback
obiektu MediaSessionCompat
z Twojej aplikacji, który został uzyskany z usługi przeglądarki multimediów w aplikacji. Gdy użytkownik chce sterować odtwarzaniem treści, np. wstrzymać odtwarzanie lub przejść do następnego utworu, Android Auto i system operacyjny Android Automotive wywołują jedną z metod obiektu callback.
Aby obsługiwać odtwarzanie treści, aplikacja musi rozszerzać abstrakcyjną klasę MediaSessionCompat.Callback
i implementować metody, które obsługuje.
Wdrożyć wszystkie te metody wywołania, które są odpowiednie dla typu treści oferowanych przez Twoją aplikację:
onPrepare()
- Wywoływany po zmianie źródła multimediów. System operacyjny Android Automotive wywołuje tę metodę natychmiast po uruchomieniu. Aplikacja multimedialna musi implementować tę metodę.
onPlay()
- Wywoływane, gdy użytkownik wybierze odtwarzanie bez wyboru konkretnego elementu. Aplikacja musi odtworzyć domyślne treści lub, jeśli odtwarzanie zostało wstrzymane za pomocą
onPause()
, wznowić odtwarzanie.Uwaga: aplikacja nie powinna automatycznie rozpoczynać odtwarzania muzyki, gdy system operacyjny Android Automotive lub Android Auto połączy się z usługą przeglądarki multimedialnej. Więcej informacji znajdziesz w sekcji ustawiania początkowego stanu odtwarzania.
onPlayFromMediaId()
- Wywoływane, gdy użytkownik wybierze odtworzenie określonego elementu. Metoda otrzymuje identyfikator przypisany do elementu multimedialnego w hierarchii treści przez usługę przeglądarki multimedialnej.
onPlayFromSearch()
- Wywoływane, gdy użytkownik wybierze odtwarzanie z zapytania wyszukiwania. Aplikacja musi dokonać odpowiedniego wyboru na podstawie przekazanego ciągu wyszukiwania.
onPause()
- Wywoływane, gdy użytkownik wstrzyma odtwarzanie.
onSkipToNext()
- Wywoływane, gdy użytkownik chce przejść do następnego elementu.
onSkipToPrevious()
- Wywoływane, gdy użytkownik chce przejść do poprzedniego elementu.
onStop()
- Wywoływane, gdy użytkownik zdecyduje się zatrzymać odtwarzanie.
Zastąp te metody w swojej aplikacji, aby udostępnić żądane funkcje. Nie musisz implementować metody, jeśli jej funkcje nie są obsługiwane przez Twoją aplikację.
Na przykład jeśli Twoja aplikacja odtwarza transmisję na żywo, np. transmisję sportową, nie musisz implementować metody onSkipToNext()
. Zamiast tego możesz użyć domyślnej implementacji operatora onSkipToNext()
.
Twoja aplikacja nie musi zawierać żadnej specjalnej logiki, aby odtwarzać treści przez głośniki samochodu. Gdy aplikacja otrzyma prośbę o odtworzenie treści, może odtworzyć dźwięk w taki sam sposób, w jaki odtwarza treści przez głośniki lub słuchawki telefonu użytkownika. Android Auto i system operacyjny Android Automotive automatycznie wysyłają treści audio do systemu samochodowego, aby odtwarzać je na głośnikach.
Więcej informacji o odtwarzaniu treści audio znajdziesz w artykułach MediaPlayer – przegląd, Aplikacja audio – przegląd i ExoPlayer – przegląd.
Ustawianie standardowych działań związanych z odtwarzaniem
Android Auto i system operacyjny Android Automotive wyświetlają elementy sterowania odtwarzaniem na podstawie działań włączonych w obiekcie PlaybackStateCompat
.
Domyślnie aplikacja musi obsługiwać te działania:
Aplikacja może dodatkowo obsługiwać te działania, jeśli są one związane z jej treściami:
Możesz też utworzyć kolejkę odtwarzania, która może być wyświetlana użytkownikowi, ale nie jest to wymagane. W tym celu wywołaj metody setQueue()
i setQueueTitle()
, włącz działanie ACTION_SKIP_TO_QUEUE_ITEM
i zdefiniuj funkcję wywołania zwrotnego onSkipToQueueItem()
.
Dodaj też obsługę ikony Co jest grane, która wskazuje, co jest obecnie odtwarzane. Aby to zrobić, wywołaj metodę setActiveQueueItemId()
i przekaż identyfikator odtwarzanego obecnie elementu w kole. Musisz zaktualizować setActiveQueueItemId()
za każdym razem, gdy nastąpi zmiana kolejki.
Aplikacje Android Auto i Android Automotive wyświetlają przyciski dla każdej włączonej czynności, a także kolejkę odtwarzania. Gdy użytkownik kliknie przyciski, system wywoła odpowiednią funkcję z MediaSessionCompat.Callback
.
Rezerwowanie niewykorzystanego miejsca
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ługuje jednej z tych funkcji, Android Auto i Android Automotive OS używają tej przestrzeni do wyświetlania utworzonych przez Ciebie działań niestandardowych.
Jeśli nie chcesz wypełniać tych pól działaniami niestandardowymi, możesz je zarezerwować, aby Android Auto i Android Automotive OS pozostawiały je puste, gdy aplikacja nie obsługuje danej funkcji. Aby to zrobić, wywołaj metodę setExtras()
z pakietem dodatków zawierającym stałe odpowiadające zarezerwowanym funkcjom.
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 w bundle, a jako ich wartości użyj zmiennej logicznej true
.
Ustaw początkowy stan odtwarzania
Ponieważ 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 włączać odtwarzania muzyki, gdy system operacyjny Android Automotive lub Android Auto połączy się z usługą przeglądarki multimediów. Zamiast tego korzystaj z Androida Auto i Androida Automotive, aby wznowić lub rozpocząć odtwarzanie na podstawie stanu samochodu lub działań użytkownika.
Aby to zrobić, ustaw początkową wartość PlaybackStateCompat
sesji multimedialnej na STATE_STOPPED
, STATE_PAUSED
, STATE_NONE
lub STATE_ERROR
.
Sesje multimediów w Android Auto i Android Automotive OS trwają tylko przez czas jazdy, więc użytkownicy często je uruchamiają i zawieszają. Aby zapewnić płynne działanie między sesjami, śledź stan poprzedniej sesji użytkownika, aby po otrzymaniu prośby o wznowienie odtwarzania użytkownik mógł automatycznie wrócić do miejsca, w którym zakończył odtwarzanie, np. do ostatniego odtwarzanego elementu multimedialnego, PlaybackStateCompat
i kolejki.
Dodawanie niestandardowych działań związanych z odtwarzaniem
Możesz dodać niestandardowe działania odtwarzania, aby wyświetlać dodatkowe działania obsługiwane przez Twoją aplikację multimedialną. Jeśli pozwala na to miejsce (i nie jest zarezerwowane), Android dodaje do elementów sterowania środkami transportu działania niestandardowe. W przeciwnym razie działania niestandardowe będą widoczne w menu przepełnienia. Działania niestandardowe są wyświetlane w kolejności, w jakiej zostały dodane do PlaybackStateCompat
.
Używaj działań niestandardowych, aby zapewnić działanie różniące się od działań standardowych. Nie używaj ich do zastępowania ani duplikowania standardowych działań.
Działania niestandardowe możesz dodawać za pomocą metody addCustomAction()
w klasie PlaybackStateCompat.Builder
.
Ten fragment kodu pokazuje, jak dodać niestandardową czynność „Uruchom kanał radiowy”:
Kotlin
val customActionExtras = Bundle() customActionExtras.putInt( androidx.media3.session.MediaConstants.EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT, androidx.media3.session.CommandButton.ICON_RADIO) stateBuilder.addCustomAction( PlaybackStateCompat.CustomAction.Builder( CUSTOM_ACTION_START_RADIO_FROM_MEDIA, resources.getString(R.string.start_radio_from_media), startRadioFromMediaIcon // or R.drawable.media3_icon_radio ).run { setExtras(customActionExtras) build() } )
Java
Bundle customActionExtras = new Bundle(); customActionExtras.putInt( androidx.media3.session.MediaConstants.EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT, androidx.media3.session.CommandButton.ICON_RADIO); stateBuilder.addCustomAction( new PlaybackStateCompat.CustomAction.Builder( CUSTOM_ACTION_START_RADIO_FROM_MEDIA, resources.getString(R.string.start_radio_from_media), startRadioFromMediaIcon) // or R.drawable.media3_icon_radio .setExtras(customActionExtras) .build());
Przykład tej metody znajdziesz w metodzie setCustomAction()
w przykładowej aplikacji Universal Android Music Player na GitHub.
Po utworzeniu działania niestandardowego sesja multimediów może na nie odpowiedzieć, zastępując metodę onCustomAction()
.
Ten fragment kodu pokazuje, jak Twoja 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)) { ... } }
Przykład tej metody znajdziesz w metodzie onCustomAction
w przykładowej aplikacji Universal Android Music Player na GitHub.
Ikony działań niestandardowych
Każde utworzone przez Ciebie działanie niestandardowe wymaga ikony.
Jeśli opis ikony pasuje do jednej z konstant CommandButton.ICON_
, należy ustawić tę wartość całkowitą dla klucza EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT
w elementach dodatkowych niestandardowej czynności. W obsługiwanych systemach zastąpi to zasób ikony przekazany do CustomAction.Builder
, umożliwiając komponentom systemowym renderowanie Twojego działania i innych działań związanych z odtwarzaniem w spójnym stylu.
Musisz też podać zasób ikony. Aplikacje w samochodach mogą działać na wielu różnych rozmiarach i gęstościach ekranu, dlatego ikony muszą być elementami wektorowymi. Plik wektorowy umożliwia skalowanie zasobów bez utraty szczegółów. Plik wektorowy ułatwia też dopasowanie krawędzi i rogów do granic pikseli w mniejszych rozdzielczościach.
Jeśli działanie niestandardowe zależy od stanu (np. włącza lub wyłącza ustawienie odtwarzania), zapewnij różne ikony dla różnych stanów, aby użytkownicy mogli zobaczyć zmianę po wybraniu działania.
Dodaj alternatywne style ikony dla wyłączonych działań.
Jeśli działanie niestandardowe jest niedostępne w bieżącym kontekście, zastąp ikonę działania ikoną alternatywną, która wskazuje, że działanie jest wyłączone.
Wskazać format dźwięku
Aby wskazać, że obecnie odtwarzane media używają specjalnego formatu audio, możesz określić ikony renderowane w samochodach obsługujących tę funkcję. Możesz ustawić KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI
i KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI
w pakiecie dodatkowych elementów bieżąco odtwarzanego elementu multimedialnego (przekazanych do MediaSession.setMetadata()
). Upewnij się, że ustawisz oba te dodatkowe elementy, aby dostosować się do różnych układów.
Dodatkowo możesz ustawić parametr KEY_IMMERSIVE_AUDIO
, aby poinformować producentów OEM, że chodzi o dźwięk przestrzenny. Powinni oni bardzo uważnie rozważyć, czy zastosować efekty dźwiękowe, które mogłyby zakłócać treści przestrzenne.
Dodawanie linków z elementu odtwarzanego w danym momencie
Możesz skonfigurować aktualnie odtwarzany element multimedialny tak, aby jego podpis, opis lub oba te elementy były linkami do innych elementów multimedialnych. Dzięki temu użytkownik może szybko przejść do powiązanych elementów, np. do innych utworów tego samego wykonawcy lub innych odcinków podcastu. Jeśli samochód obsługuje tę funkcję, użytkownicy mogą kliknąć link, aby przejść do tych treści.
Aby dodać linki, skonfiguruj metadane KEY_SUBTITLE_LINK_MEDIA_ID
(aby linkować z napisów) lub KEY_DESCRIPTION_LINK_MEDIA_ID
(aby linkować z opisu). Szczegółowe informacje znajdziesz w dokumentacji tych pól metadanych.
Obsługa komend głosowych
Aplikacja multimedialna musi obsługiwać polecenia głosowe, aby zapewnić kierowcom bezpieczne i wygodne korzystanie z aplikacji, które nie będzie ich rozpraszać. Jeśli na przykład aplikacja odtwarza jeden element multimedialny, użytkownik może powiedzieć „Odtwórz [tytuł utworu]”, aby poprosić aplikację o odtworzenie innego utworu bez patrzenia na wyświetlacz samochodu ani dotykania go. Użytkownicy mogą inicjować zapytania, klikając odpowiednie przyciski na kierownicy lub wypowiadając słowa kluczowe „OK Google”.
Gdy Android Auto lub system operacyjny Android Automotive wykryje i zinterpretuje polecenie głosowe, zostanie ono przesłane do aplikacji przez onPlayFromSearch()
.
Po otrzymaniu tego wywołania zwrotnego aplikacja wyszukuje treści pasujące do ciągu znaków query
i rozpoczyna odtwarzanie.
Użytkownicy mogą w zapytaniach podawać różne kategorie terminów, m.in. gatunek, wykonawcę, album, nazwę utworu, stację radiową czy 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 określonych kategorii, doda dodatkowe informacje w parametrze extras
. Możesz wysłać te dodatkowe informacje:
Obsługa pustego ciągu query
, który może być wysyłany przez Android Auto lub system operacyjny Android Automotive, jeśli użytkownik nie poda haseł wyszukiwania.
Jeśli na przykład użytkownik powie „Włącz muzykę”, W takim przypadku aplikacja może wybrać ostatnio odtwarzany lub nowo sugerowany utwór.
Jeśli wyszukiwanie nie może zostać przetworzone szybko, nie blokuj go w onPlayFromSearch()
.
Zamiast tego ustaw stan odtwarzania na STATE_CONNECTING
i przeprowadź wyszukiwanie na wątku asynchronicznym.
Po rozpoczęciu odtwarzania zastanów się nad wypełnieniem kolejki sesji multimedialnej powiązanymi treściami. Jeśli na przykład użytkownik poprosi o odtworzenie albumu, Twoja aplikacja może wypełnić kolejkę listą utworów z albumu. Zastanów się też nad wdrożeniem obsługi wyników wyszukiwania do przeglądania, aby użytkownik mógł wybrać inny utwór pasujący do jego zapytania.
Oprócz zapytań „odtwórz” systemy Android Auto i Android Automotive rozpoznają zapytania głosowe, aby umożliwić sterowanie odtwarzaniem, np. „zatrzymaj muzykę” i „następny utwór”, oraz dopasowywać te polecenia do odpowiednich wywołań sesji multimediów, takich jak onPause()
i onSkipToNext()
.
Szczegółowe informacje o tym, jak w aplikacji zaimplementować obsługę poleceń głosowych, znajdziesz w artykule Asystent Google i aplikacje multimedialne.
Wdrażanie zabezpieczeń przed rozpraszaniem uwagi
Podczas korzystania z Androida Auto telefon użytkownika jest połączony z głośnikami w samochodzie, dlatego musisz podjąć dodatkowe środki ostrożności, aby nie rozpraszać kierowcy.
Wyciszanie alarmów w samochodzie
Aplikacje multimedialne w Androidzie Auto nie mogą rozpoczynać odtwarzania dźwięku przez głośniki samochodowe, chyba że użytkownik rozpocznie odtwarzanie, na przykład przez naciśnięcie przycisku odtwarzania. Nawet alarm zaprogramowany przez użytkownika w aplikacji do obsługi multimediów nie może włączać odtwarzania muzyki przez głośniki samochodowe.
Aby spełnić ten wymóg, aplikacja może użyć sygnału CarConnection
przed odtworzeniem dźwięku. Aplikacja może sprawdzić, czy telefon wyświetla obraz na ekranie samochodu, obserwując LiveData
dla typu połączenia z samochodem i sprawdzając, czy jest on równy CONNECTION_TYPE_PROJECTION
.
Jeśli telefon użytkownika jest w trybie prezentacji, aplikacje multimedialne obsługujące alarmy muszą wykonać jedną z tych czynności:
- Wyłącz alarm.
- odtwarzanie alarmu przez
STREAM_ALARM
i zapewnienie na ekranie telefonu interfejsu do jego wyłączania;
Obsługa reklam multimedialnych
Domyślnie Android Auto wyświetla powiadomienie, gdy metadane multimediów ulegną zmianie podczas odtwarzania dźwięku. Gdy aplikacja multimedialna przełączy się z odtwarzania muzyki na wyświetlanie reklamy, wyświetlenie powiadomienia użytkownikowi może go rozpraszać. Aby w tym przypadku uniemożliwić wyświetlanie powiadomienia przez Androida Auto, musisz ustawić klucz metadanych multimediów METADATA_KEY_IS_ADVERTISEMENT
na METADATA_VALUE_ATTRIBUTE_PRESENT
, jak pokazano 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 wyświetl komunikat o błędzie za pomocą metody setErrorMessage()
. Pełną listę kodów błędów, których możesz używać podczas ustawiania komunikatu o błędzie, znajdziesz w PlaybackStateCompat
.
Komunikaty o błędach muszą być widoczne dla użytkownika i przetłumaczone na jego język. Android Auto i Android Automotive OS mogą wyświetlić użytkownikowi komunikat o błędzie.
Jeśli na przykład treści nie są dostępne w bieżącym regionie użytkownika, możesz użyć kodu błędu ERROR_CODE_NOT_AVAILABLE_IN_REGION
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łędów 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, przekaż mu tę informację w wiadomości. Na przykład komunikat o błędzie może zawierać komunikat „Zaloguj się w aplikacji [nazwa aplikacji]” zamiast „Zaloguj się”.
Inne materiały
- Przykładowy odtwarzacz Universal Media Player
- Przegląd aplikacji do odtwarzania dźwięku
- Omówienie ExoPlayer