Android Auto i Android Automotive OS pomagają udostępnić treści z aplikacji do multimediów użytkownikom w samochodzie. Aplikacja do multimediów dla samochodów musi obsługiwać przeglądarkę multimediów, aby systemy operacyjne Android Auto i Android Automotive lub inna aplikacja z przeglądarką multimediów mogły wykrywać i wyświetlać 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 telefonie, i jest ona zgodna z architekturą aplikacji do multimediów na Androida.
W tym przewodniku opisujemy wymagane komponenty MediaBrowserService
i MediaSession
, których aplikacja potrzebuje, by mogła działać na Androidzie Auto i Androidzie Automotive. Gdy ukończysz podstawową infrastrukturę mediów, możesz dodać obsługę Androida Auto i obsługę systemu operacyjnego Android Automotive do swojej aplikacji do multimediów.
Zanim zaczniesz
- Zapoznaj się z dokumentacją interfejsu Android Media API.
- W artykule Tworzenie aplikacji multimedialnych znajdziesz wskazówki dotyczące projektowania.
- Przejrzyj kluczowe terminy i zagadnienia wymienione w tej sekcji.
Kluczowe terminy i koncepcje
- Usługa przeglądarki multimediów
- Usługa na Androida wdrożona przez aplikację do multimediów zgodną z interfejsem API
MediaBrowserServiceCompat
. Aplikacja używa tej usługi do ujawniania swoich treści. - Przeglądarka multimediów
- Interfejs API używany przez aplikacje do multimediów do wykrywania usług przeglądarek multimedialnych i wyświetlania ich treści. Android Auto i system operacyjny Android Automotive używają przeglądarki do odtwarzania multimediów, aby znaleźć odpowiednią usługę.
- Element multimedialny
Przeglądarka multimediów porządkuje zawartość w postaci drzewa obiektów
MediaItem
. Element multimedialny może mieć jedną lub obie z tych flag:FLAG_PLAYABLE
: oznacza, że element jest liściem na drzewie treści. Element reprezentuje pojedynczy strumień dźwięku, np. utwór z albumu, rozdział w audiobooku 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 z tego albumu.
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.
- Zoptymalizowane pod kątem pojazdów
Działanie aplikacji na system operacyjny Android Automotive zgodnej ze wskazówkami dotyczącymi projektowania tego systemu. Interfejs do tych działań nie jest rysowany przez system operacyjny Android Automotive, dlatego musisz zadbać o to, aby aplikacja była zgodna z wytycznymi dotyczącymi projektowania. Zwykle obejmuje to większe elementy dotykowe i rozmiary czcionek, obsługę trybów dziennych i nocnych oraz wyższe proporcje kontrastu.
Interfejsy zoptymalizowane pod kątem pojazdu mogą się wyświetlać tylko wtedy, gdy nie obowiązują ograniczenia związane z wrażeniami użytkownika (CUXR), ponieważ te interfejsy mogą wymagać od użytkownika większej uwagi lub interakcji. Napędy CUXR nie działają, gdy samochód jest zatrzymany lub zaparkowany, ale zawsze działają, gdy samochód jest w ruchu.
Nie musisz projektować działań pod kątem Androida Auto, ponieważ Android Auto tworzy własny interfejs zoptymalizowany pod kątem pojazdu na podstawie informacji z Twojej usługi przeglądarki multimediów.
Skonfiguruj pliki manifestu aplikacji
Zanim utworzysz usługę przeglądarki multimediów, musisz skonfigurować pliki manifestu aplikacji.
Deklarowanie usługi przeglądarki multimediów
Zarówno Android Auto, jak i system operacyjny Android Automotive łączą się z Twoją aplikacją przez usługę przeglądarki multimediów, aby przeglądać elementy multimedialne. Zadeklaruj usługę przeglądarki multimediów w pliku manifestu, aby systemy Android Auto i Android Automotive mogły ją wykryć i połączyć się z aplikacją.
Ten fragment kodu pokazuje, jak zadeklarować usługę przeglądarki multimediów w pliku manifestu. Umieść ten kod w pliku manifestu modułu 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ślanie ikon aplikacji
Musisz określić ikony aplikacji, których Android Auto i Android Automotive mogą używać do reprezentowania Twojej aplikacji w interfejsie systemu. Wymagane są 2 rodzaje ikon:
- Ikona Menu z aplikacjami
- Ikona informacji o źródle
Ikona Menu z aplikacjami
Ikona programu uruchamiającego reprezentuje aplikację w interfejsie systemu, na przykład w programie uruchamiającym czy w zasobniku z ikonami. Aby używać ikony z aplikacji mobilnej do reprezentowania aplikacji multimedialnej w samochodzie, użyj tej deklaracji w pliku manifestu:
<application
...
android:icon="@mipmap/ic_launcher"
...
/>
Aby użyć innej ikony niż w aplikacji mobilnej, ustaw w pliku manifestu właściwość android:icon
w elemencie <service>
usługi przeglądarki multimediów:
<application>
...
<service
...
android:icon="@mipmap/auto_launcher"
...
/>
</application>
Ikona informacji o źródle
Jest ona używana tam, gdzie pierwszeństwo mają treści multimedialne, np. na kartach multimediów. Rozważ ponowne użycie małej ikony używanej do powiadomień. Ta ikona musi być monochromatyczna. Ikonę, która będzie reprezentować Twoją aplikację, możesz określić za pomocą tej deklaracji w pliku manifestu:
<application>
...
<meta-data
android:name="androidx.car.app.TintableAttributionIcon"
android:resource="@drawable/ic_status_icon" />
...
</application>
Utwórz usługę przeglądarki do multimediów
Możesz utworzyć usługę przeglądarki multimediów, rozszerzając klasę MediaBrowserServiceCompat
. Dzięki tej usłudze zarówno Android Auto, jak i Android Automotive będzie mógł:
- Przejrzyj hierarchię treści aplikacji, aby wyświetlić menu użytkownikowi.
- Aby sterować odtwarzaniem dźwięku, pobierz token obiektu
MediaSessionCompat
aplikacji.
Możesz też użyć usługi przeglądarki multimediów, by umożliwić innym klientom dostęp do treści multimedialnych z Twojej aplikacji. Mogą to być inne aplikacje na telefonie użytkownika lub inne klienty zdalne.
Przepływ pracy usługi przeglądarki multimediów
W tej sekcji omawiamy, jak system operacyjny Android Automotive i Android Auto współdziałają z usługą przeglądarki multimediów w trakcie standardowego przepływu pracy użytkownika.
- Użytkownik uruchamia Twoją aplikację na urządzeniu z systemem operacyjnym Android Automotive lub Android Auto.
- System operacyjny Android Automotive lub Android Auto kontaktuje się z usługą przeglądarki multimediów w Twojej aplikacji, korzystając z metody
onCreate()
. Podczas implementacji metodyonCreate()
musisz utworzyć i zarejestrować obiektMediaSessionCompat
oraz jego obiekt wywołania zwrotnego. - System operacyjny Android Automotive lub Android Auto wywołuje metodę
onGetRoot()
usługi, aby uzyskać główny element multimedialny w hierarchii treści. Główny element multimedialny nie jest wyświetlany, lecz służy do pobierania większej ilości treści z aplikacji. - System operacyjny Android Automotive lub Android Auto wywołuje metodę
onLoadChildren()
usługi, aby pobrać dane podrzędne głównego elementu multimedialnego. System operacyjny Android Automotive i Android Auto wyświetlają te elementy multimedialne jako elementy treści najwyższego poziomu. Więcej informacji o tym, czego system oczekuje na tym poziomie, znajdziesz w sekcji Struktura menu głównego na tej stronie. - Jeśli użytkownik wybierze element multimedialny, który można przeglądać, metoda
onLoadChildren()
Twojej usługi zostanie wywołana ponownie, aby pobrać elementy podrzędne wybranej pozycji menu. - Gdy użytkownik wybierze element multimedialny, który można odtworzyć, system operacyjny Android Automotive lub Android Auto wywołuje odpowiednią metodę wywołania zwrotnego sesji multimediów, aby wykonać to działanie.
- Jeśli aplikacja obsługuje tę funkcję, użytkownik może też przeszukiwać Twoje treści. W takim przypadku system operacyjny Android Automotive lub Android Auto wywołuje metodę
onSearch()
usługi.
Utwórz hierarchię treści
Android Auto i Android Automotive OS wywołują usługę przeglądarki multimediów w Twojej aplikacji, aby ustalić, jakie treści są dostępne. Aby to umożliwić, w przeglądarce multimediów musisz wdrożyć 2 metody: onGetRoot()
i onLoadChildren()
Implementacja onGetRoot
Metoda onGetRoot()
Twojej usługi zwraca informacje o węźle głównym hierarchii treści.
Android Auto i system operacyjny Android Automotive używają tego węzła głównego, aby wysyłać żądanie o pozostałe treści za pomocą metody onLoadChildren()
.
Ten fragment kodu zawiera 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); }
Bardziej szczegółowy przykład tej metody znajdziesz w opisie metody onGetRoot()
w przykładowej aplikacji Universal Android Music Player na GitHubie.
Dodaj weryfikację pakietu dla onGetRoot()
Gdy następuje wywołanie metody onGetRoot()
usługi, pakiet wywołujący przekazuje do usługi informacje identyfikacyjne. Usługa może używać tych informacji do określenia, czy pakiet może uzyskać dostęp do Twoich treści. Możesz na przykład ograniczyć dostęp do zawartości aplikacji do listy zatwierdzonych pakietów, porównując pakiet clientPackageName
z listą dozwolonych i potwierdzając certyfikat używany do podpisania pakietu APK pakietu. Jeśli nie można zweryfikować pakietu, zwróć null
, aby odmówić dostępu do Twoich treści.
Aby aplikacje systemowe, takie jak Android Auto i system operacyjny Android Automotive, miały dostęp do Twoich treści, gdy wywołują one metodę onGetRoot()
, Twoja usługa musi zawsze zwracać wartość BrowserRoot
niezerową. Sygnatura aplikacji systemowej Android Automotive może się różnić w zależności od marki i modelu samochodu, dlatego musisz zezwolić wszystkim aplikacjom systemowym na pełną obsługę systemu operacyjnego Android Automotive.
Ten fragment kodu pokazuje, jak usługa może sprawdzić, czy pakiet wywołujący 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 jest fragmentem kodu z zajęć PackageValidator
w przykładowej aplikacji Universal Android Music Player na GitHubie. W tej klasie znajdziesz bardziej szczegółowy przykład implementacji weryfikacji pakietu w metodzie onGetRoot()
Twojej usługi.
Oprócz zezwalania na aplikacje systemowe musisz zezwolić Asystentowi Google na połączenie się z urządzeniem MediaBrowserService
. Pamiętaj, że Asystent Google ma osobne nazwy pakietów na telefon, w tym na Androida Auto i system operacyjny Android Automotive.
Implementacja onLoadChildren()
Po otrzymaniu obiektu węzła głównego, systemy operacyjne Android Auto i Android Automotive tworzą menu najwyższego poziomu, wywołując w obiekcie węzła głównego onLoadChildren()
w celu pobrania jego elementów podrzędnych. Aplikacje klienckie tworzą podmenu,
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 multimedialnych jest identyfikowany przez unikalny ciąg identyfikatora. Aplikacje klienckie traktują te ciągi identyfikatorów jako nieprzejrzyste tokeny. Gdy aplikacja kliencka chce przejść do menu podrzędnego lub odtworzyć element multimedialny, przekazuje token. Twoja aplikacja odpowiada za powiązanie tokena z odpowiednim elementem multimedialnym.
Ten fragment kodu zawiera 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 opisie metody onLoadChildren()
w przykładowej aplikacji Universal Android Music Player na GitHubie.
Utwórz strukturę menu głównego
Android Auto i system operacyjny Android Automotive mają określone ograniczenia dotyczące struktury menu głównego. Są one przekazywane do funkcji MediaBrowserService
za pomocą wskazówek dotyczących katalogu głównego, które można odczytać za pomocą argumentu Bundle
przekazywanego do onGetRoot()
.
Postępując zgodnie z tymi wskazówkami, system będzie optymalnie wyświetlać główną zawartość jako karty nawigacyjne. Jeśli nie zastosujesz się do tych wskazówek, niektóre treści główne mogą zostać usunięte lub mogą stać się trudniejsze do znalezienia przez system. Wysyłane są 2 wskazówki:
- Ograniczenie liczby elementów podrzędnych: w większości przypadków możesz oczekiwać, że ta liczba wyniesie 4. Oznacza to, że nie można wyświetlić ponad czterech kart.
- Obsługiwane flagi w elementach podrzędnych: ta wartość powinna wynosić
MediaItem#FLAG_BROWSABLE
. Oznacza to, że jako karty mogą być wyświetlane tylko elementy, które można przeglądać (nie te, które można odtworzyć).
Aby odczytać odpowiednie wskazówki dotyczące poziomu 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 zastosować rozgałęzienie logiki struktury hierarchii treści na podstawie wartości tych wskazówek, zwłaszcza jeśli Twoja hierarchia różni się w przypadku integracji MediaBrowser
poza Androidem Auto i systemem operacyjnym Android Automotive.
Jeśli na przykład zwykle wyświetlasz element główny z możliwością odtwarzania, możesz umieścić go w elemencie, który można przeglądać na poziomie głównym, ze względu na wartość wskazówek dotyczących obsługiwanych flag.
Oprócz tych wskazówek warto też przestrzegać kilku dodatkowych wskazówek, które pomogą Ci zadbać o optymalne renderowanie kart:
- Dla każdego elementu karty należy udostępniać monochromatyczne, najlepiej białe ikony.
- Dla każdego elementu karty podawaj krótkie, ale treściwe etykiety. Krótsze etykiety zmniejszają ryzyko obcięcia ciągów znaków.
Wyświetlanie elementów graficznych
Elementy graficzne przeznaczone do elementów multimedialnych muszą być przekazywane jako lokalny identyfikator URI przy użyciu ContentResolver.SCHEME_CONTENT
lub ContentResolver.SCHEME_ANDROID_RESOURCE
.
Ten lokalny identyfikator URI musi przyjmować postać bitmapy lub obiekt rysowalny wektorowo w zasobach aplikacji. W przypadku obiektów MediaDescriptionCompat
reprezentujących elementy w hierarchii treści przekaż identyfikator URI za pomocą funkcji setIconUri()
.
W przypadku obiektów MediaMetadataCompat
reprezentujących aktualnie odtwarzany element przekaż identyfikator URI za pomocą putString()
, korzystając z dowolnego z tych kluczy:
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI
MediaMetadataCompat.METADATA_KEY_ART_URI
MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI
Poniżej opisujemy, jak pobrać sztukę z identyfikatora URI w sieci i udostępnić ją za pomocą lokalnego identyfikatora URI. Pełniejszy przykład znajdziesz w opisie implementacji metody openFile()
i otaczających ją metod w przykładowej aplikacji odtwarzacza muzyki Universal Android.
Utwórz identyfikator URI
content://
odpowiadający identyfikatorowi URI sieciowej. Usługa przeglądarki multimediów i sesja multimediów przekazują ten identyfikator URI treści do Androida Auto i Androida 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 swojej implementacji
ContentProvider.openFile()
sprawdź, czy dla odpowiedniego identyfikatora URI istnieje plik. Jeśli nie, pobierz plik obrazu i zapisz go w pamięci podręcznej. Ten fragment kodu używa metody 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 zbudowaniu hierarchii treści za pomocą elementów, które można przeglądać lub odtwarzać, możesz zastosować style treści, które określają, jak elementy te będą wyświetlane w samochodzie.
Możesz używać tych stylów treści:
- Elementy listy
-
Ten styl treści traktuje priorytetowo tytuły i metadane.
- Elementy siatki
-
Ten styl treści traktuje obrazy priorytetowo przed tytułami i metadanymi.
Ustaw domyślne style treści
Możesz ustawić globalne domyślne ustawienia wyświetlania elementów multimedialnych, dodając określone stałe do pakietu dodatków BrowserRoot
w metodzie onGetRoot()
. Android Auto i system operacyjny Android Automotive odczytują ten pakiet i szukają tych stałych, aby określić właściwy styl.
Te dodatki mogą zostać użyte jako klucze w pakiecie:
DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
: wskazuje wskazówkę dotyczącą prezentacji dla wszystkich elementów w drzewie przeglądania, które można przeglądać.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
: wskazuje wskazówkę dotyczącą prezentacji dla wszystkich elementów gry w drzewie przeglądania.
Klucze mogą być mapowane na te stałe wartości całkowite, co wpływa na wyświetlanie 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ą one takie same jak zwykłe elementy list, z tym że wokół ikon elementów są stosowane marginesy, ponieważ ikony wyglądają lepiej, gdy są małe. Ikony muszą być wektorowymi elementami rysowalnymi. Ta wskazówka powinna być podana tylko w przypadku elementów, które można przeglądać.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM
: odpowiadające im elementy są wyświetlane jako elementy siatki „Kategoria”. Są takie same jak zwykłe elementy siatki z tą różnicą, że wokół ikon elementów są stosowane marginesy, ponieważ ikony wyglądają lepiej, gdy są małe. Ikony muszą być wektorowymi elementami rysowalnymi. Ta wskazówka powinna być podana tylko w przypadku elementów, które można przeglądać.
Poniższy fragment kodu pokazuje, jak ustawić domyślny styl treści dla elementów możliwych do przeglądania jako siatki, a elementy gry na 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 poszczególnych elementów
Interfejs Content Style API pozwala zastąpić domyślny styl treści w elementach podrzędnych każdego elementu multimedialnego, który można przeglądać, a także samych elementów multimedialnych.
Aby zastąpić ustawienie domyślne w przypadku elementów podrzędnych elementu multimedialnego, który można przeglądać, utwórz pakiet rozszerzeń w elemencie MediaDescription
elementu multimedialnego i dodaj podane wyżej wskazówki. DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
obowiązuje w przypadku dzieci, które można zagrać w ten element, a DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
– do dzieci, które można przeglądać.
Aby zastąpić ustawienie domyślne w przypadku samego elementu multimedialnego, a nie jego elementów podrzędnych, utwórz pakiet dodatków w elemencie MediaDescription
elementu multimedialnego i dodaj wskazówkę z kluczem DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM
.
Użyj wartości opisanych wcześniej, aby określić prezentację tego elementu.
Poniższy fragment kodu pokazuje, jak utworzyć możliwy do przeglądania element MediaItem
, który zastąpi domyślny styl treści zarówno w przypadku siebie, jak i jego elementów podrzędnych. Stylizuje się jako element listy kategorii, elementy podrzędne, które można przeglądać, jako elementy listy, a elementy podrzędne, które można odtwarzać, 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ą wskazówek dotyczących tytułów
Do grupowania powiązanych elementów multimedialnych możesz używać wskazówek dotyczących poszczególnych elementów. Każdy element multimedialny w grupie musi zadeklarować w elemencie MediaDescription
pakiet dodatków, który obejmuje 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 będzie używany
jako tytuł grupy.
Poniższy fragment kodu pokazuje, jak utworzyć obiekt 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ć, tworząc obok siebie blok. Załóżmy na przykład, że chcesz wyświetlić w tej kolejności 2 grupy elementów multimedialnych – „Utwory” i „Albumy”, a aplikacja przesyła 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 wartością
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
Elementy multimedialne z grup „Utwory” i „Albumy” nie są umieszczone w sąsiadujących ze sobą blokach, dlatego Android Auto i Android Automotive interpretują to 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 „Utwory” 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 przekazać je w takiej kolejności:
- 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 wartością
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
Wyświetl dodatkowe wskaźniki metadanych
Możesz dołączyć dodatkowe wskaźniki metadanych, aby szybko wyświetlać informacje o treściach w drzewie przeglądarki multimediów i podczas odtwarzania. W drzewie przeglądania systemy operacyjne Android Auto i Android Automotive odczytują dodatki związane z produktem i szukają określonych stałych, aby określić, które wskaźniki mają być wyświetlane. Podczas odtwarzania multimediów Android Auto i system operacyjny Android Automotive odczytują metadane sesji multimedialnej i poszukują określonych stałych, aby określić wskaźniki do wyświetlenia.
Te stałe mogą być używane zarówno w opisie MediaItem
, jak i w dodatkowych (MediaMetadata
):
EXTRA_DOWNLOAD_STATUS
: wskazuje stan pobierania elementu. Użyj tej stałej jako klucza. Możliwe wartości to te długie stałe:STATUS_DOWNLOADED
: element został w całości pobrany.STATUS_DOWNLOADING
: element jest pobierany.STATUS_NOT_DOWNLOADED
: element nie został pobrany.
METADATA_KEY_IS_EXPLICIT
: wskazuje, czy element zawiera treści dla dorosłych. Aby wskazać, że element jest jednoznacznie jasny, użyj tej stałej jako klucza i długościMETADATA_VALUE_ATTRIBUTE_PRESENT
jako wartości.
Tych stałych można używać tylko w dodatkowych opisach (MediaItem
):
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 te stałe liczby całkowite:DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED
: element w ogóle nie został odtworzony.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED
: element został odtworzony tylko częściowo, a bieżąca pozycja znajduje się gdzieś pośrodku.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED
: element został ukończony.
DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
: wskazuje postęp ukończenia odtwarzania długich treści w zakresie od 0,0 do 1,0 włącznie. Zawiera on więcej informacji o staniePARTIALLY_PLAYING
, dzięki czemu system operacyjny Android Auto lub Android Automotive wyświetla bardziej zrozumiały wskaźnik postępu, np. pasek postępu. Jeśli korzystasz z tego dodatku, przeczytaj sekcję o aktualizowaniu paska postępu w widoku przeglądania podczas odtwarzania treści w tym przewodniku, aby dowiedzieć się, jak dbać o aktualność tego wskaźnika po pierwszym wyświetleniu.
Aby wyświetlać wskaźniki, które pojawiają się, gdy użytkownik przegląda drzewo przeglądania multimediów, utwórz pakiet dodatków zawierający co najmniej 1 z tych stałych i przekaż go do metody MediaDescription.Builder.setExtras()
.
Ten fragment kodu pokazuje, jak wyświetlać wskaźniki, które pokazują, że element multimedialny jest gotowy 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świetlać wskaźniki odtwarzanego elementu multimedialnego, możesz zadeklarować wartości Long
dla elementu METADATA_KEY_IS_EXPLICIT
lub EXTRA_DOWNLOAD_STATUS
w MediaMetadataCompat
elementu mediaSession
. W widoku odtwarzania nie można wyświetlić wskaźników DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS
ani DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
.
Ten fragment kodu pokazuje, jak wskazać, że bieżący utwór w widoku odtwarzania jest przeznaczony dla pełnoletnich i został pobrany:
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 w trakcie odtwarzania treści.
Jak już wspomnieliśmy, możesz użyć dodatku DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
, aby wyświetlić pasek postępu w przypadku częściowo odtworzonych treści w widoku przeglądania. Jeśli jednak użytkownik będzie nadal odtwarzać częściowo odtworzoną treść z systemu Android Auto lub Android Automotive, z upływem czasu wskaźnik ten stanie się niedokładny.
Aby zapewnić aktualność paska postępu w systemach Android Auto i Android Automotive, możesz podać dodatkowe informacje w usługach MediaMetadataCompat
i PlaybackStateCompat
, aby połączyć bieżące treści z elementami multimedialnymi w widoku przeglądania. Aby element multimedialny miał automatycznie aktualizowany pasek postępu, musi spełniać te wymagania:
- Po utworzeniu obiekt
MediaItem
musi wysłać w dodatkowych komponentachDESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
o wartości od 0, 0 do 1, 0 włącznie. MediaMetadataCompat
musi wysyłać ciągMETADATA_KEY_MEDIA_ID
z wartością ciągu znaków równą identyfikatorze mediów przekazywanym do metodyMediaItem
.PlaybackStateCompat
musi zawierać dodatkowy z kluczemPLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID
, który jest mapowany na ciąg znaków równy identyfikatorowi mediów przekazywanemu do kluczaMediaItem
.
Ten fragment kodu pokazuje, jak wskazać, że aktualnie odtwarzany element jest połączony 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świetl wyniki wyszukiwania, które można przeglądać
Aplikacja może oferować kontekstowe wyniki wyszukiwania, które wyświetlają się użytkownikom po rozpoczęciu wyszukiwania. Android Auto i Android Automotive OS wyświetlają te wyniki w interfejsach zapytań lub za pomocą asortymentów, które łączą się z zapytaniami wprowadzonymi wcześniej w sesji. Więcej informacji znajdziesz w sekcji Obsługa komend głosowych w tym przewodniku.
Aby wyświetlić możliwe do przeglądania wyniki wyszukiwania, umieść klucz stały BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED
w pakiecie dodatków metod onGetRoot()
usługi, mapując go na wartość logiczną true
.
Ten fragment kodu pokazuje, jak włączyć obsługę w metodzie 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 metodę onSearch()
w usłudze przeglądarki multimediów. Android Auto i system operacyjny Android Automotive przekazują hasła wyszukiwane przez użytkownika za pomocą tej metody za każdym razem, gdy użytkownik wywołuje interfejs zapytania wyszukiwania lub akredytację „Wyniki wyszukiwania”.
Możesz uporządkować wyniki wyszukiwania za pomocą metody onSearch()
w Twojej usłudze za pomocą elementów tytułów, aby łatwiej je przeglądać. Jeśli na przykład aplikacja odtwarza muzykę, możesz
uporządkować wyniki wyszukiwania według albumu, wykonawcy i utworów.
Ten fragment kodu zawiera 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 przeglądania
Niestandardowe działania przeglądania umożliwiają dodawanie niestandardowych ikon i etykiet do obiektów MediaItem
w aplikacji multimedialnej w samochodzie oraz obsługę interakcji użytkowników z tymi działaniami. Dzięki temu możesz rozszerzyć funkcjonalność aplikacji do multimediów, np. dodać działania „Pobierz”, „Dodaj do kolejki”, „Włącz radio”, „Ulubione” lub „Usuń”.
Jeśli dostępnych jest więcej działań niestandardowych niż zezwala 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 ciągu znaków).
- Etykieta działania (tekst wyświetlany użytkownikowi).
- Identyfikator URI ikony działania (element rysowalny wektorowo, z możliwością zabarwienia)
W BrowseRoot
następuje globalnie lista niestandardowych działań przeglądania. Następnie możesz dołączyć podzbiór tych działań do poszczególnych MediaItem.
Gdy użytkownik wejdzie w interakcję z niestandardowym działaniem przeglądania, aplikacja otrzyma wywołanie zwrotne w komponencie onCustomAction()
. Możesz wykonać działanie i w razie potrzeby zaktualizować listę działań dla elementu MediaItem
. Jest to przydatne w przypadku działań stanowych,
np. „Ulubione” i „Pobierz”. W przypadku działań, które nie wymagają aktualizacji, np. „Włącz radio”, nie musisz aktualizować listy działań.
Niestandardowe działania przeglądania możesz też dołączyć do katalogu głównego węzła przeglądania. Te czynności będą wyświetlane na dodatkowym pasku narzędzi pod głównym paskiem narzędzi.
Jak zaimplementować niestandardowe działania przeglądania
Oto kroki, które pozwalają dodać do projektu niestandardowe działania przeglądania:
- Zastąp 2 metody w implementacji
MediaBrowserServiceCompat
: - Analizuj limity działań w czasie działania:
- W
onGetRoot()
sprawdź maksymalną dozwoloną liczbę działań dla każdegoMediaItem
za pomocą kluczaBROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT
w:Bundle
rootHints
. Wartość 0 oznacza, że dana funkcja nie jest obsługiwana przez system.
- W
- 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 wszystkie obiekty działaniaBundle
do listy.
- Dla każdej czynności utwórz obiekt
- Dodaj listę globalną do elementu
BrowseRoot
:- W sekcji
BrowseRoot
dodatkówBundle
dodaj listę działań jakoParcelable
Arraylist
za pomocą kluczaBROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST
.
- W sekcji
- Dodaj działania do obiektów
MediaItem
:- Możesz dodawać działania do poszczególnych obiektów
MediaItem
, dodając listę identyfikatorów działań w dodatkachMediaDescriptionCompat
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ń oraz zwracanie postępów lub wyników:
- W
onCustomAction
wykonaj działanie na podstawie identyfikatora działania i innych potrzebnych danych. Za pomocą kluczaEXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID
możesz uzyskać identyfikatorMediaItem
, który wywołał działanie w przypadku dodatków. - Możesz zaktualizować listę działań dla elementu
MediaItem
, dodając kluczEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
do pakietu wyników lub postępu.
- W
Oto kilka zmian, które możesz wprowadzić w BrowserServiceCompat
, aby zacząć korzystać z niestandardowych działań przeglądania.
Zastąp zasadę BrowserServiceCompat
Musisz zastąpić poniższe metody w zadaniu 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 należy spakować 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 niestandardowego działania przeglądania Bundle
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);
Utwórz onCustomAction
wynik
- Przeanalizuj element 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); }
- Aby uzyskać wyniki asynchroniczne, odłącz wynik.
result.detach()
- Utwórz pakiet wyników
- Wiadomość do użytkownika
mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE, mContext.getString(stringRes))
- Aktualizowanie elementu(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);
- 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 postęp jest zaktualizowany, zadzwoń pod numer
result.sendProgressUpdate(resultBundle)
. - Zakończ, dzwoniąc pod numer
result.sendResult(resultBundle)
.
Aktualizowanie stanu działania
Używając metody result.sendProgressUpdate(resultBundle)
z kluczem EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
, możesz zaktualizować MediaItem
, aby odzwierciedlał nowy stan działania. Dzięki temu możesz informować użytkownika w czasie rzeczywistym o postępach i wynikach podejmowanych działań.
Przykład: działanie polegające na pobraniu
Oto przykład użycia tej funkcji do zaimplementowania działania pobierania z 3 stanami:
- Pobieranie: to początkowy stan działania. Gdy użytkownik wybierze to działanie, możesz zamienić je na „Pobieranie” i wywołać metodę
sendProgressUpdate
, aby zaktualizować interfejs. - Pobieranie: ten stan oznacza, że trwa pobieranie. Możesz użyć tego stanu, by wyświetlić użytkownikowi pasek postępu lub inny wskaźnik.
- Pobrano: ten stan oznacza, że pobieranie zostało zakończone. Po zakończeniu pobierania możesz zamienić „Pobieranie” na „Pobrane” i wywołać metodę
sendResult
za pomocą klawiszaEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
, aby wskazać, że element powinien zostać odświeżony. Możesz też użyć kluczaEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE
, aby wyświetlić użytkownikowi komunikat o powodzeniu.
Dzięki temu możesz wyraźnie poinformować użytkownika o procesie pobierania i jego obecnym stanie. Możesz dodać jeszcze więcej szczegółów za pomocą ikon, które pokazują stany pobierania: 25%, 50% i 75%.
Przykład: ulubiona akcja
Kolejny przykład to ulubione działanie z 2 stanami:
- Ulubione: działanie jest wyświetlane w przypadku elementów, których nie ma na liście ulubionych użytkownika. Gdy użytkownik wybierze to działanie, możesz zamienić je na „Dodano do ulubionych” i wywołać
sendResult
za pomocą kluczaEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
, aby zaktualizować interfejs. - Dodane do ulubionych: to działanie jest wyświetlane w przypadku elementów znajdujących się na liście ulubionych użytkownika. Gdy użytkownik wybierze to działanie, możesz zamienić je na „Ulubione” i wywołać metodę
sendResult
przy użyciu kluczaEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
, aby zaktualizować interfejs.
Dzięki temu użytkownicy mogą w jasny i spójny sposób zarządzać ulubionymi elementami.
Te przykłady pokazują elastyczność niestandardowych działań przeglądania i sposoby ich wykorzystania do zaimplementowania różnych funkcji z opiniami w czasie rzeczywistym, aby zwiększyć wygodę użytkowników korzystających z aplikacji do multimediów w samochodzie.
Pełną przykładową implementację tej funkcji znajdziesz w projekcie TestMediaApp
.
Włącz sterowanie odtwarzaniem
Android Auto i system operacyjny Android Automotive wysyłają polecenia sterujące odtwarzaniem przez MediaSessionCompat
usługi.
Musisz zarejestrować sesję i zaimplementować powiązane z nią metody wywołania zwrotnego.
Zarejestruj sesję multimediów
W metodzie onCreate()
usługi przeglądarki multimediów utwórz MediaSessionCompat
, a następnie 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()); ... }
Podczas tworzenia obiektu sesji multimediów ustawiasz obiekt wywołania zwrotnego służący do obsługi żądań sterowania odtwarzaniem. Obiekt wywołania zwrotnego możesz utworzyć, dostarczając implementację klasy MediaSessionCompat.Callback
dla swojej aplikacji. W następnej sekcji dowiesz się, jak wdrożyć ten obiekt.
Wdrażanie poleceń Play
Gdy użytkownik prosi o odtworzenie elementu multimedialnego z Twojej aplikacji, system operacyjny Android Automotive i Android Auto korzystają z klasy MediaSessionCompat.Callback
z obiektu MediaSessionCompat
aplikacji uzyskanego z usługi przeglądarki multimediów w aplikacji. Gdy użytkownik chce sterować odtwarzaniem treści, np. wstrzymać odtwarzanie lub przejść do następnej ścieżki, Android Auto i Android Automotive OS wywołają jedną z metod obiektu wywołania zwrotnego.
Aby umożliwić odtwarzanie treści, Twoja aplikacja musi rozszerzyć abstrakcyjną klasę MediaSessionCompat.Callback
i zaimplementować metody obsługiwane przez Twoją aplikację.
Zaimplementuj wszystkie poniższe metody wywołania zwrotnego, które są odpowiednie dla typu treści oferowanych przez Twoją aplikację:
onPrepare()
- Wywoływane po zmianie źródła multimediów. System operacyjny Android Automotive też wywołuje tę metodę natychmiast po uruchomieniu. Twoja aplikacja do multimediów musi implementować tę metodę.
onPlay()
- Wywoływane, jeśli użytkownik zdecyduje się zagrać w grze bez wybierania konkretnego elementu. Aplikacja musi odtwarzać swoje domyślne treści. Jeśli odtwarzanie zostało wstrzymane za pomocą
onPause()
, aplikacja wznowi odtwarzanie.Uwaga: aplikacja nie powinna automatycznie odtwarzać muzyki, gdy system operacyjny Android Automotive lub Android Auto połączy się z przeglądarką multimediów. Więcej informacji znajdziesz w sekcji na temat ustawiania początkowego stanu odtwarzania.
onPlayFromMediaId()
- Wywoływane, gdy użytkownik chce odtworzyć konkretny element. Metoda jest przekazywana identyfikator, który usługa przeglądarki multimediów przypisała elementowi multimedialnemu w hierarchii treści.
onPlayFromSearch()
- Wywoływane, gdy użytkownik chce odtworzyć film, wpisując zapytanie. Aplikacja musi dokonać odpowiedniego wyboru na podstawie przekazanego ciągu wyszukiwania.
onPause()
- Wywoływane, gdy użytkownik zdecyduje się wstrzymać odtwarzanie.
onSkipToNext()
- Wywoływane, gdy użytkownik zdecyduje się przejść do następnego elementu.
onSkipToPrevious()
- Wywoływane, gdy użytkownik zdecyduje się przejść do poprzedniego elementu.
onStop()
- Wywoływane, gdy użytkownik zdecyduje się zatrzymać odtwarzanie.
Zastąp te metody w aplikacji, aby umożliwić korzystanie z odpowiednich funkcji. Nie musisz implementować metody, jeśli jej funkcja nie jest obsługiwana przez Twoją aplikację. Jeśli na przykład aplikacja odtwarza transmisję na żywo, np. transmisję sportową, nie musisz implementować metody onSkipToNext()
. Zamiast tego możesz użyć domyślnej implementacji onSkipToNext()
.
Twoja aplikacja nie wymaga żadnej specjalnej logiki do odtwarzania treści przez głośniki w samochodzie. Gdy aplikacja otrzyma prośbę o odtworzenie treści, może odtworzyć dźwięk w taki sam sposób jak dźwięk przez głośniki lub słuchawki telefonu użytkownika. Android Auto i system operacyjny Android Automotive automatycznie przesyłają treści audio do systemu samochodu, aby odtwarzać je przez głośniki samochodu.
Więcej informacji o odtwarzaniu treści audio znajdziesz w omówieniu odtwarzacza MediaPlayer, omówieniu aplikacji Audio i omówieniu odtwarzacza ExoPlayer.
Ustaw standardowe działania związane z odtwarzaniem
Android Auto i system operacyjny Android Automotive wyświetlają elementy sterujące odtwarzaniem na podstawie działań, które włączono w obiekcie PlaybackStateCompat
.
Domyślnie aplikacja musi obsługiwać te działania:
Aplikacja może dodatkowo obsługiwać te działania, jeśli są powiązane z jej zawartością:
Dodatkowo możesz utworzyć kolejkę odtwarzania, która może się wyświetlać użytkownikowi, ale nie jest wymagana. Aby to zrobić, wywołaj metody setQueue()
i setQueueTitle()
, włącz działanie ACTION_SKIP_TO_QUEUE_ITEM
i zdefiniuj wywołanie zwrotne onSkipToQueueItem()
.
Dodano też obsługę ikony Teraz odtwarzane, która wskazuje, co jest odtwarzane. Aby to zrobić, wywołaj metodę setActiveQueueItemId()
i przekaż identyfikator aktualnie odtwarzanego elementu w kolejce. Musisz aktualizować setActiveQueueItemId()
przy każdej zmianie w kolejce.
Systemy Android Auto i Android Automotive wyświetlają przyciski dla każdego włączonego działania oraz kolejki odtwarzania. Po kliknięciu przycisków system wywoła odpowiednie wywołanie zwrotne z MediaSessionCompat.Callback
.
Zarezerwuj niewykorzystane miejsce
Android Auto i system operacyjny Android Automotive zarezerwują w interfejsie miejsce na działania ACTION_SKIP_TO_PREVIOUS
i ACTION_SKIP_TO_NEXT
. Jeśli Twoja aplikacja nie obsługuje żadnej z tych funkcji, Android Auto i system operacyjny Android Automotive będą wyświetlać w tym miejscu wszystkie utworzone przez Ciebie działania niestandardowe.
Jeśli nie chcesz wypełniać tych miejsc działaniami niestandardowymi, możesz je zarezerwować. Dzięki temu Android Auto i Android Automotive OS będą pozostawiać puste miejsce, gdy aplikacja nie obsługuje danej funkcji. W tym celu wywołaj metodę setExtras()
z pakietem dodatkowych, który zawiera stałe odpowiadające funkcjom zarezerwowanym.
SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
odpowiada wartości ACTION_SKIP_TO_NEXT
, a SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
odpowiada wartości ACTION_SKIP_TO_PREVIOUS
. Użyj tych stałych jako kluczy w pakiecie, a ich wartości – wartości logicznej true
.
Ustawienie początkowego stanu Odtwarzanie
Gdy Android Auto i Android Automotive OS komunikują się z przeglądarką multimediów, sesja multimediów informuje o stanie odtwarzania treści za pomocą interfejsu PlaybackStateCompat
.
Aplikacja nie powinna automatycznie rozpoczynać odtwarzania muzyki, gdy system operacyjny Android Automotive lub Android Auto połączy się z przeglądarką multimediów. Zamiast tego w zależności od stanu samochodu lub działań użytkownika korzystaj z Androida Auto i systemu operacyjnego Android Automotive.
Aby to zrobić, ustaw początkowy PlaybackStateCompat
sesji multimedialnej na STATE_STOPPED
, STATE_PAUSED
, STATE_NONE
lub STATE_ERROR
.
Sesje multimediów w Androidzie Auto i systemie operacyjnym Android Automotive trwają tylko do końca jazdy, więc użytkownicy często uruchamiają i zatrzymują te sesje. Aby zapewnić płynną obsługę różnych dysków, śledź poprzedni stan sesji użytkownika. Dzięki temu, gdy aplikacja do multimediów otrzyma żądanie wznowienia, będzie mógł automatycznie wznowić odtwarzanie w miejscu, w którym przerwano odtwarzanie – na przykład ostatnio odtwarzany element multimedialny, element PlaybackStateCompat
czy kolejkę.
Dodawanie niestandardowych działań związanych z odtwarzaniem
Możesz dodać niestandardowe działania związane z odtwarzaniem, aby wyświetlać dodatkowe działania obsługiwane przez Twoją aplikację do multimediów. Jeśli miejsce na dane pozwala(i nie jest zarezerwowane), Android dodaje działania niestandardowe do ustawień transportu. W przeciwnym razie działania niestandardowe
wyświetlą się w rozszerzonym menu. Działania niestandardowe są wyświetlane w kolejności, w której zostały dodane do: PlaybackStateCompat
.
Korzystaj z działań niestandardowych, by zapewniać zachowanie różniące się od działań standardowych. Nie używaj ich do zastępowania ani powielania działań standardowych.
Działania niestandardowe możesz dodawać za pomocą metody addCustomAction()
w klasie PlaybackStateCompat.Builder
.
Ten fragment kodu pokazuje, jak dodać niestandardowe działanie „Uruchom kanał radiowy”:
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 w opisie metody setCustomAction()
w przykładowej aplikacji Universal Android Music Player na GitHubie.
Po utworzeniu działania niestandardowego sesja multimediów może zareagować na to działanie, zastępując metodę onCustomAction()
.
Ten fragment kodu pokazuje, jak aplikacja może zareagować 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 w opisie metody onCustomAction
w przykładowej aplikacji Universal Android Music Player na GitHubie.
Ikony działań niestandardowych
Każde utworzone działanie niestandardowe wymaga zasobu ikony. Aplikacje w samochodach mogą działać na ekranach o różnej rozdzielczości i o różnej rozdzielczości, dlatego przesyłane ikony muszą być elementami rysowalnymi w formacie wektorowym. Obiekt rysowalny w formacie wektorowym pozwala skalować zasoby bez utraty szczegółów. Funkcja rysowania wektorowego ułatwia też wyrównywanie krawędzi i rogów do granic pikseli przy mniejszych rozdzielczościach.
Jeśli działanie niestandardowe ma stan stanowy – np. włącza lub wyłącza ustawienie odtwarzania – dostarczaj różne ikony dla poszczególnych stanów. Dzięki temu użytkownicy mogą zobaczyć zmianę po wybraniu tego działania.
Podawanie alternatywnych stylów ikon dla wyłączonych działań
Gdy działanie niestandardowe jest niedostępne w bieżącym kontekście, zamień ikonę działania niestandardowego na inną ikonę wskazującą, że to działanie jest wyłączone.
Wskaż format dźwięku
Aby wskazać, że aktualnie odtwarzane multimedia używają specjalnego formatu dźwięku, możesz określić ikony renderowane w samochodach obsługujących tę funkcję. Możesz ustawić właściwości KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI
i KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI
w pakiecie z dodatkowymi elementami aktualnie odtwarzanego elementu multimedialnego (przekazanego do MediaSession.setMetadata()
). Pamiętaj, aby ustawić oba te elementy dodatkowe, aby dostosować je do różnych układów.
Dodatkowo możesz dodać KEY_IMMERSIVE_AUDIO
, aby poinformować producentów OEM, że jest to dźwięk wciągający. Dlatego powinni oni być bardzo ostrożni przy podejmowaniu decyzji o zastosowaniu efektów dźwiękowych, które mogą zakłócać treści multimedialne.
Dodaj linki z aktualnie odtwarzanego elementu
Możesz skonfigurować aktualnie odtwarzany element multimedialny w taki sposób, aby jego podtytuł i 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. przejść do innych utworów tego samego wykonawcy, do innych odcinków danego podcastu itd. Jeśli samochód obsługuje tę funkcję, użytkownik może kliknąć link, aby przejrzeć te treści.
Aby dodawać linki, skonfiguruj metadane KEY_SUBTITLE_LINK_MEDIA_ID
(linki z podtytułu) lub KEY_DESCRIPTION_LINK_MEDIA_ID
(linki z opisu). Szczegółowe informacje na ten temat można znaleźć w dokumentacji tych pól metadanych.
Obsługa komend głosowych
Aplikacja do multimediów musi obsługiwać komendy głosowe, aby kierowcy mogli bezpiecznie i wygodnie korzystać z urządzenia, a jednocześnie ograniczyć rozpraszanie uwagi. Jeśli na przykład aplikacja odtwarza jeden element multimedialny, użytkownik może powiedzieć „Włącz [tytuł utworu]”, aby aplikacja włączyła inny utwór 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-klucze „OK Google”.
Gdy Android Auto lub Android Automotive wykryje i zinterpretuje komendę głosową, jest ona przekazywana do aplikacji przez onPlayFromSearch()
.
Po otrzymaniu wywołania zwrotnego aplikacja znajduje treści pasujące do ciągu query
i rozpoczyna odtwarzanie.
Użytkownicy mogą określać w zapytaniach różne kategorie haseł, np. gatunek, wykonawcę, album, tytuł utworu, stację radiową lub playlistę. Tworząc obsługę wyszukiwania, uwzględnij wszystkie kategorie odpowiednie dla Twojej aplikacji.
Jeśli Android Auto lub Android Automotive wykryje, że dane zapytanie pasuje do
określonych kategorii, doda dodatkowe informacje w parametrze extras
. Można wysłać te dodatki:
Konto zawiera pusty ciąg znaków query
, który może być wysyłany przez system operacyjny Android Auto lub Android Automotive, jeśli użytkownik nie określi wyszukiwanego hasła.
na przykład „Włącz jakąś muzykę”. W takim przypadku aplikacja może włączyć
ostatnio odtwarzany lub proponowany utwór.
Jeśli wyszukiwanie nie może być szybko przetwarzane, nie blokuj wyszukiwania w onPlayFromSearch()
.
Zamiast tego ustaw stan odtwarzania na STATE_CONNECTING
i przeprowadź wyszukiwanie w wątku asynchronicznym.
Gdy rozpocznie się odtwarzanie, spróbuj uzupełnić kolejkę sesji multimedialnej odpowiednimi treściami. Jeśli na przykład użytkownik poprosi o odtworzenie albumu, aplikacja może wypełnić kolejkę listą utworów z tego albumu. Rozważ też wdrożenie możliwości przeglądania wyników wyszukiwania, aby użytkownik mógł wybrać inną ścieżkę pasującą do jego zapytania.
Oprócz zapytań „odtwórz” Android Auto i systemy operacyjne Android Automotive rozpoznają zapytania głosowe, aby sterować odtwarzaniem, np. „wstrzymaj muzykę” i „następny utwór”, i dopasowują te polecenia do odpowiednich wywołań zwrotnych sesji multimediów, takich jak onPause()
i onSkipToNext()
.
Szczegółowy przykład implementowania w aplikacji działań związanych z odtwarzaniem z obsługą głosu znajdziesz w artykule o Asystencie Google i aplikacjach do multimediów.
Stosuj środki ochrony rozpraszające uwagę
Telefon użytkownika jest podłączony do głośników samochodu podczas korzystania z Androida Auto, dlatego musisz podjąć dodatkowe środki ostrożności, aby nie rozpraszać kierowcy.
Wyciszanie alarmów w samochodzie
Aplikacje do multimediów na Androidzie Auto nie mogą rozpoczynać odtwarzania dźwięku przez głośniki samochodu, chyba że użytkownik rozpocznie odtwarzanie np. przez naciśnięcie przycisku odtwarzania. Nawet alarm zaplanowany przez użytkownika z aplikacji do multimediów nie może rozpoczynać odtwarzania muzyki przez głośniki samochodu.
Aby spełnić to wymaganie, przed odtworzeniem dźwięku aplikacja może użyć CarConnection
jako sygnału. Aplikacja może sprawdzić, czy telefon wyświetla obraz na ekranie samochodu, obserwując zdarzenie LiveData
jako typ połączenia i sprawdzając, czy ma on wartość CONNECTION_TYPE_PROJECTION
.
Jeśli telefon użytkownika przesyła obraz, aplikacje do multimediów obsługujące alarmy muszą wykonywać jedną z tych czynności:
- Wyłącz alarm.
- Włącz alarm na telefonie
STREAM_ALARM
i udostępniaj interfejs na ekranie telefonu, który umożliwia jego wyłączenie.
Obsługa reklam medialnych
Domyślnie Android Auto wyświetla powiadomienie, gdy metadane multimediów zmienią się podczas sesji odtwarzania dźwięku. Gdy aplikacja do multimediów przełącza się z muzyki na wyświetlanie reklam, wyświetlanie powiadomienia jest rozpraszające. Aby w takim przypadku Android Auto nie mógł wyświetlić powiadomienia, ustaw 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 podaj komunikat o błędzie, korzystając z metody setErrorMessage()
. Listę kodów błędów, których możesz użyć podczas ustawiania komunikatu o błędzie, znajdziesz w sekcji PlaybackStateCompat
.
Komunikaty o błędach muszą być widoczne dla użytkownika i muszą być zlokalizowane w jego bieżącym języku. Android Auto i system operacyjny Android Automotive mogą wyświetlić użytkownikowi komunikat o błędzie.
Jeśli na przykład treść nie jest dostępna w regionie użytkownika, możesz podczas ustawiania tego komunikatu użyć kodu błędu ERROR_CODE_NOT_AVAILABLE_IN_REGION
.
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 telefon, aby naprawić błąd, podaj mu te informacje w wiadomości. Komunikat o błędzie może np. brzmieć „Zaloguj się w aplikacji [nazwa aplikacji]”, a nie „Zaloguj się”.