Medien-Apps für Autos entwickeln

Mit Android Auto und Android Automotive OS kannst du die Inhalte deiner Medien-App in ihrem Auto nutzen. Eine Medien-App für Autos muss einen Medienbrowserdienst bieten damit Android Auto und Android Automotive OS oder eine andere App Ihre Inhalte finden und anzeigen kann.

In diesem Leitfaden wird davon ausgegangen, dass Sie bereits eine Medien-App haben, die Audioinhalte auf einem und dass Ihre Medien-App der Medien-App von Android entspricht Architektur.

In diesem Leitfaden werden die erforderlichen Komponenten eines MediaBrowserService und MediaSession, die deine App für Android Auto oder Android benötigt Automotive OS Nachdem Sie die Kernmedieninfrastruktur fertiggestellt haben, Unterstützung für Android Auto und Unterstützung für Android Automotive OS zu Ihren Medien

Hinweis

  1. Lesen Sie die Dokumentation zur Android Media API.
  2. Lesen Sie den Hilfeartikel Medien-Apps erstellen. für Designberatung.
  3. Sehen Sie sich die in diesem Abschnitt aufgeführten wichtigsten Begriffe und Konzepte noch einmal an.

Wichtige Begriffe und Konzepte

Medienbrowserdienst
Ein von Ihrer Medien-App implementierter Android-Dienst, der den MediaBrowserServiceCompat der API erstellen. Deine App verwendet diesen Dienst, um seine Inhalte verfügbar zu machen.
Medienbrowser
Eine API, die von Medien-Apps verwendet wird, um Medienbrowserdienste zu erkennen und Inhalte anzuzeigen für ihre Inhalte. Android Auto und Android Automotive OS nutzen einen Medienbrowser, um den Medienbrowser Ihrer App zu finden.
Medienelement

Der Medienbrowser organisiert seinen Inhalt in einer Baumstruktur von MediaItem. Objekte. Ein Medienelement kann eines oder beide der folgenden Flags haben:

  • FLAG_PLAYABLE: Gibt an, dass das Element ein Blatt im Inhaltsbaum ist. Das Element steht für einen einzelnen Soundstream, z. B. einen Titel auf einem Album, in einem Hörbuch oder in einer Folge eines Podcasts.
  • FLAG_BROWSABLE: Gibt an, dass das Element ein Knoten im Inhaltsbaum ist und hat Kinder. Das Element steht beispielsweise für ein Album und die untergeordneten Elemente sind die Songs auf dem Album.

Ein Medienelement, das sowohl blätterbar als auch abspielbar ist, agiert wie eine Playlist. Sie können wählen Sie das Element selbst aus, um alle seine untergeordneten Elemente wiederzugeben, oder suchen Sie in den Kinder.

Fahrzeugoptimiert

Eine Aktivität für eine Android Automotive OS-App, die die Android Automotive OS-Designrichtlinien Die Oberfläche für diese Aktivitäten wird nicht von Android Automotive OS gezeichnet. müssen Sie sicherstellen, dass Ihre App den Designrichtlinien entspricht. In der Regel bietet größere Tippziele und Schriftgrößen, Unterstützung für Tag- und Nachtmodi sowie höhere Kontrastverhältnisse.

Fahrzeugoptimierte Benutzeroberflächen dürfen nur angezeigt werden, wenn Einschränkungen für die Nutzerfreundlichkeit sind nicht in Kraft, weil diese Benutzeroberflächen erfordern möglicherweise besondere Aufmerksamkeit oder Interaktion der Nutzenden. CUXR sind nicht aktiv, wenn das Fahrzeug steht oder geparkt ist, aber immer aktiv sind. wenn das Auto in Bewegung ist.

Sie müssen keine Aktivitäten für Android Auto entwerfen, und erstellt mithilfe der Informationen aus der Medienbrowserdienst.

Manifestdateien Ihrer App konfigurieren

Bevor Sie den Medienbrowserdienst erstellen können, müssen Sie Ihren den Manifestdateien der App.

Medienbrowserdienst deklarieren

Sowohl Android Auto als auch Android Automotive OS stellen über Ihr Medienbrowserdienst zum Durchsuchen von Medieninhalten. Medien deklarieren Browserdienst in deinem Manifest, um Android Auto und Android Automotive OS um den Dienst zu finden und eine Verbindung zu Ihrer App herzustellen.

Das folgende Code-Snippet zeigt, wie Sie Ihren Medienbrowserdienst in in deinem Manifest. Fügen Sie diesen Code in die Manifestdatei für Ihr Das Android Automotive OS-Modul und in der Manifestdatei für Ihre Smartphone-App

<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 festlegen, die Android Auto und Android Automotive OS nutzen können zur Darstellung Ihrer App in der System-UI. Es sind zwei Symboltypen erforderlich:

  • Launcher-Symbol
  • Attributionssymbol

Launcher-Symbol

Das Launcher-Symbol repräsentiert Ihre App in der System-Benutzeroberfläche, z. B. im Launcher und in der Leiste mit Symbolen. Sie können angeben, dass Sie das Symbol aus Ihre mobile App, um Ihre Auto-Medien-App mithilfe des folgenden Manifests darzustellen Erklärung:

<application
    ...
    android:icon="@mipmap/ic_launcher"
    ...
/>

Wenn Sie ein anderes Symbol als das Ihrer mobilen App verwenden möchten, legen Sie die Property android:icon fest. im Element <service> des Medienbrowserdienstes im Manifest:

<application>
    ...
    <service
        ...
        android:icon="@mipmap/auto_launcher"
        ...
    />
</application>

Attributionssymbol

Abbildung 1: Attributionssymbol auf der Medienkarte.

Das Symbol für die Namensnennung wird an Stellen verwendet, an denen Medieninhalte Vorrang haben, zum Beispiel auf Medienkarten. Vielleicht solltest du das kleine Symbol für Benachrichtigungen wiederverwenden. Dieses Symbol muss monochrom sein. Sie können ein Symbol angeben, das für mit der folgenden Manifest-Deklaration:

<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 MediaBrowserServiceCompat erweitern . Sowohl Android Auto als auch Android Automotive OS können deinen Dienst dann verwenden um Folgendes zu tun:

  • Durchsuchen Sie die Contenthierarchie Ihrer App, um dem Nutzer ein Menü anzuzeigen.
  • Token für MediaSessionCompat Ihrer App abrufen Objekt zur Steuerung der Audiowiedergabe.

Sie können Ihren Medienbrowser auch nutzen, um anderen Clients über deine App auf Medieninhalte zuzugreifen. Diese Medienclients können andere Apps auf einem oder ein anderer Remote-Client.

Workflow für Medienbrowser-Dienste

In diesem Abschnitt wird beschrieben, wie Android Automotive OS und Android Sie können in einem typischen Nutzerworkflow automatisch mit dem Medienbrowserdienst interagieren.

  1. Der Nutzer startet deine App unter Android Automotive OS oder Android Auto.
  2. Android Automotive OS oder Android Auto kontaktiert den Medienbrowser deiner App Dienst mithilfe der onCreate() . Bei der Implementierung der onCreate() müssen Sie eine MediaSessionCompat erstellen und registrieren. und das zugehörige Callback-Objekt enthält.
  3. Android Automotive OS oder Android Auto ruft die onGetRoot() deines Dienstes auf , um das Stammmedienelement in Ihrer Contenthierarchie abzurufen. Das Stammmedienelement wird nicht angezeigt. Stattdessen werden sie verwendet, um mehr Inhalte aus Ihrer App abzurufen.
  4. Android Automotive OS oder Android Auto ruft die onLoadChildren() , um die untergeordneten Elemente des Stammmedienelements abzurufen. Android Automotive OS und In Android Auto werden diese Medienelemente als oberste Ebene der Inhalte angezeigt. Weitere Informationen finden Sie unter Strukturieren Sie das Stammverzeichnis auf dieser Seite, um weitere Informationen zu erhalten. Informationen darüber, was das System auf dieser Ebene erwartet.
  5. Wenn der Nutzer ein durchsuchbares Medienelement auswählt, wird der onLoadChildren() wird erneut aufgerufen, um die untergeordneten Elemente des ausgewählten Menüelements abzurufen.
  6. Wenn der Nutzer ein abspielbares Medienelement, Android Automotive OS oder Android auswählt, Die entsprechende Callback-Methode für Mediensitzungen wird automatisch aufgerufen, um diese Aktion auszuführen.
  7. Sofern Ihre App dies unterstützt, können Nutzer auch in Ihren Inhalten suchen. In dieser Android Automotive OS oder Android Auto die onSearch() .

Contenthierarchie erstellen

Android Auto und Android Automotive OS rufen den Medienbrowserdienst Ihrer App auf, um herauszufinden, welche Inhalte verfügbar sind. Sie müssen zwei Methoden in Ihrem Medienbrowserdienst onGetRoot() und onLoadChildren()

onGetRoot implementieren

onGetRoot() Ihres Dienstes werden Informationen zum Stammknoten der Contenthierarchie zurückgegeben. Android Auto und Android Automotive OS verwenden diesen Root-Knoten, um den Rest des Ihre Inhalte mithilfe der onLoadChildren() .

Das folgende Code-Snippet zeigt eine einfache Implementierung des onGetRoot()-Methode:

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 onGetRoot(). in der Beispiel-App "Universal Android Music Player" auf GitHub.

Paketvalidierung für onGetRoot() hinzufügen

Bei einem Aufruf der onGetRoot() Ihres Dienstes übergibt das aufrufende Paket identifizierende Informationen an Ihren Dienst. Ihr kann anhand dieser Informationen entscheiden, ob das Paket auf Ihre Inhalte. Beispielsweise können Sie den Zugriff auf App-Inhalte auf eine Liste mit genehmigte Pakete, indem Sie die clientPackageName mit Ihrer Zulassungsliste vergleichen und Prüfen des Zertifikats, mit dem das APK des Pakets signiert wurde. Wenn das Paket nicht bestätigt werden, geben Sie null zurück, um den Zugriff auf Ihre Inhalte zu verweigern.

Um System-Apps wie Android Auto und Android Automotive OS zur Verfügung zu stellen, mit Zugriff auf Ihre Inhalte verwendet, muss Ihr Dienst immer einen Wert ungleich null zurückgeben. BrowserRoot, wenn diese System-Apps die onGetRoot() aufrufen . Die Signatur der Android Automotive OS-System-App kann je nach nach der Marke und dem Modell des Autos, sodass Sie Verbindungen von allen System-Apps, um Android Automotive OS zuverlässig zu unterstützen.

Das folgende Code-Snippet zeigt, wie Ihr Dienst überprüfen kann, ob das Das aufrufende Paket ist eine System-App:

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 dem PackageValidator- in der Beispiel-App "Universal Android Music Player" auf GitHub. Kurs ansehen ein ausführlicheres Beispiel zur Implementierung der Paketvalidierung für Ihre onGetRoot() des Dienstes .

Sie müssen nicht nur System-Apps, sondern auch Google Assistant verbinde dich mit deinem MediaBrowserService. Beachte, dass Google Assistant separate Paketnamen für das Smartphone, einschließlich Android Auto, und für Android Automotive OS.

onLoadChildren() implementieren

Nach Erhalt des Root-Knotenobjekts werden Android Auto und Android Automotive OS Erstellen eines übergeordneten Menüs durch Aufrufen von onLoadChildren() für das Root-Knotenobjekt, um dessen untergeordnete Elemente abzurufen. Client-Apps erstellen Untermenüs von und rufen diese Methode unter Verwendung von untergeordneten Knotenobjekten auf.

Jeder Knoten in Ihrer Contenthierarchie wird durch ein MediaBrowserCompat.MediaItem dargestellt. -Objekt enthält. Jedes dieser Medienelemente wird durch einen eindeutigen ID-String identifiziert. Kunde Apps behandeln diese ID-Strings als intransparente Tokens. Wenn eine Client-App Daten durchsuchen möchte an ein Untermenü senden oder ein Medienelement abspielen, gibt es das Token weiter. Ihre App ist verantwortlich zum Verknüpfen des Tokens mit dem entsprechenden Medienelement.

Das folgende Code-Snippet zeigt eine einfache Implementierung von 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 onLoadChildren() in der Beispiel-App "Universal Android Music Player" auf GitHub.

Stammmenü strukturieren

Abbildung 2: Stamminhalt wird als Navigationstab angezeigt.

Android Auto und Android Automotive OS haben spezifische Einschränkungen Struktur des Stammmenüs. Diese Informationen werden MediaBrowserService mitgeteilt über Stammhinweise, die durch das Argument Bundle gelesen werden können, das an onGetRoot() Wenn Sie diese Hinweise beachten, kann das System den Stamminhalt optimal anzeigen. als Navigationstabs. Wenn Sie diese Hinweise nicht beachten, entfernt oder vom System weniger gut sichtbar sind. Zwei Hinweise werden gesendet:

Verwenden Sie den folgenden Code, um die relevanten Stammhinweise zu lesen:

Kotlin

import androidx.media.utils.MediaConstants

// Later, in your MediaBrowserServiceCompat.
override fun onGetRoot(
    clientPackageName: String,
    clientUid: Int,
    rootHints: Bundle
): BrowserRoot {

  val maximumRootChildLimit = rootHints.getInt(
      MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT,
      /* defaultValue= */ 4)
  val supportedRootChildFlags = rootHints.getInt(
      MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS,
      /* defaultValue= */ MediaItem.FLAG_BROWSABLE)

  // Rest of method...
}

Java

import androidx.media.utils.MediaConstants;

// Later, in your MediaBrowserServiceCompat.
@Override
public BrowserRoot onGetRoot(
    String clientPackageName, int clientUid, Bundle rootHints) {

    int maximumRootChildLimit = rootHints.getInt(
        MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT,
        /* defaultValue= */ 4);
    int supportedRootChildFlags = rootHints.getInt(
        MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS,
        /* defaultValue= */ MediaItem.FLAG_BROWSABLE);

    // Rest of method...
}

Sie können die Logik für die Struktur Ihrer Contenthierarchie verzweigen. dieser Hinweise berücksichtigt werden, insbesondere wenn Ihre Hierarchie zwischen MediaBrowser-Integrationen außerhalb von Android Auto und Android Automotive OS. Wenn Sie normalerweise ein abspielbares Root-Element anzeigen, sollten Sie es verschachteln. unter einem durchsuchbaren Stammelement aufgrund des Werts der unterstützten Flags Tipp:

Neben den Root-Hinweisen sind noch ein paar weitere Richtlinien zu beachten, um sicherzustellen, dass Tabs optimal gerendert werden:

  • Stellen Sie für jedes Tabelement monochrome, vorzugsweise weiße Symbole bereit.
  • Geben Sie kurze, aber aussagekräftige Labels für jedes Tabelement an. Labels kurz halten verringert die Wahrscheinlichkeit, dass Strings abgeschnitten werden.

Media-Artwork anzeigen

Artwork für Medienelemente muss als lokaler URI übergeben werden mit einer der folgenden Methoden: ContentResolver.SCHEME_CONTENT oder ContentResolver.SCHEME_ANDROID_RESOURCE. Dieser lokale URI muss entweder in eine Bitmap oder ein Vektor-Drawable im Anwendungsressourcen. Für MediaDescriptionCompat-Objekte, die Elemente darstellen in in der Contenthierarchie übergeben Sie den URI über setIconUri(). Übergeben Sie für MediaMetadataCompat-Objekte, die das gerade wiedergegebene Element darstellen, den URI über putString(), mit einem der folgenden Schlüssel:

In den folgenden Schritten wird beschrieben, wie Sie Artwork aus einem Web-URI herunterladen und bereitstellen können. über einen lokalen URI. Ein vollständigeres Beispiel finden Sie in der Implementierung openFile() und die umliegenden Methoden in Universal Android Music Beispiel-App für Player.

  1. Erstellen Sie einen content://-URI, der dem Web-URI entspricht. Der Medienbrowser Dienst- und Mediensitzung geben diesen Inhalts-URI an Android Auto weiter 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();
    }
    
  2. Prüfen Sie bei der Implementierung von ContentProvider.openFile(), ob eine Datei für den entsprechenden URI vorhanden ist. Ist dies nicht der Fall, laden Sie die Bilddatei herunter und speichern Sie sie im Cache. Die 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 Erstellen von Inhalten Dienstanbieter.

Inhaltsstile anwenden

Nachdem Sie Ihre Contenthierarchie mit durchsuchbaren oder abspielbaren Elementen erstellt haben, können 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 werden Bilder gegenüber Titeln und Metadaten priorisiert.

Standardstile für Inhalte festlegen

Sie können globale Standardeinstellungen für die Anzeige Ihrer Medienelemente festlegen, indem Sie bestimmte Konstanten im Extra-Bundle BrowserRoot Ihres Dienstes onGetRoot() . Android Auto und Android Automotive OS lesen dieses Paket und suchen nach um den passenden Stil zu bestimmen.

Die folgenden Extras können als Schlüssel im Bundle verwendet werden:

Die Schlüssel können den folgenden ganzzahligen konstanten Werten zugeordnet werden, um die Präsentation dieser Elemente:

Im folgenden Code-Snippet sehen Sie, wie der Standardinhaltsstil durchsuchbare Elemente zu Rastern und abspielbare Elemente zu Listen:

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 Element festlegen

Mit der Content Style API können Sie den Standardinhaltsstil für beliebige die untergeordneten Elemente des durchsuchbaren Medienelements sowie jedes Medienelement selbst.

Um die Standardeinstellung für die untergeordneten Elemente eines durchsuchbaren Medienelements zu überschreiben, erstellen Sie ein Extras-Set in der MediaDescription des Medienelements und fügen Sie dasselbe hinzu. die zuvor genannten Hinweise. DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE gilt für alle spielbaren untergeordneten Elemente dieses Elements, während DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE gilt für dieses Element durchsuchbaren Kindern.

Um den Standardwert für ein bestimmtes Medienelement selbst zu überschreiben, nicht für dessen Kinder, erstelle ein Extras-Set unter MediaDescription des Medienelements und füge einen Hinweis mit dem Schlüssel DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM Verwenden Sie die zuvor beschriebenen Werte, um die Darstellung dieses Elements anzugeben.

Das folgende Code-Snippet zeigt, wie Sie ein durchsuchbares MediaItem-Element erstellen, überschreibt den Standardinhaltsstil sowohl für sich selbst als auch für die untergeordneten Elemente. Stile erstellen sich selbst als Kategorielistenelement, seine durchsuchbaren untergeordneten Elemente als Listenelemente und seine spielbare untergeordnete 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 ein Extras-Set in der MediaDescription deklarieren, die enthält eine Zuordnung mit dem Schlüssel DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE und einen identischen Stringwert. Lokalisieren Sie diesen String, der als Titel der Gruppe.

Im folgenden Code-Snippet sehen Sie, wie ein MediaItem mit einer Untergruppe erstellt wird Überschrift von "Songs":

Kotlin

import androidx.media.utils.MediaConstants

private fun createMediaItem(
    mediaId: String,
    folderName: String,
    iconUri: Uri
): MediaBrowser.MediaItem {
    val mediaDescriptionBuilder = MediaDescription.Builder()
    mediaDescriptionBuilder.setMediaId(mediaId)
    mediaDescriptionBuilder.setTitle(folderName)
    mediaDescriptionBuilder.setIconUri(iconUri)
    val extras = Bundle()
    extras.putString(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE,
        "Songs")
    mediaDescriptionBuilder.setExtras(extras)
    return MediaBrowser.MediaItem(
        mediaDescriptionBuilder.build(), /* playable or browsable flag*/)
}

Java

import androidx.media.utils.MediaConstants;

private MediaBrowser.MediaItem createMediaItem(String mediaId, String folderName, Uri iconUri) {
   MediaDescription.Builder mediaDescriptionBuilder = new MediaDescription.Builder();
   mediaDescriptionBuilder.setMediaId(mediaId);
   mediaDescriptionBuilder.setTitle(folderName);
   mediaDescriptionBuilder.setIconUri(iconUri);
   Bundle extras = new Bundle();
   extras.putString(
       MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE,
       "Songs");
   mediaDescriptionBuilder.setExtras(extras);
   return new MediaBrowser.MediaItem(
       mediaDescriptionBuilder.build(), /* playable or browsable flag*/);
}

Ihre App muss alle Medienelemente übergeben, die Sie als zusammenhängender Block. Angenommen, Sie möchten zwei Gruppen anzeigen, von Medienelementen, "Titel" und "Alben", in dieser Reihenfolge und Ihre App fünf Medienelemente in der folgenden Reihenfolge:

  1. Medienelement A mit extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  2. Medienelement B mit extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
  3. Medienelement C mit extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  4. Medienelement D mit extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  5. Medienelement E mit extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")

Da die Medienelemente für die "Songs" Gruppe und "Alben" Gruppe werden nicht beibehalten in zusammenhängenden Blöcken zusammen, Android Auto und Android Automotive OS interpretiert dies als die folgenden vier Gruppen:

  • Gruppe 1 namens „Songs“ mit Medienelement A
  • Gruppe 2 namens „Alben“ mit Medienelement B
  • Gruppe 3 namens „Songs“ mit den Medienelementen C und D
  • Gruppe 4 namens „Alben“ mit Medienelement E

Um diese Elemente in zwei Gruppen anzuzeigen, muss Ihre App die Medienelemente in der in folgender Reihenfolge:

  1. Medienelement A mit extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  2. Medienelement C mit extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  3. Medienelement D mit extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  4. Medienelement B mit extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
  5. Medienelement E mit extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")

Zusätzliche Metadatenindikatoren anzeigen

Sie können zusätzliche Metadaten-Indikatoren hinzufügen, um einen guten Überblick zu erhalten. Informationen für Inhalte in der Baumstruktur des Mediabrowsers und während der Wiedergabe Im Baum durchsuchen, Android Auto und Android Automotive OS lesen die zugehörigen Extras mit einem Element und suchen Sie nach bestimmten Konstanten, um zu bestimmen, welche Indikatoren Display. Während der Medienwiedergabe lesen Android Auto und Android Automotive OS die Metadaten für die Mediensitzung und achten Sie auf bestimmte Konstanten, angezeigt werden sollen.

Abbildung 3: Wiedergabeansicht mit Metadaten zur Identifizierung des Songs und Interpret sowie ein Symbol für anstößige Inhalte.

Abbildung 4: Suchansicht mit einem Punkt für nicht wiedergegebene Inhalte auf das erste Element und eine Fortschrittsanzeige für teilweise abgespielte Inhalte auf der Seite zweiten Element.

Die folgenden Konstanten können beide MediaItem-Beschreibungsextras und MediaMetadata Extras:

Die folgenden Konstanten können nur in MediaItem-Beschreibungsextras verwendet werden:

Anzeigen, die angezeigt werden, während der Nutzer im Medienstöber surft erstellen, erstellen Sie ein Extras-Set, das eine oder mehrere dieser Konstanten und übergeben Sie dieses Bundle an die Methode MediaDescription.Builder.setExtras().

Das folgende Code-Snippet zeigt, wie Indikatoren für explizite Medien Element, 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 */);

Um Hinweise für ein Medienelement anzuzeigen, das gerade abgespielt wird, hast du folgende Möglichkeiten: Deklarieren Sie Long-Werte für METADATA_KEY_IS_EXPLICIT oder EXTRA_DOWNLOAD_STATUS in: MediaMetadataCompat von mediaSession. Sie können den DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS oder DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE in der Wiedergabeansicht.

Das folgende Code-Snippet zeigt, wie angegeben wird, dass der aktuelle Titel im Wiedergabeansicht ist explizit und wird heruntergeladen:

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());

Aktualisiere die Fortschrittsanzeige in der Übersicht, während Inhalte abgespielt werden

Wie bereits erwähnt, können Sie DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE um eine Fortschrittsanzeige für teilweise abgespielte Inhalte im Suchansicht. Spielt ein Nutzer den teilweise abgespielten Inhalt jedoch Android Auto oder Android Automotive OS ausgeht, wird diese Anzeige mit der Zeit ungenau sind.

Für Android Auto und Android Automotive OS Damit die Fortschrittsanzeige immer auf dem neuesten Stand ist, können Sie zusätzliche Informationen in MediaMetadataCompat und PlaybackStateCompat, mit denen aktuelle Inhalte verknüpft werden sollen Medienelemente in der Ansicht zum Durchsuchen angezeigt. Die folgenden Anforderungen müssen für den Medienelement eine automatisch aktualisierte Fortschrittsanzeige zu erhalten:

Im folgenden Code-Snippet sehen Sie, wie angegeben wird, dass das aktuell abgespielte Element ist mit einem Element in der Übersicht verknüpft:

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());

Abbildung 5: Wiedergabeansicht mit der Option „Suchergebnisse“ für Anzeigen von Medieninhalten, die sich auf die Sprachsuche des Nutzers beziehen

Ihre App kann kontextbezogene Suchergebnisse bereitstellen, die Nutzern angezeigt werden, wenn wird eine Suchanfrage gestartet. Android Auto und Android Automotive OS-Sendung diese Ergebnisse über Benutzeroberflächen für Suchanfragen oder Angebote, die neu ausgerichtet sind, in früheren Sitzungen. Weitere Informationen finden Sie in der Unterstützung der Sprachbedienung in diesem Leitfaden.

Um blätterbare Suchergebnisse anzuzeigen, schließen Sie den Konstantenschlüssel ein BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED im Extras-Paket des onGetRoot()-Objekts Ihres Dienstes -Methode zur Zuordnung zum booleschen Wert true.

Das folgende Code-Snippet zeigt, wie die Unterstützung im 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);
}

Wenn du Suchergebnisse bereitstellen möchtest, musst du den onSearch() überschreiben in Ihrem Medienbrowserdienst auf. Android Auto und Android Automotive OS die Suchbegriffe des Nutzers an diese Methode weiterleiten, wenn ein Nutzer eine Suche aufruft die Abfrageoberfläche oder die Option „Suchergebnisse“.

Sie können die Suche Ergebnisse aus der onSearch()-Methode Ihres Dienstes mithilfe von title items damit sie leichter durchsuchbar sind. Wenn in Ihrer App beispielsweise Musik wiedergegeben wird, Suchergebnisse nach Album, Künstler und Songs sortieren.

Das folgende Code-Snippet zeigt eine einfache Implementierung der 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

Eine einzelne benutzerdefinierte Suchaktion.

Abbildung 6: Einzelne benutzerdefinierte Suchaktion

Mit benutzerdefinierten Suchaktionen können Sie benutzerdefinierte Symbole und Labels zu den MediaItem-Objekten in der Medien-App des Autos und verarbeiten Nutzerinteraktionen mit diese Aktionen durchführen. So kannst du die Funktionalität der Medien-App um eine zum Beispiel „Herunterladen“, „Zur Wiedergabeliste hinzufügen“, „Radio abspielen“ „Favorit“ oder „Entfernen“ Aktionen.

Ein Dreipunkt-Menü für benutzerdefinierte Suchaktionen.

Abbildung 7: Überlauf der benutzerdefinierten Suchaktion

Wenn es mehr benutzerdefinierte Aktionen gibt, als der OEM zulässt, wird eine Dreipunkt-Menü angezeigt.

So funktioniert es:

Jede benutzerdefinierte Suchaktion wird wie folgt definiert:

  • Eine Aktions-ID (ein eindeutiger String-Identifikator)
  • Ein Aktionslabel (der Text, der dem Nutzer angezeigt wird)
  • URI für ein Aktionssymbol (ein Vektor-Drawable, das gefärbt werden kann)

Sie definieren eine globale Liste von benutzerdefinierten Suchaktionen im Rahmen Ihres BrowseRoot Dann 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 dann die Aktion ausführen und die Liste Aktionen für MediaItem, falls erforderlich. Dies ist nützlich für zustandsorientierte Aktionen z. B. „Favorit“ und „Herunterladen“. Für Aktionen, die nicht aktualisiert werden müssen, z. B. „Wiedergabe“ Radio“ verwenden, müssen Sie die Liste der Aktionen nicht aktualisieren.

Benutzerdefinierte Suchaktionen im Stamm eines Suchknotens.

Abbildung 8: Symbolleiste für benutzerdefinierte Suchaktionen

Sie können auch benutzerdefinierte Suchaktionen an den Stamm des Suchknotens anhängen. Diese Aktionen werden in einer sekundären Symbolleiste unterhalb der Hauptsymbolleiste angezeigt.

So implementieren Sie benutzerdefinierte Suchaktionen

So fügen Sie Ihrem Projekt benutzerdefinierte Suchaktionen hinzu:

  1. Zwei Methoden in Ihrem MediaBrowserServiceCompat Implementierung: <ph type="x-smartling-placeholder">
  2. Parsen Sie die Aktionslimits während der Laufzeit: <ph type="x-smartling-placeholder">
      </ph>
    • Holen Sie sich in onGetRoot() die maximal zulässige Anzahl an Aktionen für jede MediaItem mit dem Schlüssel BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT in rootHints Bundle. Eine Grenze von 0 bedeutet, dass das Element nicht vom System unterstützt.
  3. Erstellen Sie die globale Liste benutzerdefinierter Suchaktionen: <ph type="x-smartling-placeholder">
      </ph>
    • Erstellen Sie 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ügen Sie alle Bundle-Aktionsobjekte einer Liste hinzu.
  4. Fügen Sie die globale Liste zu BrowseRoot hinzu: <ph type="x-smartling-placeholder">
  5. Fügen Sie Ihren MediaItem-Objekten Aktionen hinzu: <ph type="x-smartling-placeholder">
      </ph>
    • Sie können einzelnen MediaItem-Objekten Aktionen hinzufügen, indem Sie den Parameter Liste der Aktions-IDs in den MediaDescriptionCompat-Extras mit dem Schlüssel DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST Diese Liste muss eine Teilmenge der globalen Liste der Aktionen sein, die Sie in BrowseRoot.
  6. Aktionen verarbeiten und Fortschritt oder Ergebnisse zurückgeben: <ph type="x-smartling-placeholder">

Hier sind einige Änderungen, die du in deinem BrowserServiceCompat vornehmen kannst, um loszulegen mit benutzerdefinierten Suchaktionen.

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

Überprüfe, wie viele benutzerdefinierte Suchaktionen unterstützt werden.

public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, Bundle rootHints) {
    rootHints.getInt(
            MediaConstants.BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT, 0)
}

Benutzerdefinierte Suchaktion erstellen

Jede Aktion muss in einer separaten Bundle zusammengefasst werden.

  • Aktions-ID
    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID,
                    "<ACTION_ID>")
    
  • Aktionslabel
    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL,
                    "<ACTION_LABEL>")
    
  • URI für Aktionssymbol
    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI,
                    "<ACTION_ICON_URI>")
    

Benutzerdefinierte Suchaktionen zu Parceable ArrayList hinzufügen

Fügen Sie alle Bundle-Objekte der benutzerdefinierten Suchaktion 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;
}

Liste der benutzerdefinierten Suchaktionen zum 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;
}

Einem MediaItem Aktionen 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-Build-Ergebnis

  • Analysieren Sie die mediaId aus Bundle extras:
    @Override
    public void onCustomAction(
              @NonNull String action, Bundle extras, @NonNull Result<Bundle> result){
      String mediaId = extras.getString(MediaConstans.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID);
    }
    
  • Für asynchrone Ergebnisse trennen Sie das Ergebnis. result.detach()
  • Build-Ergebnis-Bundle <ph type="x-smartling-placeholder">
      </ph>
    • Nachricht an Nutzer
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE,
                mContext.getString(stringRes))
      
    • Artikel aktualisieren(um Aktionen in einem Artikel zu aktualisieren)
      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);
      
  • Wenn ein Fehler auftritt, rufen Sie result.sendError(resultBundle). auf.
  • Wenn ein Fortschritt angezeigt wird, rufe result.sendProgressUpdate(resultBundle) auf.
  • Rufe zum Abschluss result.sendResult(resultBundle) auf.

Aktionsstatus aktualisieren

Wenn Sie die Methode result.sendProgressUpdate(resultBundle) mit dem Parameter EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM können Sie MediaItem aktualisieren, um den neuen Status der Aktion widerzuspiegeln. Dieses können Sie den Nutzenden in Echtzeit Feedback zum Fortschritt geben Ergebnis ihrer Handlung.

Beispiel: Download-Aktion

Hier ist ein Beispiel, wie Sie mit dieser Funktion eine Downloadaktion implementieren können. mit drei Status:

  1. Herunterladen: Dies ist der anfängliche Status der Aktion. Wenn der Nutzer können Sie stattdessen „Wird heruntergeladen“ verwenden, und rufen Sie sendProgressUpdate, um die UI zu aktualisieren.
  2. Downloading: Dieser Status zeigt an, dass der Download läuft. Sie können Verwenden Sie diesen Status, um dem Nutzer eine Fortschrittsanzeige oder einen anderen Indikator anzuzeigen.
  3. Heruntergeladen: Dieser Status zeigt an, dass der Download abgeschlossen ist. Wenn der Parameter wird der Download beendet, mit „Heruntergeladen“ und rufen Sie sendResult mit dem EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM um anzugeben, dass das Element aktualisiert werden soll. Außerdem können Sie die EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE um dem Nutzer eine Erfolgsmeldung anzuzeigen.

Auf diese Weise können Sie den Nutzenden klares Feedback zum Download geben. Prozess und seinen aktuellen Status. Mit Symbolen können Sie noch mehr Details hinzufügen, Downloadstatus von 25%, 50%, 75 %.

Beispiel: Lieblingsaktion

Ein weiteres Beispiel ist eine Lieblingsaktion mit zwei Status:

  1. Favorit: Diese Aktion wird für Elemente angezeigt, die nicht im Favoritenliste des Nutzers. Wenn der Nutzer diese Aktion auswählt, kannst du sie austauschen. mit „Zu Favoriten hinzugefügt“ und rufe sendResult mit der EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM um die Benutzeroberfläche zu aktualisieren.
  2. In Favoriten: Diese Aktion wird für Elemente angezeigt, die sich in den Favoritenliste. Wenn der Nutzer diese Aktion auswählt, kannst du sie austauschen durch „Favorit“ und rufe sendResult mit der EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM um die Benutzeroberfläche zu aktualisieren.

Dieser Ansatz bietet Nutzern eine klare und einheitliche Möglichkeit, Favoriten hinzufügen.

Diese Beispiele veranschaulichen die Flexibilität von benutzerdefinierten Suchaktionen verschiedene Funktionen mit Echtzeit-Feedback für für eine verbesserte Nutzererfahrung in der Medien-App des Autos.

Ein vollständiges Beispiel für die Implementierung dieser Funktion finden Sie in der TestMediaApp

Wiedergabesteuerung aktivieren

Android Auto und Android Automotive OS senden Befehle zur Wiedergabesteuerung MediaSessionCompat Ihres Dienstes. Sie müssen eine Sitzung registrieren und die zugehörigen Callback-Methoden implementieren.

Mediensitzung registrieren

Im onCreate() des Medienbrowserdienstes eine MediaSessionCompat-Datei erstellen, 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 Sie das Mediensitzungsobjekt erstellen, legen Sie ein Callback-Objekt fest, das verwendet wird. für Anfragen zur Wiedergabesteuerung. Sie erstellen dieses Callback-Objekt, indem Sie Bereitstellung der MediaSessionCompat.Callback -Klasse für Ihre App. Im nächsten Abschnitt wird die Implementierung dieses Objekts erläutert.

Wiedergabebefehle implementieren

Wenn ein Nutzer die Wiedergabe eines Medienelements aus deiner App anfordert, wird Android Automotive Betriebssystem und Android Auto verwenden den MediaSessionCompat.Callback Kurs aus dem MediaSessionCompat Ihrer App -Objekt, das sie vom Medienbrowserdienst Ihrer App erhalten haben. Wenn ein Nutzer möchte die Wiedergabe von Inhalten steuern, indem sie z. B. die Wiedergabe anhalten oder zur beim nächsten Track, Android Auto und Android Automotive OS einen der Callbacks aufrufen, Methoden des Objekts.

Damit die Wiedergabe von Inhalten verarbeitet werden kann, muss deine App die abstrakte MediaSessionCompat.Callback-Funktion erweitern und implementiere die von deiner App unterstützten Methoden.

Implementieren Sie alle folgenden Callback-Methoden, die für die Art der Inhalte, die Ihre App bietet:

onPrepare()
Wird aufgerufen, wenn die Mediaquelle geändert wird. Android Automotive OS ruft außerdem diese Methode sofort nach dem Booten. Deine Medien-App muss dies implementieren .
onPlay()
Wird aufgerufen, wenn der Nutzer „Spielen“ auswählt, ohne ein bestimmtes Element auszuwählen. Ihr müssen die Standardinhalte der App wiedergeben. Wenn die Wiedergabe pausiert wurde, onPause(), dein setzt die Wiedergabe fort.

Hinweis:Ihre App sollte nicht automatisch mit der Wiedergabe von Musik beginnen. wenn Android Automotive OS oder Android Auto eine Verbindung zu Ihrem Medienbrowser herstellen Service. Weitere Informationen finden Sie im Abschnitt über Festlegen des anfänglichen Wiedergabestatus

onPlayFromMediaId()
Wird aufgerufen, wenn der Nutzer entscheidet, ein bestimmtes Element abzuspielen. Die Methode wurde übergeben. Die ID, die Ihr Medienbrowserdienst zugewiesen hat zum Medienelement in Ihrer Contenthierarchie hinzugefügt.
onPlayFromSearch()
Wird aufgerufen, wenn der Nutzer sich für eine Suchanfrage entscheidet. Die App muss treffen Sie auf Grundlage der übergebenen Suchzeichenfolge eine geeignete Entscheidung.
onPause()
Wird aufgerufen, wenn der Nutzer die Wiedergabe pausiert.
onSkipToNext()
Wird aufgerufen, wenn der Nutzer entscheidet, zum nächsten Element zu springen.
onSkipToPrevious()
Wird aufgerufen, wenn der Nutzer entscheidet, zum vorherigen Element zu springen.
onStop()
Wird aufgerufen, wenn der Nutzer die Wiedergabe beendet.

Überschreiben Sie diese Methoden in Ihrer App, um die gewünschten Funktionen bereitzustellen. Ich Sie müssen keine Methode implementieren, wenn ihre Funktionalität nicht von Ihrer App unterstützt wird. Für Spielt Ihre App beispielsweise einen Livestream ab, etwa eine Sportübertragung, die Methode onSkipToNext() nicht implementieren. Sie können die Standardeinstellung Implementierung von onSkipToNext().

Ihre App benötigt keine spezielle Logik, um Inhalte über die Lautsprechern. Wenn deine App eine Anfrage zur Wiedergabe von Inhalten erhält, kann sie Audio abspielen wie Inhalte über eine die über die Lautsprecher oder Kopfhörer des Smartphones ausgeliefert werden. Android Auto und Android Automotive OS automatisch an das System des Autos zur Wiedergabe über den die Lautsprecher des Autos.

Weitere Informationen zum Abspielen von Audioinhalten finden Sie unter MediaPlayer – Übersicht Übersicht über die Audio-App, und die ExoPlayer-Übersicht.

Standardmäßige Wiedergabeaktionen festlegen

Die Wiedergabesteuerung von Android Auto und Android Automotive OS Aktionen, die in der PlaybackStateCompat aktiviert sind -Objekt enthält.

Standardmäßig muss Ihre App die folgenden Aktionen unterstützen:

Deine App kann außerdem die folgenden Aktionen unterstützen, wenn sie relevant für Inhalte der App:

Darüber hinaus haben Sie die Möglichkeit, eine Warteschlange für die Wiedergabe zu erstellen, die für alle Nutzer nicht unbedingt erforderlich. Rufen Sie dazu die Methode setQueue() auf. und setQueueTitle() die ACTION_SKIP_TO_QUEUE_ITEM-Funktion zu aktivieren, Aktion und definiere den Callback onSkipToQueueItem().

Sie können auch das Symbol Läuft gerade unterstützen, das anzeigt, was das gerade läuft. Rufen Sie dazu die Methode setActiveQueueItemId() auf. und übergeben Sie die ID des aktuell in der Warteschlange wiedergegebenen Elements. Erforderliche Schritte setActiveQueueItemId() bei jeder Änderung der Warteschlange aktualisieren.

Android Auto- und Android Automotive OS-Schaltflächen auf dem Display für jede aktivierte Aktion und der Wiedergabeliste. Wenn die Tasten klickt, ruft das System den entsprechenden Callback von MediaSessionCompat.Callback

Ungenutzte Flächen reservieren

Android Auto und Android Automotive OS reservieren in der Benutzeroberfläche Aktionen „ACTION_SKIP_TO_PREVIOUS“ und „ACTION_SKIP_TO_NEXT“. Wenn Ihre App keine dieser Funktionen unterstützt, verwenden Android Auto und Android Automotive OS Bereich zum Anzeigen von benutzerdefinierten Aktionen, die Sie erstellen.

Wenn Sie diese Bereiche nicht mit benutzerdefinierten Aktionen füllen möchten, können Sie damit Android Auto und Android Automotive OS wenn deine App die entsprechende Funktion nicht unterstützt. Rufen Sie dazu setExtras() mit einem Extra-Bundle, das Konstanten enthält, die dem reservierten Funktionen. 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 in der Bündeln und verwenden Sie den booleschen Wert true für die zugehörigen Werte.

Anfänglichen Wiedergabestatus festlegen

Wenn Android Auto und Android Automotive OS mit deinem Medienbrowser kommunizieren übermittelt, sendet Ihre Mediensitzung den Status der Inhaltswiedergabe mithilfe von PlaybackStateCompat. Deine App sollte nicht automatisch mit der Wiedergabe von Musik beginnen, wenn Android Automotive OS oder Android Auto eine Verbindung zu Ihrem Medienbrowser herstellen. Verwenden Sie stattdessen Android und Android Automotive OS, um die Wiedergabe je nach Status oder Nutzeraktionen.

Legen Sie dazu den anfänglichen PlaybackStateCompat fest. Ihrer Mediensitzung zu STATE_STOPPED, STATE_PAUSED STATE_NONE oder STATE_ERROR.

Mediensitzungen in Android Auto und Android Automotive OS dauern nur Dauer der Fahrt, sodass die Nutzer diese Sitzungen häufig starten und beenden. Bis nahtlose Fahrt zwischen den Fahrten fördern, sodass die Medien-App um die Anfrage fortzusetzen, kann der Nutzer automatisch dort weitermachen, wo er aufgehört hat. deaktiviert, z. B. das zuletzt wiedergegebene Medienelement, PlaybackStateCompat, und der Warteschlange.

Benutzerdefinierte Wiedergabeaktionen hinzufügen

Du kannst benutzerdefinierte Wiedergabeaktionen hinzufügen, um zusätzliche Aktionen anzuzeigen, die deine Medien-App unterstützt. Wenn der Platz ausreicht (und nicht reserviert ist), fügt Android den benutzerdefinierte Aktionen an die Transportsteuerungen an. Andernfalls werden die benutzerdefinierten Aktionen im Dreipunkt-Menü angezeigt. Benutzerdefinierte Aktionen werden in der Reihenfolge angezeigt werden sie PlaybackStateCompat hinzugefügt.

Benutzerdefinierte Aktionen verwenden, um ein Verhalten zu ermöglichen, das sich vom Standardverhalten unterscheidet Aktionen. Verwenden Sie sie nicht, um Standardtechnologien zu ersetzen oder zu duplizieren. Aktionen.

Mit dem addCustomAction() können Sie benutzerdefinierte Aktionen hinzufügen. in der PlaybackStateCompat.Builder-Datei .

Das folgende Code-Snippet zeigt, wie Sie ein benutzerdefiniertes Aktion:

Kotlin

stateBuilder.addCustomAction(
    PlaybackStateCompat.CustomAction.Builder(
        CUSTOM_ACTION_START_RADIO_FROM_MEDIA,
        resources.getString(R.string.start_radio_from_media),
        startRadioFromMediaIcon
    ).run {
        setExtras(customActionExtras)
        build()
    }
)

Java

stateBuilder.addCustomAction(
    new PlaybackStateCompat.CustomAction.Builder(
        CUSTOM_ACTION_START_RADIO_FROM_MEDIA,
        resources.getString(R.string.start_radio_from_media),
        startRadioFromMediaIcon)
    .setExtras(customActionExtras)
    .build());

Ein ausführlicheres Beispiel für diese Methode finden Sie in der setCustomAction(). in der Beispiel-App "Universal Android Music Player" auf GitHub.

Nachdem Sie die benutzerdefinierte Aktion erstellt haben, kann Ihre Mediensitzung auf die Aktion reagieren durch Überschreiben des onCustomAction() .

Das folgende Code-Snippet zeigt, wie Ihre App auf eine Aktion „Radiokanal starten“:

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 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 die auf vielen verschiedenen Bildschirmgrößen und -dichten ausgeführt werden. müssen Vektor-Drawables sein. A Mit Vector Drawable kannst du Assets skalieren, ohne Details zu verlieren. Ein Vektor Drawable vereinfacht auch das Ausrichten der Kanten und Ecken an Pixelgrenzen bei kleinere Auflösungen.

Wenn eine benutzerdefinierte Aktion zustandsorientiert ist, z. B. wenn sie eine Wiedergabeeinstellung ein- oder ausschaltet, deaktiviert. Bieten Sie unterschiedliche Symbole für die verschiedenen Stadien an, damit Nutzende eine Änderung sehen, wenn sie die Aktion auswählen.

Alternative Symbolstile für deaktivierte Aktionen angeben

Wenn eine benutzerdefinierte Aktion für den aktuellen Kontext nicht verfügbar ist, tauschen Sie das benutzerdefinierte Aktionssymbol mit einem alternativen Symbol, das anzeigt, dass die Aktion deaktiviert ist.

Abbildung 6: Beispiele von benutzerdefinierten Aktionssymbolen

Audioformat angeben

Um anzugeben, dass für die aktuelle Wiedergabe von Medien ein spezielles Audioformat verwendet wird, kannst du Symbole angeben, die in Autos gerendert werden, die diese Funktion unterstützen. Ich kann das KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI und die KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI im Extras-Paket des aktuell wiedergegebenen Medienelements (übergeben an MediaSession.setMetadata(). Legen Sie beides fest: dieser Extras für unterschiedliche Layouts.

Außerdem können Sie den zusätzlichen Wert für KEY_IMMERSIVE_AUDIO festlegen. Autohersteller zu informieren, dass es sich um immersiven Audio handelt. Diese sollten vorsichtig sein, wenn ihr entscheidet, ob ihr Audioeffekte anwendet, die die immersive Inhalte zu erstellen.

Sie können das aktuell wiedergegebene Medienelement so konfigurieren, dass Untertitel, Beschreibung oder beide sind Links zu anderen Medienelementen. So können Nutzende schnell zu verwandte Artikel; z. B. zu anderen Songs desselben Künstlers, andere Folgen dieses Podcasts usw. unterstützt. Wenn das Auto diese Funktion unterstützt, können Nutzer können Sie auf den Link tippen, um zu diesen Inhalten zu gelangen.

Um Links hinzuzufügen, konfigurieren Sie die KEY_SUBTITLE_LINK_MEDIA_ID-Metadaten (um aus der Untertitel zu verlinken) oder KEY_DESCRIPTION_LINK_MEDIA_ID (für Verknüpfung von die Beschreibung). Weitere Informationen finden Sie in der entsprechenden Referenzdokumentation Metadatenfelder.

Sprachbedienung unterstützen

Ihre Medien-App muss die Sprachbedienung unterstützen, damit Fahrer und die praktische Erfahrung, die Ablenkungen minimiert. Wenn Ihre App zum Beispiel ein Medienelement spielt, kann der Nutzer sagen: „Spiel [Titel] ab“ um einen anderen Song abzuspielen, ohne den Sensor des Autos Display. Nutzer können Abfragen starten, indem sie auf die entsprechenden Schaltflächen das Lenkrad verwenden oder die Hotwords Ok Google sagen.

Wenn Android Auto oder Android Automotive OS eine Stimme erkennen und interpretiert Aktion wird diese Sprachbedienung der App über onPlayFromSearch() Beim Empfang dieses Callbacks findet die App Inhalte, die mit der query übereinstimmen. String und startet die Wiedergabe.

Nutzer können in ihrer Suchanfrage verschiedene Kategorien von Begriffen angeben: Genre, Künstler, Album, Titelname, Radiosender oder Playlist. Beim Erstellen unterstützen. Berücksichtigen Sie dabei alle Kategorien, die für Ihre App sinnvoll sind. Wenn Android Auto oder Android Automotive OS erkennt, bestimmten Kategorien hinzugefügt werden, werden Extras im extras-Parameter angehängt. Die können folgende Extras gesendet werden:

Berücksichtigen Sie einen leeren query-String, der gesendet werden kann durch Android Auto oder Android Automotive OS, wenn der Nutzer keine Suchbegriffe angibt. Beispiel: Der Nutzer sagt „Spiel Musik“. In diesem Fall könnte Ihre App einen vor Kurzem angehörten oder einen neu vorgeschlagenen Titel starten.

Wenn eine Suchanfrage nicht schnell verarbeitet werden kann, solltest du sie nicht in onPlayFromSearch() blockieren. Setze stattdessen den Wiedergabestatus auf STATE_CONNECTING. und die Suche in einem asynchronen Thread durchführen.

Sobald die Wiedergabe beginnt, können Sie die Warteschlange der Mediensitzung mit verwandte Inhalte. Wenn der Nutzer beispielsweise die Wiedergabe eines Albums anfordert, App die Playlist mit der Titelliste des Albums füllen. Erwägen Sie auch, durchsuchbare Suchergebnisse werden unterstützt, sodass Nutzer einen anderen Track suchen, der ihrer Suchanfrage entspricht.

Neben play Android Auto und Android Automotive OS Sprachbefehle erkennen, um die Wiedergabe zu steuern, z. B. „Musik pausieren“ und "nächste Song“ und ordnen Sie diese Befehle den entsprechenden Mediensitzungs-Callbacks zu. wie onPause() und onSkipToNext().

Ein detailliertes Beispiel für die Implementierung von sprachgesteuerten Wiedergabeaktionen in finden Sie unter Google Assistant und Medien-Apps.

Ablenkungsmaßnahmen implementieren

Weil das Smartphone eines Nutzers während der Nutzung von Android mit den Lautsprechern im Auto verbunden ist Automatisch angezeigt wird, müssen Sie zusätzliche Vorkehrungen treffen, damit der Fahrer nicht abgelenkt wird.

Alarme im Auto unterdrücken

Android Auto-Medien-Apps dürfen keine Audiowiedergabe über die Autolautsprecher starten wenn der Nutzer die Wiedergabe beispielsweise durch Drücken einer Wiedergabetaste startet. Auch ein vom Nutzer geplanter Wecker in deiner Medien-App darf nicht gestartet werden. Musik über die Autolautsprecher abzuspielen.

Um diese Anforderung zu erfüllen, kann CarConnection verwenden als Signal hinzu, bevor Audio wiedergegeben wird. Deine App kann prüfen, ob das Smartphone auf ein Autodisplay zu projizieren, indem LiveData für die Autoverbindung beobachtet wird. Typ und zu prüfen, ob der Wert CONNECTION_TYPE_PROJECTION

Wenn das Smartphone des Nutzers eine Projektion startet, müssen Medien-Apps, die Wecker unterstützen, eine Aktion ausführen Folgendes tun:

  • Deaktiviere den Alarm.
  • Alarm über STREAM_ALARM abspielen und über eine Benutzeroberfläche auf dem Smartphone-Display, um den Alarm zu deaktivieren.

Umgang mit Medienwerbung

Standardmäßig zeigt Android Auto eine Benachrichtigung an, wenn sich die Medienmetadaten ändern während einer Audiowiedergabesitzung. Wenn eine Medien-App von der Musikwiedergabe wechselt Werbung zu präsentieren, lenkt von einer Benachrichtigung an den Nutzer. So verhindern Sie, dass Android Auto eine Benachrichtigung anzeigt müssen Sie den Schlüssel für die Medienmetadaten METADATA_KEY_IS_ADVERTISEMENT bis METADATA_VALUE_ATTRIBUTE_PRESENT Dies wird 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 geben Sie mithilfe des setErrorMessage() eine Fehlermeldung an. . Weitere Informationen finden Sie unter PlaybackStateCompat. finden Sie eine Liste mit Fehlercodes, die Sie beim Festlegen der Fehlermeldung verwenden können. Fehlermeldungen müssen für den Nutzer sichtbar und mit den aktuellen Sprache. Android Auto und Android Automotive OS können dann den Fehler Nachricht an den Nutzer.

Wenn Inhalte in der aktuellen Region des Nutzers nicht verfügbar sind, haben Sie folgende Möglichkeiten: ERROR_CODE_NOT_AVAILABLE_IN_REGION verwenden Fehlercode beim Festlegen der Fehlermeldung.

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 Verwenden einer Mediensitzung: Status und Fehler.

Wenn ein Android Auto-Nutzer die App auf Ihrem Smartphone öffnen muss, um einen Fehler zu beheben, um dem Nutzer diese Informationen in Ihrer Nachricht zur Verfügung zu stellen. Beispiel: Ihr Fehler könnte die Meldung „In [Name Ihrer App] anmelden“ angezeigt werden. statt "Bitte melden Sie sich an".

Weitere Informationen