Android Auto y el SO Android Automotive (AAOS) llaman al servicio de navegador multimedia de tu app para descubrir qué contenido está disponible. Para ello, debes implementar estos dos métodos en tu servicio de navegador multimedia.
Implementa onGetRoot
El método onGetRoot de tu servicio muestra información sobre el nodo raíz
de tu jerarquía de contenido. Android Auto y AAOS usan este nodo raíz
para solicitar el resto del contenido mediante el onLoadChildren
método. Este fragmento de código muestra una implementación del método 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);
}
Para obtener un ejemplo detallado de este método, consulta onGetRoot en la app de ejemplo Universal
Android Music Player en GitHub.
Agrega validación de paquetes
Cuando se realiza una llamada al método onGetRoot de tu servicio, el paquete de llamadas
pasa información de identificación a tu servicio. Tu servicio puede usar esta información para decidir si ese paquete puede acceder a tu contenido.
Por ejemplo, puedes restringir el acceso al contenido de tu app a una lista de paquetes aprobados:
- Compara el
clientPackageNamecon tu lista de entidades permitidas. - Verifica el certificado que se usó para firmar el APK del paquete.
Si no se puede verificar el paquete, muestra null para denegar el acceso a tu contenido.
Para proporcionar a las apps del sistema, como Android Auto y AAOS, acceso a tu contenido, tu servicio debe mostrar un BrowserRoot que no sea nulo cuando estas apps del sistema llamen al método onGetRoot.
La firma de la app del sistema AAOS varía según la marca y el modelo de un automóvil. Asegúrate de permitir las conexiones de todas las apps del sistema para admitir AAOS.
Este fragmento de código muestra cómo tu servicio puede validar que el paquete de llamadas es una app del 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
}
Este fragmento de código es un extracto de la PackageValidator clase en la
app de ejemplo Universal Android Music Player en GitHub. Consulta esa clase para obtener un ejemplo más detallado de cómo implementar la validación de paquetes para el método onGetRoot de tu servicio.
Además de permitir las apps del sistema, debes permitir que el Asistente de Google se conecte a tu MediaBrowserService. El Asistente de Google usa diferentes nombres de paquetes
para sus apps para dispositivos móviles y AAOS.
Implementa onLoadChildren
Después de recibir el objeto del nodo raíz, Android Auto y AAOS
compilan un menú de nivel superior llamando a onLoadChildren en el objeto de nodo raíz
para obtener sus descendientes. Las apps cliente compilan submenús llamando al mismo método con los objetos del nodo descendiente.
Cada nodo de tu jerarquía de contenido está representado por un
MediaBrowserCompat.MediaItem objeto. Cada uno de estos elementos multimedia se identifica con una cadena de ID única. Las apps cliente tratan estas cadenas de ID como tokens opacos.
Cuando una app cliente quiere navegar a un submenú o reproducir un elemento multimedia, pasa el token. Tu app es responsable de asociar el token con el elemento multimedia adecuado.
Este fragmento de código muestra una implementación de 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 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<List<MediaBrowserCompat.MediaItem>> result) {
// Assume for example that the music catalog is already loaded/cached.
List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<>();
// 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);
}
Para ver un ejemplo de este método, consulta onLoadChildren en la
app de ejemplo Universal Android Music Player en GitHub.
Estructura el menú raíz
Android Auto y el SO Android Automotive tienen restricciones específicas sobre la estructura del menú raíz. Se comunican con MediaBrowserService a través de sugerencias de raíz, que se pueden leer con el argumento Bundle que se pasa a onGetRoot(). Cuando se siguen, estas sugerencias permiten que el sistema muestre el contenido raíz como pestañas de navegación. Si no sigues estas sugerencias, es posible que el sistema quite parte del contenido raíz o que sea menos fácil de descubrir.

Figura 1: Contenido raíz que se muestra como pestañas de navegación
Si aplicas estas sugerencias, el sistema mostrará el contenido raíz como pestañas de navegación. Si no aplicas estas sugerencias, es posible que se quite parte del contenido raíz o que sea menos fácil de descubrir. Estas sugerencias se transmiten de la siguiente manera:
Límite en la cantidad de elementos secundarios raíz: En la mayoría de los casos, se espera que este número sea cuatro, lo que significa que solo se pueden mostrar cuatro pestañas (o menos).
Marcas admitidas en los elementos secundarios raíz: Se espera que este valor sea
MediaItem#FLAG_BROWSABLE, lo que significa que solo los elementos explorables (no los elementos reproducibles) se pueden mostrar como pestañas.Límite en la cantidad de acciones de exploración personalizadas: Verifica cuántas acciones de exploración personalizadas se admiten.
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...
}
Puedes ramificar la lógica de la estructura de tu jerarquía de contenido en función de los valores de estas sugerencias, especialmente si tu jerarquía varía entre las integraciones de MediaBrowser de fuera de Android Auto y AAOS.
Por ejemplo, si sueles mostrar un elemento raíz reproducible, tal vez sea preferible que lo anides en un elemento raíz explorable, debido al valor de la sugerencia de marcas compatible.
Además de las sugerencias de raíz, usa estos lineamientos para renderizar pestañas de forma óptima:
Íconos monocromáticos (preferentemente blancos) para cada elemento de pestaña
Etiquetas cortas y significativas para cada elemento de pestaña (las etiquetas cortas reducen las probabilidades de que se trunquen)