Mit Android Auto und Android Automotive OS können Sie die Inhalte Ihrer Medien-App Nutzern im Auto zur Verfügung stellen. Eine Medien-App für Autos muss einen Medienbrowserdienst bereitstellen, damit Android Auto und Android Automotive OS oder eine andere App mit einem Medienbrowser Ihre Inhalte finden und anzeigen können.
In diesem Leitfaden wird davon ausgegangen, dass Sie bereits eine Medien-App haben, die Audio auf einem Smartphone abspielt, und dass Ihre Medien-App der Architektur von Android-Medien-Apps entspricht.
In diesem Leitfaden werden die Komponenten von MediaBrowserService
und MediaSession
beschrieben, die deine App benötigt, damit sie unter Android Auto oder Android Automotive OS funktioniert. Nachdem du die zentrale Medieninfrastruktur fertiggestellt hast, kannst du deiner Medien-App die Unterstützung für Android Auto und Android Automotive OS hinzufügen.
Hinweis
- Weitere Informationen finden Sie in der Dokumentation zur Android Media API.
- Weitere Informationen zum Design finden Sie unter Medien-Apps erstellen.
- Sehen Sie sich die in diesem Abschnitt aufgeführten wichtigen Begriffe und Konzepte an.
Wichtige Begriffe und Konzepte
- Medienbrowserdienst
- Ein von deiner Medien-App implementierter Android-Dienst, der der
MediaBrowserServiceCompat
API entspricht. Ihre App verwendet diesen Dienst, um ihre Inhalte zu präsentieren. - Medienbrowser
- Eine API, die von Medien-Apps verwendet wird, um Medienbrowserdienste zu erkennen und ihre Inhalte anzuzeigen. Android Auto und Android Automotive OS verwenden einen Medienbrowser, um den Medienbrowserdienst deiner App zu finden.
- Medienelement
Der Medienbrowser organisiert seine Inhalte in einem Baum aus
MediaItem
-Objekten. Ein Medienelement kann eines oder beide der folgenden Flags haben:FLAG_PLAYABLE
: Gibt an, dass das Element ein Endknoten im Inhaltsbaum ist. Das Element steht für einen einzelnen Soundstream, z. B. einen Titel auf einem Album, ein Kapitel in einem Hörbuch oder eine Folge eines Podcasts.FLAG_BROWSABLE
: gibt an, dass das Element ein Knoten im Inhaltsbaum ist und untergeordnete Elemente hat. Das Element steht beispielsweise für ein Album und die untergeordneten Elemente sind die Songs auf dem Album.
Ein Medienelement, das sowohl durchsucht als auch abgespielt werden kann, funktioniert wie eine Playlist. Sie können das Element selbst auswählen, um alle untergeordneten Elemente abzuspielen, oder die untergeordneten Elemente durchsuchen.
- Fahrzeugoptimiert
Eine Aktivität für eine Android Automotive OS-App, die den Android Automotive OS-Designrichtlinien entspricht. Die Benutzeroberfläche für diese Aktivitäten wird nicht von Android Automotive OS gezeichnet. Daher musst du dafür sorgen, dass deine App den Designrichtlinien entspricht. Dazu gehören in der Regel größere Tippziele und Schriftgrößen, Unterstützung für Tag- und Nachtmodus sowie höhere Kontrastverhältnisse.
Für Fahrzeuge optimierte Benutzeroberflächen dürfen nur angezeigt werden, wenn keine Einschränkungen für die Nutzerfreundlichkeit von Autos gelten, da diese Oberflächen eine längere Aufmerksamkeit oder Interaktion des Nutzers erfordern können. CUXRs sind nicht aktiv, wenn das Auto steht oder parkt, aber immer, wenn es in Bewegung ist.
Sie müssen keine Aktivitäten für Android Auto entwerfen, da Android Auto anhand der Informationen aus Ihrem Medienbrowserdienst eine eigene, für Fahrzeuge optimierte Oberfläche erstellt.
Manifestdateien Ihrer App konfigurieren
Bevor Sie Ihren Media-Browser-Dienst erstellen können, müssen Sie die Manifestdateien Ihrer App konfigurieren.
Medienbrowserdienst deklarieren
Sowohl Android Auto als auch Android Automotive OS stellen über Ihren Medienbrowserdienst eine Verbindung zu Ihrer App her, um Medienelemente zu durchsuchen. Deklariere den Medienbrowserdienst in deinem Manifest, damit Android Auto und Android Automotive OS den Dienst finden und eine Verbindung zu deiner App herstellen können.
Das folgende Code-Snippet zeigt, wie du deinen Media-Browser-Dienst in deinem Manifest deklarierst. Fügen Sie diesen Code in die Manifestdatei für Ihr Android Automotive OS-Modul und in die Manifestdatei für Ihre Smartphone-App ein.
<application>
...
<service android:name=".MyMediaBrowserService"
android:exported="true">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
...
</application>
App-Symbole angeben
Sie müssen App-Symbole angeben, die Android Auto und Android Automotive OS verwenden können, um Ihre App in der System-UI darzustellen. Es sind zwei Symboltypen erforderlich:
- Launcher-Symbol
- Attributionssymbol
Launcher-Symbol
Das Launcher-Symbol steht für Ihre App in der System-UI, z. B. im Launcher und in der Symbolleiste. Mit der folgenden Manifestdeklaration kannst du angeben, dass du das Symbol deiner mobilen App zur Darstellung deiner Auto-Medien-App verwenden möchtest:
<application
...
android:icon="@mipmap/ic_launcher"
...
/>
Wenn Sie ein anderes Symbol als das Ihrer mobilen App verwenden möchten, legen Sie die android:icon
-Eigenschaft für das <service>
-Element Ihres Media-Browser-Dienstes im Manifest fest:
<application>
...
<service
...
android:icon="@mipmap/auto_launcher"
...
/>
</application>
Attributionssymbol
Das Attributionssymbol wird an Stellen verwendet, an denen Medieninhalte Vorrang haben, z. B. auf Medienkarten. Sie können das kleine Symbol für Benachrichtigungen wiederverwenden. Dieses Symbol muss einfarbig sein. Sie können ein Symbol angeben, das für Ihre App verwendet wird, mit der folgenden Manifestdeklaration:
<application>
...
<meta-data
android:name="androidx.car.app.TintableAttributionIcon"
android:resource="@drawable/ic_status_icon" />
...
</application>
Medienbrowserdienst erstellen
Sie erstellen einen Medienbrowserdienst, indem Sie die Klasse MediaBrowserServiceCompat
erweitern. Sowohl Android Auto als auch Android Automotive OS können Ihren Dienst dann für Folgendes verwenden:
- Durchsuchen Sie die Inhaltshierarchie Ihrer App, um den Nutzern ein Menü anzuzeigen.
- Rufe das Token für das
MediaSessionCompat
-Objekt deiner App ab, um die Audiowiedergabe zu steuern.
Sie können Ihren Medienbrowserdienst auch verwenden, um anderen Clients den Zugriff auf Medieninhalte aus Ihrer App zu ermöglichen. Diese Medienclients können andere Apps auf dem Smartphone eines Nutzers oder andere Remote-Clients sein.
Workflow für Medienbrowserdienste
In diesem Abschnitt wird beschrieben, wie Android Automotive OS und Android Auto während eines typischen Nutzerworkflows mit Ihrem Media-Browserdienst interagieren.
- Der Nutzer startet Ihre App unter Android Automotive OS oder Android Auto.
- Android Automotive OS oder Android Auto kontaktiert den Media-Browserdienst Ihrer App über die Methode
onCreate()
. Bei der Implementierung deronCreate()
-Methode müssen Sie einMediaSessionCompat
-Objekt und sein Callback-Objekt erstellen und registrieren. - Android Automotive OS oder Android Auto ruft die Methode
onGetRoot()
Ihres Dienstes auf, um das Stammmedienelement in Ihrer Inhaltshierarchie abzurufen. Das Stammmedienelement wird nicht angezeigt, sondern dient dazu, weitere Inhalte aus Ihrer App abzurufen. - Android Automotive OS oder Android Auto ruft die Methode
onLoadChildren()
deines Dienstes auf, um die untergeordneten Elemente des Stammmediumelements abzurufen. In Android Automotive OS und Android Auto werden diese Medienelemente als oberste Ebene der Inhaltselemente angezeigt. Weitere Informationen darüber, was das System auf dieser Ebene erwartet, finden Sie unter Stammmenü strukturieren auf dieser Seite. - Wenn der Nutzer ein suchbares Medienelement auswählt, wird die
onLoadChildren()
-Methode deines Dienstes noch einmal aufgerufen, um die untergeordneten Elemente des ausgewählten Menüpunkts abzurufen. - Wenn der Nutzer ein abspielbares Medienelement auswählt, ruft Android Automotive OS oder Android Auto die entsprechende Callback-Methode für Mediensitzungen auf, um diese Aktion auszuführen.
- Wenn von Ihrer App unterstützt, kann der Nutzer auch in Ihren Inhalten suchen. In diesem Fall ruft Android Automotive OS oder Android Auto die Methode
onSearch()
Ihres Dienstes auf.
Inhaltshierarchie erstellen
Android Auto und Android Automotive OS rufen den Medienbrowserdienst Ihrer App auf, um herauszufinden, welche Inhalte verfügbar sind. Dazu müssen Sie in Ihrem Media-Browser-Dienst zwei Methoden implementieren: onGetRoot()
und onLoadChildren()
.
onGetRoot implementieren
Die Methode onGetRoot()
Ihres Dienstes gibt Informationen zum Stammknoten der Inhaltshierarchie zurück.
Android Auto und Android Automotive OS verwenden diesen Root-Knoten, um den Rest deiner Inhalte mit der Methode onLoadChildren()
anzufordern.
Das folgende Code-Snippet zeigt eine einfache Implementierung der Methode 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); }
Ein ausführlicheres Beispiel für diese Methode finden Sie in der Methode onGetRoot()
in der Beispiel-App „Universal Android Music Player“ auf GitHub.
Paketvalidierung für onGetRoot() hinzufügen
Wenn die onGetRoot()
-Methode Ihres Dienstes aufgerufen wird, übergibt das aufrufende Paket identifizierende Informationen an Ihren Dienst. Anhand dieser Informationen kann Ihr Dienst entscheiden, ob das Paket auf Ihre Inhalte zugreifen kann. Du kannst beispielsweise den Zugriff auf den Inhalt deiner App auf eine Liste genehmigter Pakete beschränken. Dazu vergleichst du die clientPackageName
mit deiner Zulassungsliste und bestätigst das Zertifikat, mit dem das APK des Pakets signiert wurde. Wenn das Paket nicht bestätigt werden kann, geben Sie null
zurück, um den Zugriff auf Ihre Inhalte zu verweigern.
Damit System-Apps wie Android Auto und Android Automotive OS Zugriff auf deine Inhalte erhalten können, muss dein Dienst immer eine BrowserRoot
ungleich null zurückgeben, wenn diese System-Apps die Methode onGetRoot()
aufrufen. Die Signatur der Android Automotive OS-System-App kann je nach Marke und Modell des Autos variieren. Sie müssen daher Verbindungen von allen System-Apps zulassen, um Android Automotive OS zuverlässig zu unterstützen.
Das folgende Code-Snippet zeigt, wie Ihr Dienst prüfen kann, ob es sich beim aufrufenden Paket um eine System-App handelt:
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
}
Dieses Code-Snippet ist ein Auszug aus der Klasse PackageValidator
in der Beispielanwendung „Universal Android Music Player“ auf GitHub. In dieser Klasse finden Sie ein detaillierteres Beispiel dafür, wie Sie die Paketvalidierung für die Methode onGetRoot()
Ihres Dienstes implementieren.
Sie müssen nicht nur System-Apps zulassen, sondern auch Google Assistant erlauben, eine Verbindung zu Ihrem MediaBrowserService
herzustellen. Google Assistant hat separate Paketnamen für das Smartphone, z. B. für Android Auto und für Android Automotive OS.
onLoadChildren() implementieren
Nachdem Android Auto und Android Automotive OS das Stammknotenobjekt erhalten haben, erstellen sie ein Menü der obersten Ebene, indem sie onLoadChildren()
auf das Stammknotenobjekt aufrufen, um seine untergeordneten Elemente abzurufen. Client-Apps erstellen Untermenüs, indem sie dieselbe Methode mit untergeordneten Knotenobjekten aufrufen.
Jeder Knoten in Ihrer Inhaltshierarchie wird durch ein MediaBrowserCompat.MediaItem
-Objekt dargestellt. Jedes dieser Medienelemente wird durch einen eindeutigen ID-String identifiziert. Client-Apps behandeln diese ID-Strings als intransparente Tokens. Wenn eine Client-App ein Untermenü aufrufen oder ein Medienelement abspielen möchte, gibt sie das Token weiter. Ihre Anwendung ist dafür verantwortlich, das Token mit dem entsprechenden Medienelement zu verknüpfen.
Das folgende Code-Snippet zeigt eine einfache Implementierung der Methode 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); }
Ein vollständiges Beispiel für diese Methode finden Sie in der Methode onLoadChildren()
in der Beispiel-App „Universal Android Music Player“ auf GitHub.
Stammmenü strukturieren
Android Auto und Android Automotive OS haben spezifische Einschränkungen hinsichtlich der Struktur des Stammmenüs. Diese werden über Root-Hinweise an die MediaBrowserService
gesendet, die über das Argument Bundle
gelesen werden können, das an onGetRoot()
übergeben wird.
Wenn Sie diesen Hinweisen folgen, kann das System die Stamminhalte optimal als Navigationsleisten anzeigen. Wenn Sie diese Hinweise nicht beachten, werden einige Stamminhalte möglicherweise vom System entfernt oder weniger sichtbar gemacht. Es werden zwei Hinweise gesendet:
- Ein Limit für die Anzahl der untergeordneten Knoten des Stammknotens: In den meisten Fällen ist diese Zahl vier. Das bedeutet, dass nicht mehr als vier Tabs angezeigt werden können.
- Unterstützte Flags für untergeordnete Elemente des Stammknotens: Dieser Wert sollte
MediaItem#FLAG_BROWSABLE
sein. Das bedeutet, dass nur Elemente, die sich durchsuchen lassen, und keine abspielbaren Elemente als Tabs angezeigt werden können.
Verwenden Sie den folgenden Code, um die relevanten Stammhinweise zu lesen:
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... }
Du kannst die Logik für die Struktur deiner Inhaltshierarchie basierend auf den Werten dieser Hinweise verzweigen. Das gilt insbesondere, wenn sich deine Hierarchie zwischen MediaBrowser
-Integrationen außerhalb von Android Auto und Android Automotive OS unterscheidet.
Wenn du beispielsweise normalerweise ein übergeordnetes abspielbares Element darstellst, solltest du es aufgrund des Werts des Hinweises zu unterstützten Flags stattdessen in einem übergeordneten durchsuchbaren Element verschachteln.
Neben den Stammhinweisen gibt es einige weitere Richtlinien, die Sie beachten sollten, damit Tabs optimal gerendert werden:
- Verwenden Sie für jedes Tabelement einfarbige, vorzugsweise weiße Symbole.
- Geben Sie für jedes Tabelement kurze, aber aussagekräftige Labels an. Bei kurzen Labels verringert sich die Wahrscheinlichkeit, dass Strings abgeschnitten werden.
Media-Artwork anzeigen
Artwork für Medienelemente muss als lokaler URI mit ContentResolver.SCHEME_CONTENT
oder ContentResolver.SCHEME_ANDROID_RESOURCE
übergeben werden.
Dieser lokale URI muss in den Ressourcen der Anwendung entweder auf eine Bitmap oder ein Vektor-Zeichnen verweisen. Für MediaDescriptionCompat
-Objekte, die Elemente in der Inhaltshierarchie darstellen, übergeben Sie den URI über setIconUri()
.
Übergeben Sie bei MediaMetadataCompat
-Objekten, die das gerade wiedergegebene Element darstellen, den URI mit einem der folgenden Schlüssel über putString()
:
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI
MediaMetadataCompat.METADATA_KEY_ART_URI
MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI
In den folgenden Schritten wird beschrieben, wie du Artwork über einen Web-URI herunterlädst und über einen lokalen URI verfügbar machst. Ein vollständigeres Beispiel findest du in der Implementierung von openFile()
und den zugehörigen Methoden in der Beispiel-App „Universal Android Music Player“.
Erstellen Sie einen
content://
-URI, der dem Web-URI entspricht. Der Medienbrowserdienst und die Mediensitzung geben diesen Inhalts-URI an Android Auto und Android Automotive OS weiter.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(); }
Prüfen Sie in Ihrer Implementierung von
ContentProvider.openFile()
, ob für den entsprechenden URI eine Datei vorhanden ist. Andernfalls laden Sie die Bilddatei herunter und speichern Sie sie im Cache. Im folgenden Code-Snippet wird Glide verwendet.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); }
Weitere Informationen zu Inhaltsanbietern finden Sie unter Inhaltsanbieter erstellen.
Inhaltsstile anwenden
Nachdem Sie Ihre Inhaltshierarchie mit durchsuchbaren oder abspielbaren Elementen erstellt haben, können Sie Inhaltsstile anwenden, die festlegen, wie diese Elemente im Auto angezeigt werden.
Sie können die folgenden Inhaltsstile verwenden:
- Listenelemente
-
Bei diesem Inhaltsstil haben Titel und Metadaten Vorrang vor Bildern.
- Rasterelemente
-
Bei diesem Inhaltsstil haben Bilder Vorrang vor Titeln und Metadaten.
Standardinhaltsstile festlegen
Du kannst globale Standardeinstellungen für die Darstellung deiner Medienelemente festlegen, indem du bestimmte Konstanten in das BrowserRoot
-Extras-Bundle der onGetRoot()
-Methode deines Dienstes aufnimmst. Android Auto und Android Automotive OS lesen dieses Paket und suchen nach diesen Konstanten, um den passenden Stil zu bestimmen.
Die folgenden Extras können als Schlüssel im Bundle verwendet werden:
DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
: Gibt einen Darstellungshinweis für alle durchsuchbaren Elemente im Navigationsbaum an.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
: gibt einen Präsentationshinweis für alle abspielbaren Elemente im Suchbaum an
Die Schlüssel können den folgenden Ganzzahlkonstantenwerten zugeordnet werden, um die Darstellung dieser Elemente zu beeinflussen:
DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM
: Die entsprechenden Elemente werden als Listenelemente dargestellt.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM
: Die entsprechenden Elemente werden als Rasterelemente dargestellt.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM
: Die entsprechenden Elemente werden als Listenelemente der Kategorie angezeigt. Dies entspricht den normalen Listenelementen, mit dem Unterschied, dass Ränder um die Symbole der Elemente herum angewendet werden, da die Symbole auf kleinen Werten besser aussehen. Die Symbole müssen färbbare Vektor-Drawables sein. Dieser Hinweis wird voraussichtlich nur für Elemente angezeigt, die sich durchsuchen lassen.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM
: Die entsprechenden Elemente werden als Rasterelemente der Kategorie angezeigt. Diese Elemente ähneln normalen Rasterelementen, mit dem Unterschied, dass um die Symbole der Elemente Ränder angewendet werden, da sie bei kleiner Größe besser aussehen. Die Symbole müssen färbbare Vektor-Drawables sein. Dieser Hinweis wird nur für blätterbare Elemente angezeigt.
Im folgenden Code-Snippet wird gezeigt, wie Sie den Standardinhaltsstil für suchbare Elemente auf „Raster“ und für abspielbare Elemente auf „Listen“ festlegen:
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); }
Inhaltsstile pro Artikel festlegen
Mit der Content Style API kannst du den Standardinhaltsstil für alle untergeordneten Elemente eines suchbaren Medienelements sowie für das Medienelement selbst überschreiben.
Wenn du die Standardeinstellung für die untergeordneten Elemente eines suchbaren Medienelements überschreiben möchtest, erstelle ein Extras-Bundle in der MediaDescription
des Medienelements und füge dieselben bereits erwähnten Hinweise hinzu. DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
gilt für die spielbaren untergeordneten Elemente dieses Objekts und DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
für die durchsuchbaren untergeordneten Elemente dieses Elements.
Wenn Sie die Standardeinstellung selbst und nicht für die untergeordneten Elemente überschreiben möchten, erstellen Sie ein Extras-Bundle im MediaDescription
des Medienelements und fügen Sie einen Hinweis mit dem Schlüssel DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM
hinzu.
Verwenden Sie die oben beschriebenen Werte, um die Darstellung dieses Artikels anzugeben.
Das folgende Code-Snippet zeigt, wie eine durchsuchbare MediaItem
erstellt wird, die den Standardinhaltsstil sowohl für sich selbst als auch für ihre untergeordneten Elemente überschreibt. Es wird als Kategorielistenelement, seine durchsuchbaren untergeordneten Elemente als Listenelemente und seine abspielbaren untergeordneten Elemente als Rasterelemente dargestellt:
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); }
Elemente mithilfe von Titelhinweisen gruppieren
Wenn du ähnliche Medienelemente gruppieren möchtest, verwendest du einen Hinweis pro Element. Für jedes Medienelement in einer Gruppe muss in der MediaDescription
ein Extras-Bundle deklariert werden, das eine Zuordnung mit dem Schlüssel DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE
und einem identischen Stringwert enthält. Lokalisieren Sie diesen String, der als Titel der Gruppe verwendet wird.
Im folgenden Code-Snippet wird gezeigt, wie ein MediaItem
mit der Überschrift "Songs"
für eine Untergruppe erstellt wird:
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*/); }
Deine App muss alle Medienelemente übergeben, die du als zusammenhängenden Block gruppieren möchtest. Angenommen, Sie möchten zwei Gruppen von Medienelementen, "Titel" und "Alben", in dieser Reihenfolge anzeigen und Ihre App übergibt fünf Medienelemente in der folgenden Reihenfolge:
- Medienelement A mit
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- Medienelement B mit
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
- Medienelement C mit
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- Medienelement D mit
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- Medienelement E mit
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
Da die Medienelemente für die Gruppen „Songs“ und „Alben“ nicht in zusammenhängenden Blöcken zusammengehalten sind, werden dies von Android Auto und Android Automotive OS als die folgenden vier Gruppen interpretiert:
- Gruppe 1 namens „Titel“, die Medienelement A enthalten
- Gruppe 2 mit dem Namen „Alben“ mit dem Medienelement B
- Gruppe 3 mit dem Namen „Songs“ mit den Medienelementen C und D
- Gruppe 4 mit dem Namen „Alben“ mit dem Medienelement E
Wenn diese Elemente in zwei Gruppen angezeigt werden sollen, muss Ihre App die Medienelemente stattdessen in der folgenden Reihenfolge übergeben:
- Medienelement A mit
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- Medienelement C mit
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- Medienelement D mit
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- Medienelement B mit
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
- Medienelement E mit
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
Zusätzliche Metadaten-Indikatoren anzeigen
Du kannst zusätzliche Metadaten-Indikatoren einfügen, um Informationen zu Inhalten im Media-Browser-Baum und während der Wiedergabe auf einen Blick verfügbar zu machen. Im Navigationsbaum lesen Android Auto und Android Automotive OS die mit einem Artikel verknüpften Extras und suchen nach bestimmten Konstanten, um zu bestimmen, welche Indikatoren angezeigt werden sollen. Während der Medienwiedergabe lesen Android Auto und Android Automotive OS die Metadaten für die Mediensitzung und suchen nach bestimmten Konstanten, um die anzuzeigenden Indikatoren zu bestimmen.
Die folgenden Konstanten können sowohl in MediaItem
-Beschreibungselementen als auch in MediaMetadata
-Elementen verwendet werden:
EXTRA_DOWNLOAD_STATUS
: gibt den Downloadstatus eines Elements an. Verwenden Sie diese Konstante als Schlüssel. Die folgenden langen Konstanten sind die möglichen Werte:STATUS_DOWNLOADED
: Der Artikel ist vollständig heruntergeladen.STATUS_DOWNLOADING
: Das Element wird heruntergeladen.STATUS_NOT_DOWNLOADED
: Der Artikel wird nicht heruntergeladen.
METADATA_KEY_IS_EXPLICIT
: gibt an, ob das Element explizite Inhalte enthält. Wenn ein Element explizit angegeben werden soll, verwenden Sie diese Konstante als Schlüssel und den langenMETADATA_VALUE_ATTRIBUTE_PRESENT
als Wert.
Die folgenden Konstanten können nur in MediaItem
-Beschreibungsextras verwendet werden:
DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS
: Gibt den Wiedergabestatus von Inhalten im Langformat an, z. B. von Podcastfolgen oder Hörbüchern. Verwenden Sie diese Konstante als Schlüssel. Die folgenden Ganzzahlkonstanten sind die möglichen Werte:DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED
: Der Artikel wurde noch nicht abgespielt.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED
: Der Artikel wurde teilweise wiedergegeben und die aktuelle Position liegt in der Mitte.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED
: Das Element ist abgeschlossen.
DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
: Gibt den Fortschritt bei der Wiedergabe von Inhalten im Langformat als Doppelt-Wert zwischen 0,0 und 1,0 an. Dieses zusätzliche Element bietet weitere Informationen zumPARTIALLY_PLAYING
-Status, damit Android Auto oder Android Automotive OS eine aussagekräftigere Fortschrittsanzeige, z. B. eine Statusleiste, anzeigen können. Wenn du dieses Extra verwendest, findest du in diesem Leitfaden im Abschnitt Fortschrittsanzeige in der Wiedergabeansicht während der Wiedergabe aktualisieren Informationen dazu, wie du diesen Indikator nach dem ersten Eindruck auf dem neuesten Stand halten kannst.
Wenn du Indikatoren anzeigen möchtest, die angezeigt werden, während der Nutzer im Medien-Browse-Tree stöbert, erstelle ein Extras-Bundle mit einer oder mehreren dieser Konstanten und übergebe dieses Bundle an die MediaDescription.Builder.setExtras()
-Methode.
Im folgenden Code-Snippet wird gezeigt, wie Indikatoren für ein explizites Medienelement angezeigt werden, das zu 70% fertig ist:
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 */);
Wenn Indikatoren für ein Medienelement angezeigt werden sollen, das gerade abgespielt wird, kannst du in den MediaMetadataCompat
deiner mediaSession
Long
-Werte für METADATA_KEY_IS_EXPLICIT
oder EXTRA_DOWNLOAD_STATUS
deklarieren. Die Anzeige DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS
oder DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
kann nicht in der Wiedergabeansicht eingeblendet werden.
Das folgende Code-Snippet zeigt, wie angegeben wird, dass der aktuelle Titel in der Wiedergabeansicht explizit ist und heruntergeladen wurde:
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());
Fortschrittsanzeige in der Wiedergabeansicht während der Wiedergabe aktualisieren
Wie bereits erwähnt, kannst du mit dem Extra DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
eine Fortschrittsanzeige für teilweise abgespielte Inhalte in der Suche anzeigen lassen. Gibt ein Nutzer jedoch weiterhin die teilweise abgespielten Inhalte aus Android Auto oder Android Automotive OS wieder, wird diese Anzeige im Laufe der Zeit ungenau.
Damit die Fortschrittsanzeige in Android Auto und Android Automotive OS immer auf dem neuesten Stand ist, kannst du unter MediaMetadataCompat
und PlaybackStateCompat
zusätzliche Informationen angeben, um aktuelle Inhalte mit Medienelementen in der Ansicht „Suchen“ zu verknüpfen. Damit das Medienelement eine automatisch aktualisierte Fortschrittsanzeige hat, müssen die folgenden Anforderungen erfüllt sein:
- Beim Erstellen muss die
MediaItem
ihre Extras mit einem Wert zwischen 0, 0 und 1, 0 senden.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
MediaMetadataCompat
mussMETADATA_KEY_MEDIA_ID
mit einem Stringwert senden, der der Media-ID entspricht, die anMediaItem
übergeben wurde.PlaybackStateCompat
muss ein Extra mit dem SchlüsselPLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID
enthalten, das einem Stringwert entspricht, der der Medien-ID entspricht, die anMediaItem
übergeben wurde.
Im folgenden Code-Snippet wird gezeigt, wie angegeben wird, dass das gerade wiedergegebene Element mit einem Element in der Ansicht „Suchen“ verknüpft ist:
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());
Suchergebnisse anzeigen, die sich durchsuchen lassen
Ihre App kann kontextbezogene Suchergebnisse bereitstellen, die Nutzern angezeigt werden, wenn sie eine Suchanfrage starten. In Android Auto und Android Automotive OS werden diese Ergebnisse über Suchanfrageoberflächen oder über Funktionen angezeigt, die sich auf Suchanfragen beziehen, die zuvor in der Sitzung gestellt wurden. Weitere Informationen finden Sie in diesem Leitfaden im Abschnitt Sprachaktionen unterstützen.
Wenn Sie durchsuchbare Suchergebnisse anzeigen möchten, fügen Sie den Konstantenschlüssel BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED
in das Extras-Bundle der onGetRoot()
-Methode Ihres Dienstes ein und ordnen Sie ihn dem booleschen Wert true
zu.
Das folgende Code-Snippet zeigt, wie Sie die Unterstützung in der Methode onGetRoot()
aktivieren:
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); }
Wenn du Suchergebnisse bereitstellen möchtest, überschreibe die Methode onSearch()
in deinem Media-Browser-Dienst. Android Auto und Android Automotive OS leiten die Suchbegriffe des Nutzers an diese Methode weiter, wenn ein Nutzer eine Suchanfrageoberfläche oder die Option „Suchergebnisse“ aufruft.
Sie können die Suchergebnisse aus der onSearch()
-Methode Ihres Dienstes mithilfe von title items (Titelelemente) organisieren, um sie besser durchsuchbar zu machen. Wenn Ihre App beispielsweise Musik abspielt, können Sie die Suchergebnisse nach Album, Künstler und Titeln sortieren.
Das folgende Code-Snippet zeigt eine einfache Implementierung der Methode 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. }
Benutzerdefinierte Suchaktionen
Mit benutzerdefinierten Suchaktionen können Sie den MediaItem
-Objekten Ihrer App in der Media-App des Autos benutzerdefinierte Symbole und Labels hinzufügen und Nutzerinteraktionen mit diesen Aktionen verarbeiten. Dadurch können Sie die Funktionalität der Medien-App auf verschiedene Arten erweitern, z. B. durch Hinzufügen von Aktionen wie „Herunterladen“, „In die Wiedergabeliste“, „Radio abspielen“, „Favoriten“ oder „Entfernen“.
Wenn mehr benutzerdefinierte Aktionen vorhanden sind, als vom OEM angezeigt werden dürfen, wird dem Nutzer ein Überlaufmenü angezeigt.
So funktioniert es:
Jede benutzerdefinierte Suchaktion wird wie folgt definiert:
- Eine Aktions-ID (eine eindeutige String-Kennung)
- Ein Aktionslabel (der Text, der dem Nutzer angezeigt wird)
- URI für ein Aktionssymbol (ein Vektor-Drawable, das gefärbt werden kann)
Sie definieren eine Liste benutzerdefinierter Suchaktionen global als Teil Ihrer BrowseRoot
. Anschließend können Sie eine Teilmenge dieser Aktionen einzelnen MediaItem.
Wenn ein Nutzer mit einer benutzerdefinierten Suchaktion interagiert, erhält Ihre App einen Callback in onCustomAction()
. Sie können die Aktion dann bearbeiten und die Liste der Aktionen für die MediaItem
bei Bedarf aktualisieren. Das ist nützlich für zustandsorientierte Aktionen wie „Zu Favoriten hinzufügen“ und „Herunterladen“. Für Aktionen, die nicht aktualisiert werden müssen, z. B. „Radio abspielen“, müssen Sie die Liste der Aktionen nicht aktualisieren.
Sie können benutzerdefinierte Suchaktionen auch an den Stamm eines Navigationsknotens anhängen. Diese Aktionen werden in einer sekundären Symbolleiste unter der Hauptsymbolleiste angezeigt.
Benutzerdefinierte Suchaktionen implementieren
So fügen Sie Ihrem Projekt benutzerdefinierte Suchaktionen hinzu:
- Überschreiben Sie zwei Methoden in Ihrer
MediaBrowserServiceCompat
-Implementierung: - Aktionslimits zur Laufzeit analysieren:
- Rufen Sie in
onGetRoot()
die maximal zulässige Anzahl von Aktionen für jedeMediaItem
mit dem SchlüsselBROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT
inrootHints
Bundle
ab. Ein Limit von 0 gibt an, dass die Funktion vom System nicht unterstützt wird.
- Rufen Sie in
- Erstellen Sie die globale Liste der benutzerdefinierten Suchaktionen:
- Erstellen Sie für jede Aktion ein
Bundle
-Objekt mit den folgenden Schlüsseln: *EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID
: der Aktions-ID *EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL
: dem Aktionslabel *EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI
: dem Aktionssymbol-URI * Fügen Sie alleBundle
-Aktionsobjekte einer Liste hinzu.
- Erstellen Sie für jede Aktion ein
- Fügen Sie die globale Liste Ihrem
BrowseRoot
hinzu:- Fügen Sie die Liste der Aktionen in den
BrowseRoot
-Extras alsBundle
mit dem SchlüsselBROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST
alsParcelable
-Arraylist
hinzu.
- Fügen Sie die Liste der Aktionen in den
- Fügen Sie Ihren
MediaItem
-Objekten Aktionen hinzu:- Du kannst einzelnen
MediaItem
-Objekten Aktionen hinzufügen, indem du die Liste der Aktions-IDs mit dem SchlüsselDESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST
in dieMediaDescriptionCompat
-Extras einfügst. Diese Liste muss eine Teilmenge der globalen Liste von Aktionen sein, die Sie inBrowseRoot
definiert haben.
- Du kannst einzelnen
- Aktionen verarbeiten und Fortschritt oder Ergebnisse zurückgeben:
- Behandle in
onCustomAction
die Aktion anhand der Aktions-ID und aller anderen erforderlichen Daten. Die ID derMediaItem
, die die Aktion ausgelöst hat, kannst du über den SchlüsselEXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID
aus den Extras abrufen. - Sie können die Liste der Aktionen für eine
MediaItem
aktualisieren, indem Sie den SchlüsselEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
in das Fortschritts- oder Ergebnis-Bundle aufnehmen.
- Behandle in
Hier sind einige Änderungen, die Sie in Ihrer BrowserServiceCompat
vornehmen können, um mit benutzerdefinierten Suchaktionen zu beginnen.
BrowserServiceCompat überschreiben
Sie müssen die folgenden Methoden in MediaBrowserServiceCompat
überschreiben.
public void onLoadItem(String itemId, @NonNull Result<MediaBrowserCompat.MediaItem> result)
public void onCustomAction(@NonNull String action, Bundle extras, @NonNull Result<Bundle> result)
Limit für Parseaktionen
Sie sollten prüfen, wie viele benutzerdefinierte Suchaktionen unterstützt werden.
public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, Bundle rootHints) { rootHints.getInt( MediaConstants.BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT, 0) }
Benutzerdefinierte Suchaktion erstellen
Jede Aktion muss in einer separaten Bundle
zusammengefasst werden.
- Aktions-ID
bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID, "<ACTION_ID>")
- Aktionslabel
bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL, "<ACTION_LABEL>")
- URI für Aktionssymbol
bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI, "<ACTION_ICON_URI>")
Benutzerdefinierte Suchaktionen zu Parceable
ArrayList
hinzufügen
Fügen Sie alle Objekte vom Typ „Benutzerdefinierte Suchaktion“ Bundle
zu einem ArrayList
hinzu.
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; }
Dem Stammverzeichnis für die Suche die Liste „Benutzerdefinierte Suchaktionen“ hinzufügen
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; }
Aktionen zu einer MediaItem
hinzufügen
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);
onCustomAction
-Ergebnis erstellen
- mediaId von
Bundle extras
parsen:@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); }
- Bei asynchronen Ergebnissen das Ergebnis trennen.
result.detach()
- Build-Ergebnis-Bundle
- Nachricht an den Nutzer
mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE, mContext.getString(stringRes))
- Artikel aktualisieren(zum Aktualisieren von Aktionen in einem Artikel)
mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM, mediaId);
- Wiedergabeansicht öffnen
//Shows user the PBV without changing the playback state mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_SHOW_PLAYING_ITEM, null);
- Knoten „Browse“ aktualisieren
//Change current browse node to mediaId mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE, mediaId);
- Nachricht an den Nutzer
- Bei einem Fehler
result.sendError(resultBundle).
anrufen - Wenn die Aktualisierung voranschreitet, rufen Sie
result.sendProgressUpdate(resultBundle)
auf. - Rufen Sie abschließend
result.sendResult(resultBundle)
an.
Aktionsstatus aktualisieren
Mit der Methode result.sendProgressUpdate(resultBundle)
und dem Schlüssel EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
können Sie MediaItem
aktualisieren, um den neuen Status der Aktion widerzuspiegeln. So können Sie Nutzern in Echtzeit Feedback zum Fortschritt und Ergebnis ihrer Aktion geben.
Beispiel: Downloadaktion
Hier ein Beispiel dafür, wie Sie mit dieser Funktion eine Downloadaktion mit drei Status implementieren können:
- Herunterladen: Dies ist der Anfangsstatus der Aktion. Wenn der Nutzer diese Aktion auswählt, kannst du sie durch „Herunterladen“ ersetzen und
sendProgressUpdate
aufrufen, um die Benutzeroberfläche zu aktualisieren. - Herunterladen: Dieser Status gibt an, dass der Download gerade ausgeführt wird. Sie können diesen Status verwenden, um dem Nutzer eine Fortschrittsanzeige oder einen anderen Indikator zu zeigen.
- Heruntergeladen: Dieser Status gibt an, dass der Download abgeschlossen ist. Wenn der Download abgeschlossen ist, können Sie „Herunterladen“ durch „Heruntergeladen“ ersetzen und
sendResult
mit der TasteEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
aufrufen, um anzugeben, dass das Element aktualisiert werden soll. Außerdem kannst du den SchlüsselEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE
verwenden, um dem Nutzer eine Erfolgsmeldung anzuzeigen.
So können Sie den Nutzern klares Feedback zum Downloadprozess und seinem aktuellen Status geben. Mit Symbolen können Sie noch mehr Details hinzufügen, um den Downloadstatus bei 25%, 50 % und 75% anzuzeigen.
Beispiel: Lieblingsaktion
Ein weiteres Beispiel ist eine Lieblingsaktion mit zwei Status:
- Favoriten: Diese Aktion wird für Elemente angezeigt, die nicht in der Favoritenliste des Nutzers enthalten sind. Wenn der Nutzer diese Aktion auswählt, kannst du sie durch „Zu Favoriten hinzugefügt“ ersetzen und
sendResult
mit der TasteEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
aufrufen, um die Benutzeroberfläche zu aktualisieren. - Zu Favoriten hinzugefügt: Diese Aktion wird für Elemente angezeigt, die sich in der Favoritenliste des Nutzers befinden. Wenn der Nutzer diese Aktion auswählt, kannst du sie durch „Favoriten“ ersetzen und
sendResult
mit der TasteEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
aufrufen, um die Benutzeroberfläche zu aktualisieren.
Dieser Ansatz bietet Nutzern eine klare und einheitliche Möglichkeit, ihre Lieblingselemente zu verwalten.
Diese Beispiele zeigen die Flexibilität benutzerdefinierter Suchaktionen und wie Sie damit eine Vielzahl von Funktionen mit Echtzeitfeedback implementieren können, um die Nutzerfreundlichkeit in der Medien-App des Autos zu verbessern.
Eine vollständige Beispielimplementierung dieser Funktion finden Sie im Projekt TestMediaApp
.
Wiedergabesteuerung aktivieren
Android Auto und Android Automotive OS senden Befehle zur Wiedergabesteuerung über die MediaSessionCompat
Ihres Dienstes.
Sie müssen eine Sitzung registrieren und die zugehörigen Callback-Methoden implementieren.
Mediensitzung registrieren
Erstelle in der Methode onCreate()
deines Media-Browser-Dienstes eine MediaSessionCompat
und registriere die Mediensitzung durch Aufrufen von setSessionToken()
.
Das folgende Code-Snippet zeigt, wie eine Mediensitzung erstellt und registriert wird:
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()); ... }
Wenn Sie das Mediensitzungsobjekt erstellen, legen Sie ein Callback-Objekt fest, das zur Verarbeitung von Anfragen zur Wiedergabesteuerung verwendet wird. Sie erstellen dieses Callback-Objekt, indem Sie eine Implementierung der Klasse MediaSessionCompat.Callback
für Ihre App bereitstellen. Im nächsten Abschnitt wird beschrieben, wie Sie dieses Objekt implementieren.
Wiedergabebefehle implementieren
Wenn ein Nutzer die Wiedergabe eines Medienelements aus deiner App anfordert, verwenden Android Automotive OS und Android Auto die Klasse MediaSessionCompat.Callback
aus dem MediaSessionCompat
-Objekt deiner App, die sie vom Medienbrowserdienst deiner App abgerufen haben. Wenn ein Nutzer die Wiedergabe von Inhalten steuern möchte, also z. B. die Wiedergabe pausieren oder zum nächsten Titel springen möchte, rufen Android Auto und Android Automotive OS eine der Methoden des Callback-Objekts auf.
Damit die Wiedergabe von Inhalten funktioniert, muss Ihre App die abstrakte Klasse MediaSessionCompat.Callback
erweitern und die von Ihrer App unterstützten Methoden implementieren.
Implementiere alle folgenden Callback-Methoden, die für den Inhaltstyp deiner App sinnvoll sind:
onPrepare()
- Wird aufgerufen, wenn sich die Medienquelle ändert. Android Automotive OS ruft diese Methode ebenfalls sofort nach dem Booten auf. Diese Methode muss in Ihrer Medien-App implementiert sein.
onPlay()
- Wird aufgerufen, wenn der Nutzer „Wiedergabe“ auswählt, ohne einen bestimmten Titel auszuwählen. Ihre App muss die Standardinhalte wiedergeben. Wenn die Wiedergabe mit
onPause()
pausiert wurde, wird sie fortgesetzt.Hinweis:Ihre App sollte nicht automatisch mit der Wiedergabe von Musik beginnen, wenn Android Automotive OS oder Android Auto eine Verbindung zu Ihrem Medienbrowserdienst herstellt. Weitere Informationen finden Sie im Abschnitt zum Festlegen des anfänglichen Wiedergabestatus.
onPlayFromMediaId()
- Wird aufgerufen, wenn der Nutzer einen bestimmten Artikel abspielen möchte. Der Methode wird die ID übergeben, die dein Media-Browser-Dienst dem Medienelement in deiner Inhaltshierarchie zugewiesen hat.
onPlayFromSearch()
- Wird aufgerufen, wenn der Nutzer sich für eine Suchanfrage entscheidet. Die App muss anhand des übergebenen Suchstrings eine geeignete Auswahl treffen.
onPause()
- Wird aufgerufen, wenn der Nutzer die Wiedergabe pausiert.
onSkipToNext()
- Wird aufgerufen, wenn der Nutzer zum nächsten Element springen möchte.
onSkipToPrevious()
- Wird aufgerufen, wenn der Nutzer zum vorherigen Element springen möchte.
onStop()
- Wird aufgerufen, wenn der Nutzer die Wiedergabe beendet.
Überschreiben Sie diese Methoden in Ihrer App, um die gewünschten Funktionen bereitzustellen. Sie müssen eine Methode nicht implementieren, wenn ihre Funktion von Ihrer App nicht unterstützt wird. Wenn Ihre App beispielsweise einen Livestream wie eine Sportübertragung abspielt, müssen Sie die Methode onSkipToNext()
nicht implementieren. Sie können stattdessen die Standardimplementierung von onSkipToNext()
verwenden.
Ihre App benötigt keine spezielle Logik, um Inhalte über die Lautsprecher des Autos wiederzugeben. Wenn Ihre App eine Anfrage zum Abspielen von Inhalten erhält, kann sie Audioinhalte auf die gleiche Weise wiedergeben, wie sie Inhalte über die Lautsprecher oder Kopfhörer des Smartphones eines Nutzers wiedergibt. Android Auto und Android Automotive OS senden die Audioinhalte automatisch an das System des Autos, um sie über die Lautsprecher des Autos wiederzugeben.
Weitere Informationen zur Wiedergabe von Audioinhalten finden Sie unter MediaPlayer – Übersicht, Audio-App – Übersicht und ExoPlayer – Übersicht.
Standardmäßige Wiedergabeaktionen festlegen
In Android Auto und Android Automotive OS werden Wiedergabesteuerungen basierend auf den Aktionen angezeigt, die im PlaybackStateCompat
-Objekt aktiviert sind.
Standardmäßig muss Ihre App die folgenden Aktionen unterstützen:
Deine App kann außerdem die folgenden Aktionen unterstützen, wenn sie für den Inhalt der App relevant sind:
Außerdem haben Sie die Möglichkeit, eine Wiedergabeliste zu erstellen, die dem Nutzer angezeigt werden kann. Dies ist jedoch nicht erforderlich. Rufen Sie dazu die Methoden setQueue()
und setQueueTitle()
auf, aktivieren Sie die Aktion ACTION_SKIP_TO_QUEUE_ITEM
und definieren Sie den Callback onSkipToQueueItem()
.
Fügen Sie außerdem Unterstützung für das Symbol Now Playing hinzu, das angibt, was gerade wiedergegeben wird. Rufe dazu die Methode setActiveQueueItemId()
auf und übergebe die ID des aktuell wiedergegebenen Elements in der Wiedergabeliste. Du musst setActiveQueueItemId()
jedes Mal aktualisieren, wenn sich die Warteschlange ändert.
In Android Auto und Android Automotive OS werden Schaltflächen für jede aktivierte Aktion sowie die Wiedergabeliste angezeigt. Wenn auf die Schaltflächen geklickt wird, ruft das System den entsprechenden Rückruf von MediaSessionCompat.Callback
auf.
Ungenutzte Flächen reservieren
In Android Auto und Android Automotive OS wird in der Benutzeroberfläche Platz für die Aktionen ACTION_SKIP_TO_PREVIOUS
und ACTION_SKIP_TO_NEXT
reserviert. Wenn deine App eine dieser Funktionen nicht unterstützt, verwenden Android Auto und Android Automotive OS den Bereich, um von dir erstellte benutzerdefinierte Aktionen aufzurufen.
Wenn Sie diese Bereiche nicht mit benutzerdefinierten Aktionen füllen möchten, können Sie sie reservieren, damit Android Auto und Android Automotive OS den Bereich leer lassen, wenn Ihre App die entsprechende Funktion nicht unterstützt. Rufen Sie dazu die Methode setExtras()
mit einem Extras-Bundle auf, das Konstanten enthält, die den reservierten Funktionen entsprechen.
SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
entspricht ACTION_SKIP_TO_NEXT
und SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
entspricht ACTION_SKIP_TO_PREVIOUS
. Verwenden Sie diese Konstanten als Schlüssel im Bundle und den booleschen Wert true
für ihre Werte.
Anfangsstatus der Wiedergabe festlegen
Da Android Auto und Android Automotive OS mit Ihrem Medienbrowserdienst kommunizieren, gibt Ihre Mediensitzung den Status der Wiedergabe von Inhalten über das Symbol PlaybackStateCompat
an.
Ihre App sollte nicht automatisch mit der Musikwiedergabe beginnen, wenn Android Automotive OS oder Android Auto eine Verbindung zu Ihrem Medienbrowserdienst herstellt. Stattdessen kannst du Android Auto und Android Automotive OS verwenden, um die Wiedergabe basierend auf dem Status des Autos oder den Aktionen der Nutzer fortzusetzen oder zu starten.
Legen Sie dazu den ursprünglichen PlaybackStateCompat
deiner Mediensitzung auf STATE_STOPPED
, STATE_PAUSED
, STATE_NONE
oder STATE_ERROR
fest.
Mediensitzungen in Android Auto und Android Automotive OS dauern nur die Dauer der Fahrt. Daher starten und beenden Nutzer diese Sitzungen häufig. Um einen reibungslosen Wechsel zwischen Laufwerken zu ermöglichen, sollte der vorherige Sitzungsstatus des Nutzers überwacht werden. Wenn die Medien-App eine Fortsetzungsanfrage erhält, kann der Nutzer automatisch dort weitermachen, wo er aufgehört hat, z. B. beim zuletzt abgespielten Medienelement, der PlaybackStateCompat
und der Wiedergabeliste.
Benutzerdefinierte Wiedergabeaktionen hinzufügen
Du kannst benutzerdefinierte Wiedergabeaktionen hinzufügen, um zusätzliche Aktionen anzuzeigen, die von deiner Medien-App unterstützt werden. Wenn der Platz ausreicht (und nicht reserviert ist), fügt Android den Steuerelementen für die Mobilitätsoptionen die benutzerdefinierten Aktionen hinzu. Andernfalls werden die benutzerdefinierten Aktionen im Dreipunkt-Menü angezeigt. Benutzerdefinierte Aktionen werden in der Reihenfolge angezeigt, in der sie dem PlaybackStateCompat
hinzugefügt wurden.
Mit benutzerdefinierten Aktionen lässt sich ein Verhalten festlegen, das sich von Standardaktionen unterscheidet. Verwenden Sie sie nicht, um Standardaktionen zu ersetzen oder zu duplizieren.
Mit der Methode addCustomAction()
in der Klasse PlaybackStateCompat.Builder
können Sie benutzerdefinierte Aktionen hinzufügen.
Im folgenden Code-Snippet wird gezeigt, wie Sie eine benutzerdefinierte Aktion „Radiosender starten“ hinzufügen:
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());
Ein ausführlicheres Beispiel für diese Methode finden Sie in der setCustomAction()
-Methode in der Beispiel-App „Universal Android Music Player“ auf GitHub.
Nachdem du die benutzerdefinierte Aktion erstellt hast, kann deine Mediensitzung auf die Aktion reagieren, indem du die Methode onCustomAction()
überschreibst.
Im folgenden Code-Snippet sehen Sie, wie Ihre App auf die Aktion „Radiosender starten“ reagieren könnte:
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)) { ... } }
Ein ausführlicheres Beispiel für diese Methode finden Sie in der Methode onCustomAction
in der Beispiel-App „Universal Android Music Player“ auf GitHub.
Symbole für benutzerdefinierte Aktionen
Für jede benutzerdefinierte Aktion, die Sie erstellen, ist eine Symbolressource erforderlich. Apps in Autos können auf vielen verschiedenen Bildschirmgrößen und -dichten ausgeführt werden. Daher müssen die von Ihnen bereitgestellten Symbole Vektorgrafiken sein. Mit einem Vektor-Zeichnen können Sie Assets skalieren, ohne dass Details verloren gehen. Mit einem Vektorobjekt lassen sich außerdem bei geringeren Auflösungen die Kanten und Ecken an die Pixelgrenzen anpassen.
Wenn eine benutzerdefinierte Aktion zustandsorientiert ist, z. B. durch Ein- oder Ausschalten einer Wiedergabeeinstellung, werden verschiedene Symbole für die verschiedenen Status angezeigt, damit Nutzer eine Änderung sehen können, wenn sie die Aktion auswählen.
Alternative Symbolstile für deaktivierte Aktionen bereitstellen
Wenn eine benutzerdefinierte Aktion für den aktuellen Kontext nicht verfügbar ist, ersetzen Sie das Symbol der benutzerdefinierten Aktion durch ein alternatives Symbol, das angibt, dass die Aktion deaktiviert ist.
Audioformat angeben
Wenn Sie angeben möchten, dass für die aktuell wiedergegebenen Medien ein spezielles Audioformat verwendet wird, können Sie Symbole angeben, die in Autos gerendert werden, die diese Funktion unterstützen. Sie können KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI
und KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI
im Extras-Bundle des aktuell wiedergegebenen Medienelements festlegen (das an MediaSession.setMetadata()
übergeben wurde). Sie müssen beide Extras festlegen, um unterschiedliche Layouts zu berücksichtigen.
Außerdem kannst du das Extra KEY_IMMERSIVE_AUDIO
festlegen, um OEMs von Autos zu informieren, dass es sich um immersive Audioinhalte handelt und sie sehr vorsichtig sein sollten, wenn sie Audioeffekte anwenden, die die immersiven Inhalte beeinträchtigen könnten.
Links aus dem gerade wiedergegebenen Element hinzufügen
Du kannst das aktuell wiedergegebene Medienelement so konfigurieren, dass sein Untertitel, seine Beschreibung oder beides Links zu anderen Medienelementen sind. So können Nutzer schnell zu ähnlichen Elementen springen, z. B. zu anderen Songs desselben Künstlers oder zu anderen Folgen dieses Podcasts. Wenn das Auto diese Funktion unterstützt, können Nutzer auf den Link tippen, um zu diesen Inhalten zu gelangen.
Wenn du Links hinzufügen möchtest, konfiguriere die Metadaten KEY_SUBTITLE_LINK_MEDIA_ID
(für Links über den Untertitel) oder KEY_DESCRIPTION_LINK_MEDIA_ID
(für Links über die Beschreibung). Weitere Informationen finden Sie in der Referenzdokumentation zu diesen Metadatenfeldern.
Sprachbefehle unterstützen
Ihre Medien-App muss Sprachaktionen unterstützen, um Fahrern eine sichere und praktische Nutzung zu ermöglichen, bei der sie nicht abgelenkt werden. Wenn in Ihrer App beispielsweise ein Medienelement wiedergegeben wird, kann der Nutzer „[Songtitel]abspielen“ sagen, um Ihre App aufzufordern, einen anderen Song abzuspielen, ohne auf das Display des Autos zu schauen oder es zu berühren. Nutzer können Suchanfragen starten, indem sie auf die entsprechenden Tasten auf dem Lenkrad klicken oder das Hotword Hey Google sprechen.
Wenn Android Auto oder Android Automotive OS eine Sprachaktion erkennt und interpretiert, wird diese Sprachaktion über onPlayFromSearch()
an die App gesendet.
Wenn die App diesen Rückruf empfängt, sucht sie nach Inhalten, die mit dem String query
übereinstimmen, und startet die Wiedergabe.
Nutzer können in ihrer Suchanfrage unterschiedliche Kategorien von Begriffen angeben, z. B. Genre, Künstler, Album, Titelname, Radiosender oder Playlist. Berücksichtigen Sie beim Einrichten der Unterstützung für die Suche alle Kategorien, die für Ihre App sinnvoll sind. Wenn Android Auto oder Android Automotive OS erkennt, dass eine bestimmte Suchanfrage in bestimmte Kategorien fällt, werden dem Parameter extras
Extras angehängt. Die folgenden Extras können gesendet werden:
Berücksichtigen Sie einen leeren query
-String, der von Android Auto oder Android Automotive OS gesendet werden kann, wenn der Nutzer keine Suchbegriffe angibt.
Beispiel: Der Nutzer sagt „Spiel Musik ab“. In diesem Fall wird in Ihrer App möglicherweise ein vor Kurzem abgespielter oder neu vorgeschlagener Titel gestartet.
Wenn eine Suche nicht schnell verarbeitet werden kann, blockiere sie nicht in onPlayFromSearch()
.
Lege stattdessen den Wiedergabestatus auf STATE_CONNECTING
fest und führe die Suche in einem asynchronen Thread aus.
Nach Beginn der Wiedergabe kannst du die Wiedergabeliste der Mediensitzung mit ähnlichen Inhalten füllen. Wenn der Nutzer beispielsweise die Wiedergabe eines Albums anfordert, kann die Warteschlange von Ihrer App mit der Titelliste des Albums gefüllt werden. Du solltest auch Suchergebnisse mit Suchansicht unterstützen, damit Nutzer einen anderen Titel auswählen können, der ihrer Suchanfrage entspricht.
Neben Suchanfragen vom Typ „Wiedergabe“ erkennen Android Auto und Android Automotive OS auch Sprachanfragen zur Wiedergabesteuerung wie „Musik pausieren“ und „Nächster Titel“ und ordnen diese Befehle den entsprechenden Callbacks für die Mediensitzung zu, z. B. onPause()
und onSkipToNext()
.
Ein detailliertes Beispiel für die Implementierung sprachaktivierter Wiedergabeaktionen in Ihrer App finden Sie unter Google Assistant und Medien-Apps.
Schutzmaßnahmen gegen Ablenkungen implementieren
Da das Smartphone eines Nutzers während der Nutzung von Android Auto mit den Lautsprechern des Autos verbunden ist, musst du zusätzliche Vorkehrungen treffen, um den Fahrer nicht abzulenken.
Alarme im Auto unterdrücken
Android Auto-Medien-Apps dürfen die Audiowiedergabe über die Autolautsprecher nur starten, wenn der Nutzer die Wiedergabe beispielsweise durch Drücken einer Wiedergabetaste startet. Auch ein vom Nutzer geplanter Wecker aus Ihrer Medien-App darf keine Musik über die Lautsprecher des Autos abspielen.
Um diese Anforderung zu erfüllen, kann Ihre App CarConnection
als Signal verwenden, bevor Audio abgespielt wird. Ihre App kann prüfen, ob das Smartphone auf ein Autodisplay projiziert wird, indem sie den LiveData
für den Typ der Verbindung zum Auto beobachtet und prüft, ob er mit CONNECTION_TYPE_PROJECTION
übereinstimmt.
Wenn das Smartphone des Nutzers projiziert wird, müssen Medien-Apps, die Wecker unterstützen, einen der folgenden Schritte ausführen:
- Deaktiviere den Alarm.
- Der Wecker muss über
STREAM_ALARM
abgespielt werden und es muss eine Benutzeroberfläche auf dem Smartphone-Display geben, über die der Wecker deaktiviert werden kann.
Umgang mit Media-Anzeigen
Standardmäßig zeigt Android Auto eine Benachrichtigung an, wenn sich die Medienmetadaten während einer Audiowiedergabe ändern. Wenn eine Medien-App von der Musikwiedergabe zu einer Werbeunterbrechung wechselt, ist es ablenkend, dem Nutzer eine Benachrichtigung zu senden. Damit Android Auto in diesem Fall keine Benachrichtigung anzeigt, müssen Sie den Medienmetadatenschlüssel METADATA_KEY_IS_ADVERTISEMENT
auf METADATA_VALUE_ATTRIBUTE_PRESENT
setzen, wie im folgenden Code-Snippet gezeigt:
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()); }
Allgemeine Fehler behandeln
Wenn in der App ein Fehler auftritt, setze den Wiedergabestatus auf STATE_ERROR
und gib mit der Methode setErrorMessage()
eine Fehlermeldung an. Eine Liste der Fehlercodes, die Sie beim Festlegen der Fehlermeldung verwenden können, finden Sie unter PlaybackStateCompat
.
Fehlermeldungen müssen für Nutzer sichtbar sein und in der aktuellen Sprache des Nutzers lokalisiert sein. Android Auto und Android Automotive OS können dem Nutzer dann die Fehlermeldung anzeigen.
Wenn Inhalte beispielsweise in der aktuellen Region des Nutzers nicht verfügbar sind, kannst du den Fehlercode ERROR_CODE_NOT_AVAILABLE_IN_REGION
verwenden, wenn du die Fehlermeldung festlegst.
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());
Weitere Informationen zu Fehlerstatus findest du unter Mediasitzung verwenden: Status und Fehler.
Wenn ein Android Auto-Nutzer Ihre Smartphone-App öffnen muss, um einen Fehler zu beheben, teilen Sie ihm dies in Ihrer Nachricht mit. Die Fehlermeldung könnte beispielsweise „In [Name Ihrer App] anmelden“ statt „Bitte melden Sie sich an“ lauten.