Implementa acciones de exploración personalizadas

De manera similar a cómo usas las acciones de reproducción personalizadas para admitir capacidades únicas en la vista de reproducción, puedes usar acciones de exploración personalizadas para admitir capacidades únicas en las vistas de exploración. Por ejemplo, puedes usar acciones de exploración personalizadas para que los usuarios puedan descargar playlists o agregar un elemento a una fila.

Cuando hay más acciones personalizadas de las que muestra el fabricante de equipo original (OEM), se le muestra un menú ampliado al usuario. Cada acción de exploración personalizada se define con lo siguiente:

  • ID de acción: Identificador de cadena único
  • Etiqueta de acción: Texto que se muestra al usuario
  • Identificador de recursos uniforme (URI) del ícono de acción: Elemento de diseño vectorial que puede ajustarse

Menú ampliado de acciones de exploración personalizadas

Figura 1: Menú ampliado de acciones de exploración personalizadas.

Define una lista de acciones de exploración personalizadas a nivel global como parte de tu BrowseRoot. Luego, adjunta un subconjunto de estas acciones a los elementos MediaItem individuales.

Cuando un usuario interactúa con una acción de exploración personalizada, tu app recibe una devolución de llamada en onCustomAction. Luego, puedes controlar la acción y actualizar la lista de acciones para el elemento MediaItem si es necesario. Esto es útil para acciones con estado, como Favoritos y Descargar. En el caso de las acciones que no necesitan actualización, como Play Radio, no es necesario que actualices la lista de acciones.

Barra de herramientas de acciones de exploración personalizadas

Figura 2: Es la barra de herramientas de las acciones de exploración personalizadas.

También puedes adjuntar acciones de exploración personalizadas a la raíz de un nodo de exploración. Estas acciones se muestran en una barra de herramientas secundaria, debajo de la barra de herramientas principal.

Sigue estos pasos para agregar acciones de exploración personalizadas a tu app:

  1. Anula dos métodos en tu implementación de MediaBrowserServiceCompat:

  2. Analiza los límites de acciones en el tiempo de ejecución:

    En onGetRoot, obtén la cantidad máxima de acciones permitidas para cada elemento MediaItem usando la clave BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT en el objeto Bundle de rootHints. Un límite de 0 indica que el sistema no admite la función.

  3. Crea la lista global de acciones de exploración personalizadas. Para cada acción, crea un objeto Bundle con estas claves:

    • ID de acción EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID
    • Etiqueta de acción EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL
    • URI del ícono de acción EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI
  4. Agrega todos los objetos Bundle de acción a una lista.

  5. Agrega la lista global a tu BrowseRoot. En el objeto Bundle adicional de BrowseRoot, agrega la lista de acciones como un objeto ArrayList de Parcelable con la clave BROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST.

  6. Agrega acciones a tus objetos MediaItem. Puedes agregar acciones a objetos MediaItem individuales si incluyes la lista de IDs de acción en los elementos MediaDescriptionCompat adicionales con la clave DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST. Esta lista debe ser un subconjunto de la lista global de acciones que definiste en el objeto BrowseRoot.

  7. Controla las acciones y devuelve el progreso o los resultados:

Actualiza el estado de la acción

Para anular estos métodos en MediaBrowserServiceCompat, haz lo siguiente:

public void onLoadItem(String itemId, @NonNull Result<MediaBrowserCompat.MediaItem> result)

y

public void onCustomAction(@NonNull String action, Bundle extras, @NonNull Result<Bundle> result)

Analiza el límite de acciones

Comprueba cuántas acciones de exploración personalizadas se admiten:

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

Compila una acción de exploración personalizada

Cada acción debe empaquetarse en un objeto Bundle separado.

  • ID de acción:

    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID,
                    "<ACTION_ID>")
    
  • Etiqueta de acción:

    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL,
                    "<ACTION_LABEL>")
    
  • URI del ícono de acción:

    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI,
                    "<ACTION_ICON_URI>")
    

Agrega acciones de exploración personalizadas a ArrayList de Parcelable

Agrega todos los objetos Bundle de acciones de exploración personalizadas a un elemento ArrayList:

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

Agrega una lista de acciones de exploración personalizadas a la raíz de la exploración

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

Agrega acciones a un objeto MediaItem

Los IDs de acciones de exploración de un objeto MediaItem deben ser un subconjunto de la lista global de acciones de exploración que se proporciona en onGetRoot. Se ignoran las acciones que no estén en la lista global.

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

Compila el resultado de onCustomAction

Para compilar el resultado, haz lo siguiente:

  1. Analiza mediaId de 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);
                }
    
  2. Para los resultados asíncronos, desconecta el resultado, result.detach.

  3. Compila el paquete de resultados:

    1. Muestra un mensaje al usuario:

      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE,
                    mContext.getString(stringRes))
      
    2. Actualiza el elemento (usar para actualizar acciones en un elemento):

      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM, mediaId);
      
    3. Abre la vista de reproducción:

      //Shows user the PBV without changing the playback state
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_SHOW_PLAYING_ITEM, null);
      
    4. Actualiza el nodo de exploración:

      //Change current browse node to mediaId
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE, mediaId);
      
  4. Verifica el resultado:

    • Error: Call result.sendError(resultBundle)
    • Actualización del progreso: Llama a result.sendProgressUpdate(resultBundle)
    • Finalizar: Llamar a result.sendResult(resultBundle)

Actualiza el estado de la acción

Si usas el método result.sendProgressUpdate(resultBundle) con la clave EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM, puedes actualizar el objeto MediaItem para que refleje el nuevo estado de la acción. De esta manera, puedes proporcionarle comentarios en tiempo real al usuario sobre el progreso y el resultado de su acción.

Ejemplo de acción de descarga

En este ejemplo, se describe cómo puedes usar esta función para implementar una acción de descarga con tres estados:

  • Descargar es el estado inicial de la acción. Cuando el usuario selecciona esta acción, puedes cambiarla por Descargando y llamar a sendProgressUpdate para actualizar la interfaz de usuario (IU).

  • El estado Descargando indica que la descarga está en curso. Puedes usar este estado para mostrarle al usuario una barra de progreso o algún otro indicador.

  • El estado Descargado indica que se completó la descarga. Cuando finaliza la descarga, puedes cambiar Descargando por Instalado y llamar a sendResult con la clave EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM para indicar que el elemento debe actualizarse. Además, puedes usar la clave EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE para mostrarle un mensaje de confirmación al usuario.

Este enfoque te permite proporcionarle comentarios claros al usuario sobre el proceso de descarga y su estado actual. Puedes agregar aún más detalles con íconos que muestren los estados de descarga del 25%, 50% y 75%.

Ejemplo de acción de favoritos

En este otro ejemplo, se muestra una acción de favoritos con dos estados:

  • Se muestra Favoritos para los elementos que no están en la lista de favoritos del usuario. Cuando el usuario selecciona esta acción, cámbiala por Se agregó a Favoritos y llama a sendResult con la clave EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM para actualizar la IU.

  • Se muestra Se agregó a Favoritos para los elementos de la lista de favoritos del usuario. Cuando el usuario selecciona esta acción, cámbiala por Favoritos y llama a sendResult con la clave EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM para actualizar la IU.

Este enfoque proporciona una forma clara y coherente para que los usuarios administren sus elementos favoritos. Estos ejemplos muestran la flexibilidad de las acciones de exploración personalizadas y la manera en que puedes usarlas para implementar una variedad de funcionalidades con comentarios en tiempo real para mejorar la experiencia del usuario en la app de música del automóvil.

Puedes ver una implementación de ejemplo completa de esta función en el proyecto TestMediaApp.