Mit Android Auto und Android Automotive OS können Sie Ihre Medien-App-Inhalte Nutzern in ihrem 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 deine Inhalte finden und anzeigen können.
In diesem Leitfaden wird davon ausgegangen, dass Sie bereits eine Medien-App haben, die Audio auf einem Smartphone wiedergibt, und dass Ihre Medien-App der Architektur der Android-Medien-App entspricht.
In diesem Leitfaden werden die erforderlichen Komponenten von MediaBrowserService
und MediaSession
beschrieben, die deine App benötigt, um unter Android Auto oder Android Automotive OS zu funktionieren. Nachdem Sie die grundlegende Medieninfrastruktur abgeschlossen haben, können Sie Ihrer Medien-App Unterstützung für Android Auto und Unterstützung für Android Automotive OS hinzufügen.
Vorbereitung
- Lesen Sie die Dokumentation zur Android Media API.
- Weitere Informationen zum Design finden Sie unter Medien-Apps erstellen.
- Sehen Sie sich die in diesem Abschnitt aufgeführten wichtigsten Begriffe und Konzepte an.
Schlüsselbegriffe und -konzepte
- Medienbrowserdienst
- Ein Android-Dienst, der von Ihrer Medien-App implementiert wird und der
MediaBrowserServiceCompat
API entspricht. Deine App verwendet diesen Dienst, um den Inhalt freizugeben. - 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 deiner App zu finden.
- Medienelement
Der Medienbrowser organisiert seinen Inhalt in einer Baumstruktur aus
MediaItem
-Objekten. Ein Medienelement kann eines oder beide der folgenden Flags haben:FLAG_PLAYABLE
: Gibt an, dass das Element ein Blatt in der Inhaltsstruktur ist. Das Element steht für einen einzelnen Audiostream, 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 in der Inhaltsstruktur ist und untergeordnete Elemente hat. Das Element stellt beispielsweise ein Album dar und die untergeordneten Elemente sind die Titel auf dem Album.
Ein Medienelement, das sowohl blätterbar als auch abspielbar ist, fungiert wie eine Playlist. Sie können das Element selbst auswählen, um alle untergeordneten Elemente wiederzugeben, 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. Achten Sie deshalb darauf, dass Ihre App den Designrichtlinien entspricht. Dazu gehören in der Regel größere Tippziele und Schriftgrößen, die Unterstützung von Tag- und Nachtmodi und höhere Kontrastverhältnisse.
Fahrzeugoptimierte Benutzeroberflächen dürfen nur angezeigt werden, wenn die Einschränkungen für die Fahrzeugnutzung (Auto User Experience Restrictions, CUXR) nicht aktiv sind, da diese Benutzeroberflächen möglicherweise eine längere Aufmerksamkeit oder eine umfassendere Interaktion des Nutzers erfordern. CUXRs sind nicht aktiv, wenn das Auto angehalten oder geparkt ist, aber immer aktiv, 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 deiner App konfigurieren
Bevor Sie den Medienbrowserdienst 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 nach Medienelementen zu suchen. Sie müssen Ihren Medienbrowserdienst in Ihrem Manifest deklarieren, damit Android Auto und Android Automotive OS den Dienst erkennen und eine Verbindung zu Ihrer App herstellen können.
Das folgende Code-Snippet zeigt, wie Sie Ihren Medienbrowserdienst in Ihrem Manifest deklarieren. Füge diesen Code in die Manifestdatei für dein Android Automotive OS-Modul und in die Manifestdatei für deine Telefon-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 festlegen
Du musst App-Symbole angeben, mit denen Android Auto und Android Automotive OS deine App in der System-UI darstellen können. Es sind zwei Symboltypen erforderlich:
- Launcher-Symbol
- Attributionssymbol
Launcher-Symbol
Das Launcher-Symbol steht für deine App in der System-UI, z. B. im Launcher und in der Symbolablage. Mit der folgenden Manifestdeklaration kannst du angeben, dass das Symbol aus deiner mobilen App zur Darstellung deiner Auto-Medien-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 im Manifest des Medienbrowserdienstes das Attribut android:icon
im Element <service>
des Medienbrowsers 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 auch das kleine Symbol für Benachrichtigungen wiederverwenden. Dieses Symbol muss einfarbig sein. Mit der folgenden Manifestdeklaration können Sie ein Symbol angeben, das Ihre App repräsentiert:
<application>
...
<meta-data
android:name="androidx.car.app.TintableAttributionIcon"
android:resource="@drawable/ic_status_icon" />
...
</application>
Medienbrowserdienst erstellen
Zum Erstellen eines Medienbrowserdienstes erweitern Sie die Klasse MediaBrowserServiceCompat
. Sowohl Android Auto als auch Android Automotive OS können Ihren Dienst dann für Folgendes verwenden:
- Durchsuchen Sie die Inhaltshierarchie Ihrer App, um dem Nutzer ein Menü anzuzeigen.
- Rufen Sie das Token für das Objekt
MediaSessionCompat
Ihrer App ab, um die Audiowiedergabe zu steuern.
Sie können den Medienbrowserdienst auch verwenden, damit andere Clients über Ihre Anwendung auf Medieninhalte zugreifen können. Diese Medienclients können andere Anwendungen 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 Medienbrowserdienst interagieren.
- Der Nutzer startet deine App unter Android Automotive OS oder Android Auto.
- Android Automotive OS oder Android Auto kontaktiert den Medienbrowserdienst Ihrer App mithilfe der Methode
onCreate()
. Bei der Implementierung der MethodeonCreate()
musst du einMediaSessionCompat
-Objekt und dessen 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. Es wird stattdessen verwendet, um weitere Inhalte aus Ihrer App abzurufen. - Android Automotive OS oder Android Auto ruft die Methode
onLoadChildren()
Ihres Dienstes auf, um die untergeordneten Elemente des Stammmedienelements abzurufen. Bei Android Automotive OS und Android Auto werden diese Medienelemente als oberste Ebene von Inhaltselementen angezeigt. Weitere Informationen dazu, was das System auf dieser Ebene erwartet, finden Sie unter Stammmenü strukturieren auf dieser Seite. - Wenn der Nutzer ein durchsuchbares Medienelement auswählt, wird die Methode
onLoadChildren()
des Dienstes noch einmal aufgerufen, um die untergeordneten Elemente des ausgewählten Menüelements abzurufen. - Wenn der Nutzer ein abspielbares Medienelement auswählt, ruft Android Automotive OS oder Android Auto die entsprechende Callback-Methode für die Mediensitzung auf, um diese Aktion auszuführen.
- Sofern dies von Ihrer App unterstützt wird, können 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. Sie müssen in Ihrem Medienbrowserdienst zwei Methoden implementieren, um dies zu unterstützen: 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 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 findest du in der Methode onGetRoot()
in der Beispiel-App „Universal Android Music Player“ auf GitHub.
Paketvalidierung für onGetRoot() hinzufügen
Bei einem Aufruf der Methode onGetRoot()
Ihres Dienstes übergibt das aufrufende Paket identifizierende Informationen an Ihren Dienst. Ihr Dienst kann diese Informationen verwenden, um zu entscheiden, ob dieses Paket auf Ihre Inhalte zugreifen kann. Du kannst beispielsweise den Zugriff auf die Inhalte deiner App auf eine Liste genehmigter Pakete beschränken. Dazu vergleichst du clientPackageName
mit deiner Zulassungsliste und prüfst das Zertifikat, mit dem das APK des Pakets signiert wurde. Wenn das Paket nicht verifiziert werden kann, gib null
zurück, um den Zugriff auf deine Inhalte zu verweigern.
Damit System-Apps wie Android Auto und Android Automotive OS Zugriff auf Ihre Inhalte haben, muss Ihr Dienst immer einen 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. Daher musst du Verbindungen von allen System-Apps zulassen, um Android Automotive OS stabil zu unterstützen.
Das folgende Code-Snippet zeigt, wie Ihr Dienst prüfen kann, ob das aufrufende Paket eine Systemanwendung ist:
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 Beispiel-App „Universal Android Music Player“ auf GitHub. In dieser Klasse finden Sie ein detaillierteres Beispiel für die Implementierung der Paketvalidierung für die Methode onGetRoot()
Ihres Dienstes.
Neben System-Apps musst du auch zulassen, dass Google Assistant eine Verbindung zu deinem MediaBrowserService
herstellt. Google Assistant hat separate Paketnamen für das Smartphone. Dazu gehören Android Auto und Android Automotive OS.
onLoadChildren() implementieren
Nach dem Empfang des Stammknotenobjekts erstellen Android Auto und Android Automotive OS ein Menü der obersten Ebene. Dazu rufen Sie onLoadChildren()
für das Stammknotenobjekt auf, um die untergeordneten Elemente abzurufen. Client-Apps erstellen Untermenüs, indem sie dieselbe Methode mit untergeordneten Knotenobjekten aufrufen.
Jeder Knoten in Ihrer Contenthierarchie 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 zu einem Untermenü wechseln oder ein Medienelement abspielen möchte, übergibt sie das Token. Ihre 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 findest du in der Methode onLoadChildren()
in der Beispiel-App „Universal Android Music Player“ auf GitHub.
Stammmenü strukturieren
Bei Android Auto und Android Automotive OS gelten für die Struktur des Hauptmenüs spezielle Einschränkungen. Diese werden über Stammhinweise an MediaBrowserService
übermittelt, die durch das Bundle
-Argument gelesen werden können, das an onGetRoot()
übergeben wird.
Wenn Sie diese Hinweise befolgen, kann das System den Stamminhalt optimal als Navigationstabs anzeigen. Wenn Sie diese Hinweise nicht beachten, kann es passieren, dass Root-Inhalte verworfen oder vom System weniger gut sichtbar gemacht werden. Es werden zwei Hinweise gesendet:
- Begrenzte Anzahl von untergeordneten Stammelementen: In den meisten Fällen können Sie davon ausgehen, dass diese Zahl vier beträgt. Das bedeutet, dass nicht mehr als vier Registerkarten angezeigt werden können.
- Unterstützte Flags auf untergeordneten Stammknoten: Dieser Wert ist
MediaItem#FLAG_BROWSABLE
. Das bedeutet, dass nur durchsuchbare Elemente, 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 sich deine Hierarchie zwischen MediaBrowser
-Integrationen außerhalb von Android Auto und Android Automotive OS unterscheidet.
Wenn Sie beispielsweise normalerweise ein abspielbares Stammelement anzeigen, sollten Sie es aufgrund des Hinweises zu unterstützten Flags stattdessen unter einem durchsuchbaren Stammelement verschachteln.
Neben den Root-Hinweisen gibt es einige weitere Richtlinien, die du beachten solltest, damit Tabs optimal dargestellt werden:
- Verwenden Sie für jedes Tabelement monochrome Symbole, vorzugsweise weiße Symbole.
- Geben Sie kurze, aber aussagekräftige Labels für jedes Tabelement an. Wenn Labels kurz gehalten werden, verringert sich die Wahrscheinlichkeit, dass Strings abgeschnitten werden.
Artwork für Medien anzeigen
Artwork für Medienelemente muss als lokaler URI mit ContentResolver.SCHEME_CONTENT
oder ContentResolver.SCHEME_ANDROID_RESOURCE
übergeben werden.
Dieser lokale URI muss entweder in eine Bitmap oder ein Vektor-Drawable in den Ressourcen der Anwendung aufgelöst werden. Bei MediaDescriptionCompat
-Objekten, die Elemente in der Inhaltshierarchie darstellen, übergeben Sie den URI über setIconUri()
.
Übergeben Sie bei MediaMetadataCompat
-Objekten, die das aktuell wiedergegebene Element darstellen, den URI über putString()
mit einem 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 Sie Grafiken aus einem Web-URI herunterladen und über einen lokalen URI verfügbar machen. Ein ausführlicheres Beispiel findest du in der Implementierung von openFile()
und den umgebenden Methoden in der Beispiel-App für den Universal Android Music Player.
Erstellen Sie einen
content://
-URI, der dem Web-URI entspricht. Der Medienbrowserdienst und die Mediensitzung übergeben diesen Inhalts-URI an Android Auto und Android Automotive OS.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 der Implementierung von
ContentProvider.openFile()
, ob für den entsprechenden URI eine Datei vorhanden ist. Ist dies nicht der Fall, 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 Contentanbietern finden Sie unter Contentanbieter erstellen.
Inhaltsstile anwenden
Nachdem Sie eine Inhaltshierarchie mit durchsuchbaren oder spielbaren Elementen erstellt haben, können Sie Inhaltsstile anwenden, die bestimmen, 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 werden Bilder gegenüber Titeln und Metadaten priorisiert.
Standardstile für Inhalte festlegen
Sie können globale Standardeinstellungen für die Anzeige Ihrer Mediaelemente festlegen, indem Sie im Extras-Bundle BrowserRoot
der Methode onGetRoot()
Ihres Dienstes bestimmte Konstanten angeben. Android Auto und Android Automotive OS lesen dieses Bundle und suchen nach diesen Konstanten, um den passenden Stil zu bestimmen.
Die folgenden Extras können im Bundle als Schlüssel verwendet werden:
DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
: Gibt einen Präsentationshinweis für alle durchsuchbaren Elemente in der Suchstruktur anDESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
: Gibt einen Präsentationshinweis für alle abspielbaren Elemente im Suchbaum an
Die Schlüssel können den folgenden ganzzahligen konstanten Werten zugeordnet werden, um die Darstellung dieser Elemente zu beeinflussen:
DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM
: Die entsprechenden Elemente werden als Listenelemente angezeigt.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM
: Die entsprechenden Elemente werden als Rasterelemente angezeigt.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM
: Die entsprechenden Elemente werden als Listenelemente vom Typ „Kategorie“ angezeigt. Sie sind dieselben wie normale Listenelemente, mit der Ausnahme, dass Ränder um die Symbole der Elemente herum angewendet werden, da die Symbole besser aussehen, wenn sie klein sind. Bei den Symbolen muss es sich um farbfähige Vektor-Drawables handeln. Dieser Hinweis ist normalerweise nur für durchsuchbare Elemente enthalten.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM
: Die entsprechenden Elemente werden als Kategorie-Rasterelemente angezeigt. Sie sind die gleichen wie herkömmliche Rasterelemente, mit dem Unterschied, dass Ränder um die Symbole der Elemente herum angewendet werden, da die Symbole besser aussehen, wenn sie klein sind. Bei den Symbolen muss es sich um farbfähige Vektor-Drawables handeln. Dieser Hinweis ist normalerweise nur für durchsuchbare Elemente enthalten.
Das folgende Code-Snippet zeigt, wie Sie als Standardinhaltsstil für durchsuchbare Elemente Raster und 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); }
Inhaltsformate pro Element festlegen
Mit der Content Style API können Sie den Standardinhaltsstil sowohl für die untergeordneten Elemente aller durchsuchbaren Medienelemente als auch für jedes Medienelement selbst überschreiben.
Wenn Sie den Standardwert für die untergeordneten Elemente eines durchsuchbaren Medienelements überschreiben möchten, erstellen Sie im MediaDescription
des Medienelements ein zusätzliches Set und fügen Sie dieselben zuvor genannten Hinweise hinzu. DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
gilt für die spielbaren Kinder dieses Elements, während DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
für die blätterbaren untergeordneten Elemente dieses Elements gilt.
Wenn Sie den Standardwert für ein bestimmtes Medienelement selbst und nicht für seine untergeordneten Elemente überschreiben möchten, erstellen Sie im MediaDescription
des Medienelements ein Set mit Extras und fügen einen Hinweis mit dem Schlüssel DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM
hinzu.
Verwenden Sie dieselben Werte wie zuvor beschrieben, um die Darstellung dieses Elements anzugeben.
Das folgende Code-Snippet zeigt, wie Sie ein durchsuchbares MediaItem
erstellen, das den Standardinhaltsstil sowohl für sich selbst als auch für seine untergeordneten Elemente überschreibt. Er wird als Kategorielistenelement gestaltet, seine durchsuchbaren untergeordneten Elemente als Listenelemente und ihre spielbaren untergeordneten Elemente als Rasterelemente:
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
Um ähnliche Medienelemente zu gruppieren, verwenden Sie einen Hinweis pro Element. Jedes Medienelement in einer Gruppe muss in seinem MediaDescription
ein Extras-Set deklarieren, 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.
Das folgende Code-Snippet zeigt, wie Sie ein MediaItem
mit der Untergruppe "Songs"
als Überschrift erstellen:
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*/); }
Ihre App muss alle Medienelemente übergeben, die Sie als zusammenhängenden Block gruppieren möchten. Angenommen, Sie möchten zwei Gruppen von Medienelementen "Songs" 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 werden, interpretieren Android Auto und Android Automotive OS dies als die folgenden vier Gruppen:
- Gruppe 1 namens „Titel“, die Medienelement A enthält
- Gruppe 2 namens „Alben“, die Medienelement B enthält
- Gruppe 3 namens „Titel“ mit den Medienelementen C und D
- Gruppe 4 namens „Alben“, die das Medienelement E enthalten
Um diese Elemente in zwei Gruppen anzuzeigen, 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 Metadatenanzeigen anzeigen
Sie können zusätzliche Metadatenanzeigen einfügen, um auf einen Blick Informationen zu Inhalten in der Baumstruktur des Medienbrowsers und während der Wiedergabe bereitzustellen. Innerhalb des Navigationsbaums 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 der Mediensitzung und suchen nach bestimmten Konstanten, um anzuzeigende Indikatoren zu bestimmen.
Die folgenden Konstanten können sowohl in MediaItem
-Beschreibungsextras als auch in MediaMetadata
-Extras verwendet werden:
EXTRA_DOWNLOAD_STATUS
: Gibt den Downloadstatus eines Elements an. Verwenden Sie diese Konstante als Schlüssel. Folgende lange Konstanten sind mögliche Werte:STATUS_DOWNLOADED
: Das Element wurde vollständig heruntergeladen.STATUS_DOWNLOADING
: Das Element wird heruntergeladen.STATUS_NOT_DOWNLOADED
: Das Element wird nicht heruntergeladen.
METADATA_KEY_IS_EXPLICIT
: gibt an, ob das Element explizite Inhalte enthält. Wenn Sie angeben möchten, dass ein Element explizit ist, verwenden Sie diese Konstante als Schlüssel und den langenMETADATA_VALUE_ATTRIBUTE_PRESENT
als Wert.
Die folgenden Konstanten können nur in den Beschreibungsextras für MediaItem
verwendet werden:
DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS
: Gibt den Fertigstellungsstatus von langen Inhalten wie Podcastfolgen oder Hörbüchern an. Verwenden Sie diese Konstante als Schlüssel. Folgende Ganzzahlkonstanten sind mögliche Werte:DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED
: Das Element wurde noch nicht abgespielt.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED
: Das Element wurde teilweise wiedergegeben und die aktuelle Position befindet sich in der Mitte.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED
: Das Element ist abgeschlossen.
DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
: Gibt den Fortschritt beim Abschluss von langen Inhalten als Double zwischen 0,0 und 1,0 (einschließlich) an. Dieses zusätzliche enthält weitere Informationen zumPARTIALLY_PLAYING
-Status, damit Android Auto oder Android Automotive OS eine aussagekräftigere Fortschrittsanzeige anzeigt, z. B. eine Fortschrittsanzeige. Wenn Sie diese Ergänzung verwenden, lesen Sie den Abschnitt zum Aktualisieren der Fortschrittsanzeige in der Ansicht bei der Wiedergabe von Inhalten in diesem Leitfaden, um zu erfahren, wie Sie diese Anzeige nach der ersten Impression auf dem neuesten Stand halten.
Wenn Indikatoren angezeigt werden sollen, während der Nutzer die Media-Suche durchstöbert, müssen Sie ein zusätzliches Set erstellen, das eine oder mehrere dieser Konstanten enthält, und dieses Set an die Methode MediaDescription.Builder.setExtras()
übergeben.
Das folgende Code-Snippet zeigt, wie Indikatoren für ein explizites Medienelement angezeigt werden, das zu 70% abgeschlossen 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 */);
Damit Indikatoren für ein Medienelement eingeblendet werden, das gerade wiedergegeben wird, können Sie Long
-Werte für METADATA_KEY_IS_EXPLICIT
oder EXTRA_DOWNLOAD_STATUS
in MediaMetadataCompat
Ihres mediaSession
deklarieren. Die Anzeigen DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS
oder DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
können in der Wiedergabeansicht nicht eingeblendet werden.
Das folgende Code-Snippet zeigt, wie Sie angeben, 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 Suchansicht aktualisieren, während Inhalte wiedergegeben werden
Wie bereits erwähnt, kannst du mit DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
eine Fortschrittsanzeige für teilweise wiedergegebene Inhalte in der Übersicht einblenden. Wenn ein Nutzer jedoch den teilweise wiedergegebenen Inhalt aus Android Auto oder Android Automotive OS weiterhin 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 in MediaMetadataCompat
und PlaybackStateCompat
zusätzliche Informationen angeben, um aktuelle Inhalte mit Medienelementen in der Suchansicht zu verknüpfen. Die folgenden Anforderungen müssen erfüllt sein, damit für das Medienelement eine Fortschrittsanzeige für automatische Updates angezeigt wird:
- Beim Erstellen muss der
MediaItem
in seinen ExtrasDESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
mit einem Wert zwischen 0, 0 und 1, 0 (einschließlich) senden. - Der
MediaMetadataCompat
mussMETADATA_KEY_MEDIA_ID
mit einem Stringwert senden, der der Medien-ID entspricht, die anMediaItem
übergeben wurde. - Die
PlaybackStateCompat
muss ein Extras mit dem SchlüsselPLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID
enthalten, das einem Stringwert zugeordnet ist, der der Media-ID entspricht, die an dieMediaItem
übergeben wurde.
Das folgende Code-Snippet zeigt, wie Sie angeben, dass das aktuell wiedergegebene Element mit einem Element in der Suchansicht 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());
Durchsuchbare Suchergebnisse anzeigen
Ihre Anwendung kann kontextbezogene Suchergebnisse bereitstellen, die Nutzern angezeigt werden, wenn sie eine Suchanfrage starten. Android Auto und Android Automotive OS zeigen diese Ergebnisse über Suchabfrageoberflächen oder Angebote an, die auf Suchanfragen zu einem früheren Zeitpunkt in der Sitzung ausgerichtet sind. Weitere Informationen finden Sie in diesem Leitfaden im Abschnitt Sprachbefehle unterstützen.
Wenn Sie durchsuchbare Suchergebnisse anzeigen möchten, fügen Sie den konstanten Schlüssel BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED
in das Extras-Bundle der Methode onGetRoot()
Ihres Dienstes ein und ordnen Sie diese dem booleschen Wert true
zu.
Das folgende Code-Snippet zeigt, wie die Unterstützung in der Methode onGetRoot()
aktiviert wird:
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); }
Damit Suchergebnisse angezeigt werden können, müssen Sie die Methode onSearch()
in Ihrem Medienbrowserdienst überschreiben. Android Auto und Android Automotive OS leiten die Suchbegriffe der Nutzer an diese Methode weiter, wenn ein Nutzer eine Suchanfrageoberfläche oder „Suchergebnisse“ aufruft.
Sie können die Suchergebnisse der onSearch()
-Methode Ihres Dienstes mithilfe von Titelelementen organisieren, damit sie leichter durchsucht werden können. Wenn in Ihrer App beispielsweise Musik wiedergegeben wird, 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 kannst du den MediaItem
-Objekten deiner App in der Medien-App des Autos benutzerdefinierte Symbole und Labels hinzufügen und Nutzerinteraktionen mit diesen Aktionen verarbeiten. So können Sie die Funktionalität der Medien-App auf verschiedene Arten erweitern und beispielsweise Aktionen wie „Herunterladen“, „Zur Wiedergabeliste hinzufügen“, „Radio hören“, „Favorit“ oder „Entfernen“ hinzufügen.
Wenn es mehr benutzerdefinierte Aktionen gibt, als der OEM zulässt, wird dem Nutzer ein Dreipunkt-Menü angezeigt.
So funktioniert es:
Jede benutzerdefinierte Suchaktion wird definiert durch:
- Eine Aktions-ID (eine eindeutige String-ID)
- Ein Aktionslabel (der dem Nutzer angezeigte Text)
- Ein Aktionssymbol-URI (ein Vektor-Drawable, das eingefärbt werden kann)
Im Rahmen von BrowseRoot
definieren Sie global eine Liste von benutzerdefinierten Suchaktionen. Anschließend können Sie eine Teilmenge dieser Aktionen an einzelne MediaItem.
anhängen
Wenn ein Nutzer mit einer benutzerdefinierten Suchaktion interagiert, erhält Ihre App einen Callback in onCustomAction()
. Anschließend können Sie die Aktion verarbeiten und bei Bedarf die Liste der Aktionen für die MediaItem
aktualisieren. Dies ist nützlich für zustandsorientierte Aktionen
wie „Favorit“ und „Download“. Bei Aktionen wie „Radio hören“, die nicht aktualisiert werden müssen, müssen Sie die Liste der Aktionen nicht aktualisieren.
Sie können benutzerdefinierte Suchaktionen auch an einen Suchknotenstamm 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:
- Hier können Sie zwei Methoden in der
MediaBrowserServiceCompat
-Implementierung überschreiben: - Parsen Sie die Aktionslimits zur Laufzeit:
- In
onGetRoot()
wird die maximal zulässige Anzahl von Aktionen für jedeMediaItem
mit dem SchlüsselBROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT
inrootHints
Bundle
abgerufen. Ein Grenzwert von 0 bedeutet, dass die Funktion vom System nicht unterstützt wird.
- 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
: Aktions-ID *EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL
: Aktionslabel *EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI
: URI des Aktionssymbols * AlleBundle
-Objekte für die Aktion einer Liste hinzufügen
- Erstellen Sie für jede Aktion ein
- Fügen Sie die globale Liste zu
BrowseRoot
hinzu:- Füge in den
BrowseRoot
-Extras-Bundle
die Liste der Aktionen alsParcelable
Arraylist
mit dem SchlüsselBROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST
hinzu.
- Füge in den
- So fügen Sie Ihren
MediaItem
-Objekten Aktionen hinzu:- Sie können einzelnen
MediaItem
-Objekten Aktionen hinzufügen, indem Sie die Liste der Aktions-IDs mit dem SchlüsselDESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST
in dieMediaDescriptionCompat
-Extras aufnehmen. Diese Liste muss eine Teilmenge der globalen Liste von Aktionen sein, die Sie in derBrowseRoot
definiert haben.
- Sie können einzelnen
- So verarbeiten Sie Aktionen und geben den Fortschritt oder Ergebnisse zurück:
- In
onCustomAction
wird die Aktion basierend auf der Aktions-ID und allen anderen benötigten Daten verarbeitet. Mit dem SchlüsselEXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID
können Sie die ID desMediaItem
abrufen, der die Aktion aus den Extras ausgelöst hat. - Sie können die Liste der Aktionen für ein
MediaItem
aktualisieren, indem Sie den SchlüsselEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
in das Fortschritts- oder Ergebnis-Bundle aufnehmen.
- In
Hier sind einige Änderungen, die Sie in 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 Parse-Aktionen
Sie sollten überprü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 eine separate 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>")
- Aktionssymbol-URI
bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI, "<ACTION_ICON_URI>")
Benutzerdefinierte Suchaktionen zu Parceable
ArrayList
hinzufügen
Füge alle Bundle
-Objekte für benutzerdefinierte Suchaktionen zu einer 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; }
Liste der benutzerdefinierten Suchaktionen dem Suchstamm 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 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
- Media-ID 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 trennen Sie das Ergebnis.
result.detach()
- Ergebnis-Bundle erstellen
- Nachricht an Nutzer
mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE, mContext.getString(stringRes))
- Element aktualisieren(zum Aktualisieren von Aktionen in einem Element)
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);
- Suchknoten aktualisieren
//Change current browse node to mediaId mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE, mediaId);
- Nachricht an Nutzer
- Bei einem Fehler
result.sendError(resultBundle).
aufrufen - Wenn der Fortschritt aktualisiert wird, rufe
result.sendProgressUpdate(resultBundle)
an. - Rufe zum Abschluss
result.sendResult(resultBundle)
auf.
Aktionsstatus aktualisieren
Wenn Sie die Methode result.sendProgressUpdate(resultBundle)
mit dem Schlüssel EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
verwenden, können Sie MediaItem
aktualisieren, um den neuen Status der Aktion widerzuspiegeln. Auf diese Weise können Sie Nutzern in Echtzeit Feedback zum Fortschritt und Ergebnis ihrer Aktion geben.
Beispiel: Download-Aktion
Hier ist ein Beispiel dafür, wie Sie diese Funktion verwenden können, um eine Downloadaktion mit drei Status zu implementieren:
- Herunterladen: Dies ist der Anfangszustand der Aktion. Wenn der Nutzer diese Aktion auswählt, können Sie sie durch „Wird heruntergeladen“ ersetzen und
sendProgressUpdate
aufrufen, um die UI zu aktualisieren. - Wird heruntergeladen: Dieser Status zeigt an, dass der Download gerade durchgeführt wird. Sie können diesen Status verwenden, um dem Nutzer einen Fortschrittsbalken oder eine andere Anzeige anzuzeigen.
- Heruntergeladen: Dieser Status zeigt an, dass der Download abgeschlossen ist. Wenn der Download abgeschlossen ist, können Sie „Wird heruntergeladen“ durch „Heruntergeladen“ ersetzen und
sendResult
mit dem SchlüsselEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
aufrufen, um anzugeben, dass das Element aktualisiert werden soll. Außerdem können Sie den SchlüsselEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE
verwenden, um dem Nutzer eine Erfolgsmeldung anzuzeigen.
Auf diese Weise können Sie dem Nutzer klares Feedback zum Downloadvorgang und zu seinem aktuellen Status geben. Mit Symbolen kannst du den Downloadstatus von 25%, 50 % und 75% anzeigen.
Beispiel: Lieblingsaktion
Ein weiteres Beispiel ist eine beliebte Aktion mit zwei Status:
- Favorit: Diese Aktion wird für Elemente angezeigt, die nicht in der Favoritenliste des Nutzers enthalten sind. Wenn der Nutzer diese Aktion auswählt, können Sie sie durch „Zu Favoriten hinzufügen“ ersetzen und
sendResult
mit dem SchlüsselEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
aufrufen, um die UI 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, können Sie sie durch „Favorit“ ersetzen und
sendResult
mit der TasteEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
aufrufen, um die UI zu aktualisieren.
Dieser Ansatz bietet Nutzern eine klare und einheitliche Möglichkeit, ihre Lieblingsartikel zu verwalten.
Diese Beispiele zeigen die Flexibilität von benutzerdefinierten Suchaktionen und wie du sie verwenden kannst, um eine Vielzahl von Funktionen mit Echtzeit-Feedback zu implementieren, um eine verbesserte Nutzererfahrung in der Medien-App des Autos zu ermöglichen.
Ein vollständiges Beispiel für die Implementierung dieser Funktion finden Sie im Projekt TestMediaApp
.
Wiedergabesteuerung aktivieren
Android Auto und Android Automotive OS senden Befehle zur Wiedergabesteuerung über das MediaSessionCompat
Ihres Dienstes.
Sie müssen eine Sitzung registrieren und die zugehörigen Callback-Methoden implementieren.
Mediensitzung registrieren
Erstellen Sie in der Methode onCreate()
Ihres Medienbrowserdienstes einen MediaSessionCompat
und registrieren Sie dann 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, lege ein Callback-Objekt fest, das zur Verarbeitung von Anfragen zur Wiedergabesteuerung verwendet wird. Zum Erstellen dieses Callback-Objekts geben Sie eine Implementierung der Klasse MediaSessionCompat.Callback
für Ihre App an. Im nächsten Abschnitt wird die Implementierung dieses Objekts erläutert.
Wiedergabebefehle implementieren
Wenn ein Nutzer die Wiedergabe eines Medienelements aus Ihrer App anfordert, verwenden Android Automotive OS und Android Auto die Klasse MediaSessionCompat.Callback
aus dem MediaSessionCompat
-Objekt Ihrer App, das sie vom Medienbrowserdienst Ihrer App abgerufen haben. Wenn ein Nutzer die Inhaltswiedergabe 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.
Für die Wiedergabe von Inhalten muss die App die abstrakte MediaSessionCompat.Callback
-Klasse erweitern und die von der App unterstützten Methoden implementieren.
Implementieren Sie die folgenden Callback-Methoden, die für den Inhaltstyp Ihrer App sinnvoll sind:
onPrepare()
- Wird aufgerufen, wenn die Medienquelle geändert wird. Android Automotive OS ruft diese Methode auch unmittelbar nach dem Start auf. Ihre Medien-App muss diese Methode implementieren.
onPlay()
- Wird aufgerufen, wenn der Nutzer die Wiedergabe startet, ohne ein bestimmtes Element auszuwählen. Ihre App muss die Standardinhalte wiedergeben. Wenn sie mit
onPause()
pausiert wurde, wird sie stattdessen fortgesetzt.Hinweis:In Ihrer App sollte die Musikwiedergabe nicht automatisch gestartet werden, wenn Android Automotive OS oder Android Auto eine Verbindung zu Ihrem Medienbrowserdienst herstellt. Weitere Informationen findest du im Abschnitt zum Festlegen des anfänglichen Wiedergabestatus.
onPlayFromMediaId()
- Wird aufgerufen, wenn der Nutzer ein bestimmtes Element abspielen möchte. Der Methode wird die ID übergeben, die dem Medienelement in Ihrer Inhaltshierarchie von Ihrem Medienbrowserdienst zugewiesen wurde.
onPlayFromSearch()
- Wird aufgerufen, wenn der Nutzer über eine Suchanfrage Inhalte abspielen möchte. Die Anwendung muss auf Grundlage des übergebenen Suchstrings eine geeignete Auswahl treffen.
onPause()
- Wird aufgerufen, wenn der Nutzer die Wiedergabe pausiert.
onSkipToNext()
- Wird aufgerufen, wenn der Nutzer mit dem nächsten Element springt.
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 keine Methode implementieren, wenn ihre Funktionalität nicht von Ihrer App unterstützt wird. Wenn Ihre App beispielsweise einen Livestream (z. B. eine Sportübertragung) wiedergibt, 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 Inhalte über die Lautsprecher oder Kopfhörer eines Smartphones eines Nutzers. Android Auto und Android Automotive OS senden die Audioinhalte automatisch an das System des Autos, um es über die Lautsprecher des Autos wiederzugeben.
Weitere Informationen zum Abspielen von Audioinhalten finden Sie unter MediaPlayer, Übersicht über die Audio-App und ExoPlayer-Übersicht.
Standard-Wiedergabeaktionen festlegen
In Android Auto und Android Automotive OS werden Steuerelemente für die Wiedergabe auf Grundlage der Aktionen angezeigt, die im PlaybackStateCompat
-Objekt aktiviert sind.
Standardmäßig muss Ihre App die folgenden Aktionen unterstützen:
Ihre App kann außerdem die folgenden Aktionen unterstützen, wenn sie für den Inhalt der App relevant sind:
Darüber hinaus haben Sie die Möglichkeit, eine Warteschlange zu erstellen, die dem Nutzer angezeigt werden kann, aber nicht unbedingt erforderlich ist. Rufen Sie dazu die Methoden setQueue()
und setQueueTitle()
auf, aktivieren Sie die Aktion ACTION_SKIP_TO_QUEUE_ITEM
und definieren Sie den Callback onSkipToQueueItem()
.
Außerdem soll das Symbol Läuft gerade unterstützt werden. Damit wird angegeben, was gerade läuft. Rufen Sie dazu die Methode setActiveQueueItemId()
auf und übergeben Sie die ID des aktuell wiedergegebenen Elements in der Warteschlange. Sie müssen setActiveQueueItemId()
bei jeder Änderung der Warteschlange aktualisieren.
In Android Auto und Android Automotive OS werden Schaltflächen für jede aktivierte Aktion sowie die Wiedergabeliste für die Wiedergabe angezeigt. Wenn auf die Schaltflächen geklickt wird, ruft das System den entsprechenden Callback von MediaSessionCompat.Callback
auf.
Ungenutzten Platz reservieren
Android Auto und Android Automotive OS reservieren in der UI Platz für die Aktionen ACTION_SKIP_TO_PREVIOUS
und ACTION_SKIP_TO_NEXT
. Wenn deine App eine dieser Funktionen nicht unterstützt, verwenden Android Auto und Android Automotive OS den Bereich, um von dir erstellte benutzerdefinierte Aktionen anzuzeigen.
Wenn du diese Bereiche nicht mit benutzerdefinierten Aktionen füllen möchtest, kannst du sie reservieren, sodass Android Auto und Android Automotive OS den Bereich leer lassen, wenn deine App die entsprechende Funktion nicht unterstützt. Rufen Sie dazu die Methode setExtras()
mit einem zusätzlichen Bundle auf, das Konstanten für die reservierten Funktionen enthält.
SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
entspricht ACTION_SKIP_TO_NEXT
und SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
für ACTION_SKIP_TO_PREVIOUS
. Verwenden Sie diese Konstanten als Schlüssel im Bundle und den booleschen Wert true
für die zugehörigen Werte.
Anfänglichen Wiedergabestatus festlegen
Während Android Auto und Android Automotive OS mit Ihrem Medienbrowserdienst kommunizieren, sendet Ihre Mediensitzung den Status der Inhaltswiedergabe über das PlaybackStateCompat
.
Ihre App sollte nicht automatisch mit der Musikwiedergabe beginnen, wenn Android Automotive OS oder Android Auto eine Verbindung zu Ihrem Medienbrowserdienst herstellt. Setzen Sie stattdessen Android Auto und Android Automotive OS ein, um die Wiedergabe je nach Zustand des Autos oder Nutzeraktionen fortzusetzen oder zu starten.
Legen Sie dazu die anfängliche PlaybackStateCompat
Ihrer Mediensitzung auf STATE_STOPPED
, STATE_PAUSED
, STATE_NONE
oder STATE_ERROR
fest.
Mediensitzungen in Android Auto und Android Automotive OS dauern nur für die Dauer der Fahrt, sodass Nutzer diese Sitzungen häufig starten und beenden. Für eine nahtlose Nutzung zwischen den Laufwerken sollten Sie den vorherigen Sitzungsstatus des Nutzers im Auge behalten. Wenn die Medien-App eine Anfrage zum Fortsetzen erhält, kann der Nutzer dann automatisch dort weitermachen, wo er aufgehört hat, z. B. beim zuletzt wiedergegebenen Medienelement, dem PlaybackStateCompat
und der Warteschlange.
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 es zulässt (und nicht reserviert) ist, fügt Android die benutzerdefinierten Aktionen den Transportsteuerelementen hinzu. Andernfalls werden die benutzerdefinierten Aktionen im Dreipunkt-Menü angezeigt. Benutzerdefinierte Aktionen werden in der Reihenfolge angezeigt, in der sie zu PlaybackStateCompat
hinzugefügt wurden.
Mit benutzerdefinierten Aktionen kannst du ein Verhalten erzielen, 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.
Das folgende Code-Snippet zeigt, wie Sie die benutzerdefinierte Aktion „Start a radio channel“ (Radiokanal 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 findest du in der Methode setCustomAction()
in der Beispiel-App „Universal Android Music Player“ auf GitHub.
Nachdem Sie die benutzerdefinierte Aktion erstellt haben, kann Ihre Mediensitzung auf die Aktion reagieren, indem die Methode onCustomAction()
überschrieben wird.
Das folgende Code-Snippet zeigt, wie Ihre App auf die Aktion „Start a radio channel“ (Radiokanal 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 findest du 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. Die von dir bereitgestellten Symbole müssen also Vektor-Drawables sein. Mit einem Vektor-Drawable können Sie Assets skalieren, ohne Details zu verlieren. Ein Vektor-Drawable erleichtert außerdem das Ausrichten der Kanten und Ecken an Pixelgrenzen bei kleineren Auflösungen.
Wenn eine benutzerdefinierte Aktion zustandsorientiert ist, z. B. durch das Ein- oder Ausschalten einer Wiedergabeeinstellung, können Sie unterschiedliche Symbole für die verschiedenen Status bereitstellen. So sehen Nutzer eine Änderung, 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, tauschen Sie das Symbol für die benutzerdefinierte Aktion durch ein alternatives Symbol aus, das anzeigt, dass die Aktion deaktiviert ist.
Audioformat angeben
Wenn Sie angeben möchten, dass aktuell Medien ein spezielles Audioformat verwenden, 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-Set des aktuell wiedergegebenen Medienelements festlegen, das an MediaSession.setMetadata()
übergeben wird. Achten Sie darauf, beide Extras für verschiedene Layouts festzulegen.
Darüber hinaus können Sie das zusätzliche KEY_IMMERSIVE_AUDIO
-Objekt festlegen, um Auto-OEMs darüber zu informieren, dass es sich um immersives Audio handelt. Diese sollten sehr vorsichtig sein, wenn sie entscheiden, ob sie Audioeffekte anwenden, die die immersiven Inhalte beeinträchtigen könnten.
Links zum aktuell wiedergegebenen Element hinzufügen
Sie können 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 wechseln, z. B. zu anderen Songs desselben Künstlers, anderen Folgen dieses Podcasts usw. Wenn das Auto diese Funktion unterstützt, können Nutzer auf den Link tippen, um diese Inhalte aufzurufen.
Wenn du Links hinzufügen möchtest, konfiguriere die KEY_SUBTITLE_LINK_MEDIA_ID
-Metadaten (für die Verknüpfung mit dem Untertitel) oder KEY_DESCRIPTION_LINK_MEDIA_ID
für eine Verknüpfung von der Beschreibung aus. Weitere Informationen finden Sie in der Referenzdokumentation zu diesen Metadatenfeldern.
Sprachbefehle unterstützen
Ihre Medien-App muss Sprachbedienung unterstützen, damit Fahrer sicher und nutzerfreundlich sind und Ablenkungen minimiert werden. Wenn in Ihrer App beispielsweise ein Medienelement abgespielt wird, kann der Nutzer Spiel [Titel des Titels] abspielen. Dadurch wird die App angewiesen, einen anderen Titel abzuspielen, ohne das Display des Autos zu sehen oder zu berühren. Nutzer können Suchanfragen starten, indem sie auf die entsprechenden Schaltflächen am Lenkrad klicken oder die Hotwords Ok Google sagen.
Wenn Android Auto oder Android Automotive OS eine Spracheingabe erkennt und interpretiert, wird diese Sprachbedienung über onPlayFromSearch()
an die App gesendet.
Beim Empfang dieses Callbacks sucht die App nach Inhalten, die mit dem String query
übereinstimmen, und startet die Wiedergabe.
Nutzer können in ihrer Suchanfrage verschiedene Kategorien von Begriffen angeben: Genre, Künstler, Album, Songname, Radiosender oder Playlist. Berücksichtigen Sie bei der Entwicklung der Suchfunktion alle Kategorien, die für Ihre App sinnvoll sind. Wenn Android Auto oder Android Automotive OS erkennt, dass eine bestimmte Abfrage in bestimmte Kategorien fällt, werden Extras an den extras
-Parameter angehängt. Die folgenden Extras können gesendet werden:
Geben Sie einen leeren query
-String an, der von Android Auto oder Android Automotive OS gesendet werden kann, wenn der Nutzer keine Suchbegriffe angibt.
Beispiel: „Spiel Musik“. In diesem Fall kann Ihre App einen kürzlich abgespielten oder neu vorgeschlagenen Titel starten.
Wenn eine Suche nicht schnell verarbeitet werden kann, sollten Sie in onPlayFromSearch()
nicht blockieren.
Setze stattdessen den Wiedergabestatus auf STATE_CONNECTING
und führe die Suche in einem asynchronen Thread durch.
Sobald die Wiedergabe beginnt, sollten Sie die Warteschlange der Mediensitzung mit ähnlichen Inhalten füllen. Wenn der Nutzer beispielsweise das Abspielen eines Albums anfordert, füllt Ihre App die Warteschlange möglicherweise mit der Trackliste des Albums. Sie können auch die Unterstützung für durchsuchbare Suchergebnisse implementieren, damit Nutzer einen anderen Track auswählen können, der ihrer Suchanfrage entspricht.
Zusätzlich zu play-Anfragen erkennen Android Auto und Android Automotive OS Sprachbefehle wie „Musik pausieren“ und „Nächster Titel“ zur Steuerung der Wiedergabe und ordnen diese Befehle den entsprechenden Callbacks für Mediensitzungen wie onPause()
und onSkipToNext()
zu.
Ein ausführliches Beispiel zum Implementieren sprachgesteuerter Wiedergabeaktionen in deiner App findest du unter Google Assistant und Medien-Apps.
Ablenkungsvorkehrungen treffen
Da das Smartphone eines Nutzers während der Verwendung von Android Auto mit den Lautsprechern seines Autos verbunden ist, müssen Sie zusätzliche Maßnahmen ergreifen, um zu verhindern, dass der Fahrer abgelenkt wird.
Alarme im Auto unterdrücken
Android Auto-Medien-Apps dürfen die Audiowiedergabe über die Autolautsprecher erst starten, wenn der Nutzer die Wiedergabe beispielsweise durch Drücken einer Wiedergabetaste startet. Auch bei einem vom Nutzer eingestellten Wecker über Ihre Medien-App darf keine Musik über die Autolautsprecher abgespielt werden.
Damit diese Anforderung erfüllt wird, kann Ihre App vor der Audiowiedergabe CarConnection
als Signal verwenden. Ihre App kann prüfen, ob das Smartphone auf den Bildschirm eines Autos übertragen wird. Dazu wird LiveData
als Autoverbindungstyp beobachtet und geprüft, ob er CONNECTION_TYPE_PROJECTION
entspricht.
Wenn das Smartphone des Nutzers projiziert wird, müssen Medien-Apps, die Alarme unterstützen, eine der folgenden Aktionen ausführen:
- Den Alarm ausschalten.
- Alarm über
STREAM_ALARM
abspielen und eine Benutzeroberfläche auf dem Smartphone-Display bereitstellen, um den Alarm zu deaktivieren.
Umgang mit Medienwerbung
Standardmäßig zeigt Android Auto eine Benachrichtigung an, wenn sich die Medienmetadaten während einer Audiowiedergabesitzung ändern. Wenn eine Medien-App von der Wiedergabe von Musik zu einer Werbeanzeige wechselt, lenkt sie von der Anzeige einer Benachrichtigung für den Nutzer ab. Damit Android Auto in diesem Fall keine Benachrichtigung anzeigt, musst du 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 mithilfe der Methode setErrorMessage()
eine Fehlermeldung an. Unter PlaybackStateCompat
finden Sie eine Liste von Fehlercodes, die Sie beim Festlegen der Fehlermeldung verwenden können.
Fehlermeldungen müssen für den Nutzer sichtbar sein und der aktuellen Sprache des Nutzers entsprechen. Android Auto und Android Automotive OS können dem Nutzer die Fehlermeldung dann anzeigen.
Wenn der Inhalt beispielsweise in der aktuellen Region des Nutzers nicht verfügbar ist, können Sie beim Festlegen der Fehlermeldung den Fehlercode ERROR_CODE_NOT_AVAILABLE_IN_REGION
verwenden.
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 finden Sie unter Mediensitzung verwenden: Status und Fehler.
Wenn ein Android Auto-Nutzer deine Smartphone-App öffnen muss, um einen Fehler zu beheben, gib diese Informationen in deiner Nachricht an den Nutzer weiter. Ihre Fehlermeldung könnte beispielsweise „Melde dich in [Name deiner App]“ anstelle von „Bitte melde dich an“ lauten.