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 erforderlichen Komponenten von MediaBrowserService
und MediaSession
beschrieben, die Ihre App benötigt, um unter Android Auto oder Android Automotive OS zu funktionieren. Nachdem Sie die grundlegende Medieninfrastruktur fertiggestellt haben, können Sie Ihrer Medien-App Unterstützung für Android Auto und Unterstützung für 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 finden und deren Inhalte anzuzeigen. Android Auto und Android Automotive OS verwenden einen Medienbrowser, um den Medienbrowserdienst Ihrer 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 stellt einen einzelnen Audiostream dar, 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. Angenommen, das Element steht für ein Album und seine untergeordneten Elemente sind die Titel 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 Designrichtlinien für Android Automotive OS entspricht. Die Benutzeroberfläche für diese Aktivitäten wird nicht von Android Automotive OS erstellt. Sie müssen also dafür sorgen, dass Ihre 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 eine eigene für das Fahrzeug optimierte Benutzeroberfläche mithilfe der Informationen aus Ihrem Media-Browserdienst 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. Deklarieren Sie Ihren Medienbrowserdienst in Ihrem Manifest, damit Android Auto und Android Automotive OS den Dienst finden und eine Verbindung zu Ihrer 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 können Sie angeben, dass das Symbol Ihrer mobilen App für Ihre Automedien-App verwendet werden soll:
<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 Media-Browser-Dienst auch verwenden, um anderen Clients den Zugriff auf Medieninhalte aus Ihrer App zu ermöglichen. Diese Media-Clients 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-Browser-Dienst 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()
deines Dienstes auf, um das Stammmedienelement in deiner 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 dazu, was das System auf dieser Ebene erwartet, finden Sie auf dieser Seite unter Übergeordnetes Menü strukturieren. - 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 Rückrufmethode der Mediensitzung auf, um diese Aktion auszuführen.
- Wenn von Ihrer App unterstützt, kann der Nutzer auch in Ihren Inhalten suchen. In diesem Fall rufen 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 onGetRoot()
-Methode deines Dienstes gibt Informationen zum Stammknoten deiner Inhaltshierarchie zurück.
Android Auto und Android Automotive OS verwenden diesen Stammknoten, um den Rest Ihrer 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.
Paketüberprüfung 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 dein Dienst entscheiden, ob dieses Paket auf deine Inhalte zugreifen kann. Sie können beispielsweise den Zugriff auf die Inhalte Ihrer App auf eine Liste genehmigter Pakete beschränken, indem Sie die clientPackageName
mit Ihrer Zulassungsliste vergleichen und das Zertifikat prüfen, mit dem das APK des Pakets signiert wurde. Wenn das Paket nicht bestätigt werden kann, gib null
zurück, um den Zugriff auf deine Inhalte zu verweigern.
Damit System-Apps wie Android Auto und Android Automotive OS auf Ihre Inhalte zugreifen können, muss Ihr Dienst immer eine nicht nullwertige BrowserRoot
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 für die Implementierung der Paketüberprüfung für die onGetRoot()
-Methode Ihres Dienstes.
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, einschließlich 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 wiedergeben möchte, gibt sie das Token weiter. Deine App 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 Elemente des Stammknotens: In den meisten Fällen ist diese Zahl vier. Das bedeutet, dass mehr als vier Tabs nicht 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 Root-Hinweise 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, insbesondere wenn deine Hierarchie zwischen MediaBrowser
-Integrationen außerhalb von Android Auto und Android Automotive OS variiert.
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 Stammhinweiselementen gibt es noch 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. Wenn Sie Labels kurz halten, verringert sich die Wahrscheinlichkeit, dass die 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()
.
Für MediaMetadataCompat
-Objekte, die das aktuell wiedergegebene Element darstellen, leite die URI über putString()
weiter. Verwende dazu einen der folgenden Schlüssel:
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“.
Erstelle 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üfe in deiner Implementierung von
ContentProvider.openFile()
, ob eine Datei für den entsprechenden URI 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 Bundle und suchen nach diesen Konstanten, um den entsprechenden Stil zu ermitteln.
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 Darstellungshinweis für alle abspielbaren Elemente im Navigationsbaum 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. Diese Elemente ähneln normalen Listenelementen, mit dem Unterschied, dass um die Symbole der Elemente Ränder angewendet werden, da die Symbole bei kleiner Größe 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 voraussichtlich nur für Elemente angezeigt, die sich durchsuchen lassen.
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 zuvor genannten Hinweise hinzu. DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
gilt für die abspielbaren untergeordneten Elemente dieses Elements, während DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
für die suchbaren untergeordneten Elemente dieses Elements gilt.
Wenn du den Standardwert für ein bestimmtes Medienelement selbst und nicht für seine untergeordneten Elemente überschreiben möchtest, erstelle ein Extras-Bundle in der MediaDescription
des Medienelements und füge 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 seinem 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, „Songs“ und „Alben“, in dieser Reihenfolge anzeigen lassen und Ihre App gibt fünf Medienelemente in der folgenden Reihenfolge an:
- 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 der Gruppe „Songs“ und der Gruppe „Alben“ nicht in zusammenhängenden Blöcken zusammengefasst werden, werden sie in Android Auto und Android Automotive OS als die folgenden vier Gruppen interpretiert:
- Gruppe 1 mit dem Namen „Songs“ mit dem Medienelement A
- 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 Element 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 Long-Konstanten sind die möglichen Werte:STATUS_DOWNLOADED
: Der Artikel ist vollständig heruntergeladen.STATUS_DOWNLOADING
: Der Artikel 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 Artikel explizit ist, verwenden Sie diese Konstante als Schlüssel und die lange ZeichenfolgeMETADATA_VALUE_ATTRIBUTE_PRESENT
als Wert.
Die folgenden Konstanten können nur in MediaItem
-Textzeilen-Extras 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 abgespielt und die aktuelle Position liegt in der Mitte.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED
: Der Artikel wurde abgeschlossen.
DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
: Gibt den Fortschritt bei der Wiedergabe von Inhalten im Langformat als Doppeltzahl zwischen 0,0 und 1,0 an. Diese Zusatzinformation liefert mehr Informationen zum StatusPARTIALLY_PLAYING
, damit Android Auto oder Android Automotive OS eine aussagekräftigere Fortschrittsanzeige wie eine Fortschrittsanzeige anzeigt. 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 du Indikatoren für ein gerade wiedergegebenes Medienelement anzeigen möchtest, kannst du Long
-Werte für METADATA_KEY_IS_EXPLICIT
oder EXTRA_DOWNLOAD_STATUS
im MediaMetadataCompat
deiner mediaSession
angeben. Die Indikatoren DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS
oder DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
können nicht in der Wiedergabeansicht angezeigt werden.
Im folgenden Code-Snippet wird gezeigt, wie du angeben kannst, dass der aktuelle Titel in der Wiedergabeansicht explizit und heruntergeladen ist:
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. Wenn ein Nutzer die teilweise abgespielten Inhalte jedoch weiterhin über Android Auto oder Android Automotive OS abspielt, wird dieser Indikator mit 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 (einschließlich) anDESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
senden. - Die
MediaMetadataCompat
mussMETADATA_KEY_MEDIA_ID
mit einem Stringwert senden, der der Medien-ID entspricht, die an dieMediaItem
übergeben wurde. - Die
PlaybackStateCompat
muss ein Extra mit dem SchlüsselPLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID
enthalten, der einem Stringwert zugeordnet ist, der der Medien-ID entspricht, die an dieMediaItem
übergeben wird.
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 der onSearch()
-Methode Ihres Dienstes mithilfe von Titelelementen organisieren, um sie übersichtlich zu gestalten. 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. So können Sie die Funktionen der Media App auf vielfältige Weise erweitern, z. B. durch die Aktionen „Herunterladen“, „Zur Wiedergabeliste hinzufügen“, „Radio abspielen“, „Zu Favoriten hinzufügen“ oder „Entfernen“.
Wenn mehr benutzerdefinierte Aktionen vorhanden sind, als der OEM anzeigen lässt, wird dem Nutzer ein Überlaufmenü angezeigt.
So funktioniert es:
Jede benutzerdefinierte Suchaktion wird mit folgenden Angaben definiert:
- Eine Aktions-ID (eine eindeutige String-Kennung)
- Ein Aktionslabel (der Text, der dem Nutzer angezeigt wird)
- Ein URI für ein Aktionssymbol (ein vektorbasiertes Drawable, das eingefärbt werden kann)
Sie definieren eine Liste mit benutzerdefinierten 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:
- Rufe in
onGetRoot()
mit dem SchlüsselBROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT
in derrootHints
Bundle
die maximale Anzahl der zulässigen Aktionen für jedeMediaItem
ab. Ein Limit von 0 gibt an, dass die Funktion vom System nicht unterstützt wird.
- Rufe in
- Erstellen Sie die globale Liste der benutzerdefinierten Suchaktionen:
- Erstelle für jede Aktion ein
Bundle
-Objekt mit den folgenden Schlüsseln: *EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID
: Die Aktions-ID *EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL
: Das Aktionslabel *EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI
: Der URI des Aktionssymbols * Füge alleBundle
-Objekte der Aktion einer Liste hinzu.
- Erstelle für jede Aktion ein
- Fügen Sie die globale Liste Ihrem
BrowseRoot
hinzu:- Fügen Sie die Liste der Aktionen unter
BrowseRoot
ExtrasBundle
alsParcelable
Arraylist
mit dem SchlüsselBROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST
hinzu.
- Fügen Sie die Liste der Aktionen unter
- 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 aufnimmst. Diese Liste muss eine Teilmenge der globalen Liste der Aktionen sein, die Sie in derBrowseRoot
definiert haben.
- Du kannst einzelnen
- Aktionen verarbeiten und Fortschritt oder Ergebnisse zurückgeben:
- Verarbeite 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.
- Verarbeite 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 einem separaten Bundle
verpackt 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 aus
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 „Nach Knoten suchen“ 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 der Fortschritt aktualisiert wird, rufe
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 den 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 den 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
deines 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 du das Mediensitzungsobjekt erstellst, legst du ein Callback-Objekt fest, das zum Verarbeiten 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 Ihrer App anfordert, verwenden Android Automotive OS und Android Auto die MediaSessionCompat.Callback
-Klasse aus dem MediaSessionCompat
-Objekt Ihrer App, das über den Media-Browser-Dienst Ihrer App abgerufen wurde. Wenn ein Nutzer die Wiedergabe von Inhalten steuern möchte, z. B. die Wiedergabe pausieren oder zum nächsten Titel springen, 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 Methoden implementieren, die von Ihrer App unterstützt werden.
Implementiere alle folgenden Rückrufmethoden, die für die Art der Inhalte in deiner App sinnvoll sind:
onPrepare()
- Wird aufgerufen, wenn sich die Medienquelle ändert. Android Automotive OS ruft diese Methode auch direkt nach dem Starten auf. Ihre Medien-App muss diese Methode implementieren.
onPlay()
- Wird aufgerufen, wenn der Nutzer „Wiedergabe“ auswählt, ohne einen bestimmten Titel auszuwählen. Ihre App muss die Standardinhalte abspielen oder, wenn die Wiedergabe mit
onPause()
pausiert wurde, die Wiedergabe fortsetzen.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 die Wiedergabe über eine Suchanfrage auswählt. 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 abzuspielen. 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, damit sie über die Lautsprecher des Autos wiedergegeben werden.
Weitere Informationen zur Wiedergabe von Audioinhalten finden Sie unter MediaPlayer – Übersicht, Audio-App – Übersicht und ExoPlayer – Übersicht.
Standardwiedergabeaktionen festlegen
In Android Auto und Android Automotive OS werden Wiedergabesteuerungen basierend auf den Aktionen angezeigt, die im PlaybackStateCompat
-Objekt aktiviert sind.
Ihre App muss standardmäßig die folgenden Aktionen unterstützen:
Ihre App kann zusätzlich die folgenden Aktionen unterstützen, sofern sie für die Inhalte 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 Speicherplatz reservieren
In Android Auto und Android Automotive OS wird Platz in der Benutzeroberfläche für die Aktionen ACTION_SKIP_TO_PREVIOUS
und ACTION_SKIP_TO_NEXT
reserviert. Wenn Ihre App eine dieser Funktionen nicht unterstützt, wird in Android Auto und Android Automotive OS der Bereich für benutzerdefinierte Aktionen verwendet, die Sie erstellen.
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 Inhaltswiedergabe ü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 so lange wie die Fahrt, sodass Nutzer diese Sitzungen häufig starten und beenden. 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
Sie können benutzerdefinierte Wiedergabeaktionen hinzufügen, um zusätzliche Aktionen anzuzeigen, die von Ihrer 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 können Sie ein anderes Verhalten als bei Standardaktionen festlegen. 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
val customActionExtras = Bundle() customActionExtras.putInt( androidx.media3.session.MediaConstants.EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT, androidx.media3.session.CommandButton.ICON_RADIO) stateBuilder.addCustomAction( PlaybackStateCompat.CustomAction.Builder( CUSTOM_ACTION_START_RADIO_FROM_MEDIA, resources.getString(R.string.start_radio_from_media), startRadioFromMediaIcon // or R.drawable.media3_icon_radio ).run { setExtras(customActionExtras) build() } )
Java
Bundle customActionExtras = new Bundle(); customActionExtras.putInt( androidx.media3.session.MediaConstants.EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT, androidx.media3.session.CommandButton.ICON_RADIO); stateBuilder.addCustomAction( new PlaybackStateCompat.CustomAction.Builder( CUSTOM_ACTION_START_RADIO_FROM_MEDIA, resources.getString(R.string.start_radio_from_media), startRadioFromMediaIcon) // or R.drawable.media3_icon_radio .setExtras(customActionExtras) .build());
Ein ausführlicheres Beispiel für diese Methode finden Sie in der Methode setCustomAction()
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 ein Symbol erforderlich.
Wenn die Beschreibung dieses Symbols mit einer der Konstanten CommandButton.ICON_
übereinstimmt, sollten Sie diesen Ganzzahlwert für den Schlüssel EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT
der Extras der benutzerdefinierten Aktion festlegen. Auf unterstützten Systemen wird dadurch die Symbolressource überschrieben, die an CustomAction.Builder
übergeben wird. So können Systemkomponenten deine Aktion und andere Wiedergabeaktionen in einem einheitlichen Stil rendern.
Sie müssen auch eine Symbolressource angeben. 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 zustandsabhängig ist, z. B. eine Wiedergabeeinstellung ein- oder ausschaltet, sollten Sie für die verschiedenen Status unterschiedliche Symbole verwenden, damit Nutzer eine Änderung sehen, 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. Du kannst KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI
und KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI
im Extras-Bundle des gerade wiedergegebenen Medienelements festlegen (an MediaSession.setMetadata()
übergeben). Achte darauf, beide Extras festzulegen, um verschiedene 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 Ihrer App zu sagen, dass ein anderer Song abgespielt werden soll, 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 verschiedene Kategorien von Begriffen angeben, z. B. Genre, Künstler, Album, Songname, 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 ein Album abspielen möchte, kann deine App die Wiedergabeliste mit der Titelliste des Albums füllen. 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 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 bei der Verwendung von Android Auto mit den Lautsprechern seines Autos verbunden ist, müssen Sie zusätzliche Vorkehrungen treffen, um Ablenkungen des Fahrers zu vermeiden.
Alarme im Auto unterdrücken
Android Auto-Medien-Apps dürfen Audioinhalte nicht über die Lautsprecher des Autos wiedergeben, es sei denn, der Nutzer startet die Wiedergabe, indem er beispielsweise auf eine Wiedergabeschaltfläche drückt. 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, eine der folgenden Aktionen ausführen:
- Deaktivieren Sie den Wecker.
- 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. Wenn du verhindern möchtest, dass Android Auto in diesem Fall eine Benachrichtigung anzeigt, musst du den Schlüssel für die Medienmetadaten METADATA_KEY_IS_ADVERTISEMENT
auf METADATA_VALUE_ATTRIBUTE_PRESENT
festlegen, 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, um die Fehlermeldung festzulegen.
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.