Creare la gerarchia dei contenuti

Android Auto e Android Automotive OS (AAOS) chiamano il servizio di esplorazione dei contenuti multimediali della tua app per scoprire quali contenuti sono disponibili. Per supportare questa funzionalità, implementa questi due metodi nel servizio di esplorazione dei contenuti multimediali.

Implementare onGetRoot

Il metodo onGetRoot del servizio restituisce informazioni sul nodo radice della gerarchia dei contenuti. Android Auto e AAOS utilizzano questo nodo radice per richiedere il resto dei contenuti utilizzando il metodo onLoadChildren. Questo snippet di codice mostra un'implementazione del metodo 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);
}

Per un esempio dettagliato di questo metodo, consulta onGetRoot nell'app di esempio Universal Android Music Player su GitHub.

Aggiungere la convalida del pacchetto

Quando viene effettuata una chiamata al metodo onGetRoot del servizio, il pacchetto chiamante trasmette le informazioni identificative al servizio. Il tuo servizio può utilizzare queste informazioni per decidere se il pacchetto può accedere ai tuoi contenuti.

Ad esempio, puoi limitare l'accesso ai contenuti della tua app a un elenco di pacchetti approvati:

  • Confronta clientPackageName con la tua lista consentita.
  • Verifica il certificato utilizzato per firmare l'APK per il pacchetto.

Se il pacchetto non può essere verificato, premi null per negare l'accesso ai tuoi contenuti.

Per fornire alle app di sistema, come Android Auto e AAOS, l'accesso ai tuoi contenuti, il tuo servizio deve restituire un valore non nullo BrowserRoot quando queste app di sistema chiamano il metodo onGetRoot.

La firma dell'app di sistema AAOS varia a seconda della marca e del modello di un'auto. Assicurati di consentire le connessioni da tutte le app di sistema per supportare AAOS.

Questo snippet di codice mostra come il tuo servizio può verificare che il pacchetto chiamante sia un'app di sistema:

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
}

Questo snippet di codice è un estratto della classe PackageValidator nell'app di esempio Universal Android Music Player su GitHub. Consulta questa classe per un esempio più dettagliato di come implementare la convalida dei pacchetti per il metodo onGetRoot del tuo servizio.

Oltre a consentire le app di sistema, devi consentire all'Assistente Google di connettersi al tuo MediaBrowserService. L'Assistente Google utilizza nomi di pacchetti separati per lo smartphone, che include Android Auto Android AAOS.

Implementare onLoadChildren

Dopo aver ricevuto l'oggetto nodo radice, Android Auto e AAOS creano un menu di primo livello chiamando onLoadChildren sull'oggetto nodo radice per ottenere i relativi discendenti. Le app client creano i sottomenu chiamando questo stesso metodo utilizzando gli oggetti nodo discendenti.

Ogni nodo della gerarchia dei contenuti è rappresentato da un oggetto MediaBrowserCompat.MediaItem. Ciascuno di questi elementi multimediali è identificato da una stringa ID univoca. Le app client trattano queste stringhe ID come token opachi.

Quando un'app client vuole passare a un sottomenu o riprodurre un elemento multimediale, passa il token. La tua app è responsabile dell'associazione del token all'elemento multimediale appropriato.

Questo snippet di codice mostra un'implementazione di 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&lt;MediaBrowserCompat.MediaItem> = mutableListOf()

    // Check if 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 descendants of that menu in the mediaItems list.
    }
    result.sendResult(mediaItems)
}

Java

@Override
public void onLoadChildren(final String parentMediaId,
    final Result&lt;List&lt;MediaBrowserCompat.MediaItem>> result) {

    // Assume for example that the music catalog is already loaded/cached.

    List&lt;MediaBrowserCompat.MediaItem> mediaItems = new ArrayList&lt;>();

    // Check if 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 descendants of that menu in the mediaItems list.
    }
    result.sendResult(mediaItems);
}

Per visualizzare un esempio di questo metodo, consulta onLoadChildren nell'app di esempio Universal Android Music Player su GitHub.

Strutturare il menu principale

Android Auto e Android Automotive OS hanno vincoli specifici sulla struttura del menu principale. Questi vengono comunicati a MediaBrowserService tramite suggerimenti della radice, che possono essere letti tramite l'argomento Bundle passato a onGetRoot(). Se seguiti, questi suggerimenti consentono al sistema di visualizzare i contenuti principali come schede di navigazione. Se non segui questi suggerimenti, alcuni contenuti principali potrebbero essere eliminati o resi meno rilevabili dal sistema.

Contenuti di primo livello visualizzati come schede di navigazione

Figura 1. Contenuti di primo livello visualizzati come schede di navigazione.

Se applichi questi suggerimenti, il sistema visualizza i contenuti principali come schede di navigazione. Se non applichi questi suggerimenti, alcuni contenuti principali potrebbero essere eliminati o resi meno rilevabili. Questi suggerimenti vengono trasmessi:

Kotlin

import androidx.media.utils.MediaConstants

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...
}

Puoi scegliere di ramificare la logica per la struttura della gerarchia dei contenuti in base ai valori di questi suggerimenti, in particolare se la gerarchia varia tra le integrazioni MediaBrowser al di fuori di Android Auto e AAOS.

Ad esempio, se di solito mostri un elemento riproducibile principale, potresti volerlo nidificare in un elemento principale sfogliabile a causa del valore del suggerimento dei flag supportati.

Oltre ai suggerimenti per la radice, utilizza queste linee guida per eseguire il rendering ottimale delle schede:

  • Icone monocromatiche (preferibilmente bianche) per ogni elemento della scheda

  • Etichette brevi e significative per ogni elemento della scheda (le etichette brevi riducono le probabilità che vengano troncate)