Implementare azioni di navigazione personalizzate

Analogamente a come utilizzi le azioni di riproduzione personalizzate per supportare funzionalità uniche nella visualizzazione di riproduzione, puoi utilizzare le azioni di navigazione personalizzate per supportare funzionalità uniche nelle visualizzazioni di navigazione. Ad esempio, puoi utilizzare azioni di navigazione personalizzate in modo che gli utenti possano scaricare playlist o aggiungere un elemento a una coda.

Quando esistono più azioni personalizzate di quelle visualizzate dal produttore di apparecchiature originali (OEM), all'utente viene mostrato un menu overflow. Ogni azione di navigazione personalizzata è definita da:

  • ID azione:identificatore stringa univoco
  • Etichetta azione:testo visualizzato dall'utente
  • URI (Uniform Resource Identifier) dell'icona di azione: risorsa disegnabile vettoriale che può essere colorata

Overflow dell'azione di navigazione personalizzata

Figura 1. Overflow dell'azione di navigazione personalizzata.

Definisci un elenco di azioni di navigazione personalizzate a livello globale nell'ambito del tuo BrowseRoot. Poi associa un sottoinsieme di queste azioni a singoli MediaItem.

Quando un utente interagisce con un'azione di navigazione personalizzata, la tua app riceve un callback in onCustomAction. Quindi, gestisci l'azione e aggiorna l'elenco delle azioni per MediaItem, se necessario. Questa funzionalità è utile per le azioni stateful come Aggiungi ai preferiti e Scarica. Per le azioni che non richiedono aggiornamenti, come Play Radio, non è necessario aggiornare l'elenco delle azioni.

Barra degli strumenti delle azioni di navigazione personalizzate

Figura 2. Barra degli strumenti delle azioni di navigazione personalizzate.

Puoi anche collegare azioni di navigazione personalizzate a una radice del nodo di navigazione. Queste azioni vengono visualizzate in una barra degli strumenti secondaria sotto la barra degli strumenti principale.

Per aggiungere azioni di navigazione personalizzate alla tua app:

  1. Esegui l'override di due metodi nell'implementazione di MediaBrowserServiceCompat:

  2. Analizza i limiti delle azioni in fase di runtime:

    In onGetRoot, ottieni il numero massimo di azioni consentite per ogni MediaItem utilizzando la chiave BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT in rootHints Bundle. Un limite pari a 0 indica che la funzionalità non è supportata dal sistema.

  3. Crea l'elenco globale delle azioni di navigazione personalizzate. Per ogni azione, crea un oggetto Bundle con queste chiavi:

    • ID azione EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID
    • Etichetta azione EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL
    • URI dell'icona dell'azione EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI
  4. Aggiungi tutti gli oggetti Bundle di azione a un elenco.

  5. Aggiungi l'elenco globale al tuo BrowseRoot. In BrowseRoot extra Bundle, aggiungi l'elenco delle azioni come Parcelable ArrayList utilizzando la chiave BROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST.

  6. Aggiungi azioni agli oggetti MediaItem. Puoi aggiungere azioni a singoli oggetti MediaItem includendo l'elenco degli ID azione negli extra MediaDescriptionCompat utilizzando la chiave DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST. Questo elenco deve essere un sottoinsieme dell'elenco globale di azioni che hai definito in BrowseRoot.

  7. Gestisci le azioni e restituisci i progressi o i risultati:

Aggiornare lo stato dell'azione

Per eseguire l'override di questi metodi in MediaBrowserServiceCompat:

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

e

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

Limite azioni di analisi

Controlla il numero di azioni di navigazione personalizzate supportate:

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

Creare un'azione di navigazione personalizzata

Ogni azione deve essere inserita in un Bundle separato.

  • ID azione:

    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID,
                    "<ACTION_ID>")
    
  • Etichetta azione:

    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL,
                    "<ACTION_LABEL>")
    
  • URI dell'icona dell'azione:

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

Aggiungi azioni di navigazione personalizzate a Parcelable ArrayList

Aggiungi tutti gli oggetti Bundle dell'azione di navigazione personalizzata in un 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;
}

Aggiungere un elenco di azioni di navigazione personalizzate alla radice di navigazione

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

Aggiungere azioni a un elemento multimediale

Gli ID azioni di navigazione in un MediaItem devono essere un sottoinsieme dell'elenco globale di azioni di navigazione fornite su onGetRoot. Le azioni non presenti nell'elenco globale vengono ignorate.

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

Build onCustomAction result

Per creare il risultato:

  1. Analizza mediaId da 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. Per i risultati asincroni, stacca il risultato, result.detach.

  3. Crea il bundle dei risultati:

    1. Mostra un messaggio all'utente:

      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE,
                    mContext.getString(stringRes))
      
    2. Aggiorna l'elemento (utilizza per aggiornare le azioni in un elemento):

      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM, mediaId);
      
    3. Apri la visualizzazione di riproduzione:

      //Shows user the PBV without changing the playback state
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_SHOW_PLAYING_ITEM, null);
      
    4. Aggiorna il nodo di navigazione:

      //Change current browse node to mediaId
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE, mediaId);
      
  4. Controlla il risultato:

    • Errore: chiama result.sendError(resultBundle)
    • Aggiornamento sullo stato di avanzamento: chiamata result.sendProgressUpdate(resultBundle)
    • Fine:chiama result.sendResult(resultBundle)

Aggiornare lo stato dell'azione

Utilizzando il metodo result.sendProgressUpdate(resultBundle) con la chiave EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM, puoi aggiornare MediaItem in modo che rifletta il nuovo stato dell'azione. In questo modo puoi fornire feedback in tempo reale all'utente sui progressi e sul risultato della sua azione.

Azione di download di esempio

Questo esempio descrive come utilizzare questa funzionalità per implementare un'azione di download con tre stati:

  • Download è lo stato iniziale dell'azione. Quando l'utente seleziona questa azione, puoi scambiarla con Download e chiamare sendProgressUpdate per aggiornare l'interfaccia utente (UI).

  • Lo stato Download in corso indica che il download è in corso. Puoi utilizzare questo stato per mostrare all'utente una barra di avanzamento o un altro indicatore.

  • Lo stato Scaricato indica che il download è stato completato. Al termine del download, puoi scambiare Downloading con Downloaded e chiamare sendResult con la chiave EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM per indicare che l'elemento deve essere aggiornato. Inoltre, puoi utilizzare il tasto EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE per mostrare un messaggio di successo all'utente.

Questo approccio ti consente di fornire all'utente un feedback chiaro sul processo di download e sul suo stato attuale. Puoi aggiungere ulteriori dettagli con le icone per mostrare gli stati di download al 25%, 50% e 75%.

Azione preferita di esempio

Un altro esempio è un'azione preferita con due stati:

  • Preferiti viene visualizzato per gli elementi non presenti nell'elenco dei preferiti dell'utente. Quando l'utente seleziona questa azione, scambiala con Preferiti e chiama sendResult con la chiave EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM per aggiornare l'interfaccia utente.

  • Preferiti viene visualizzato per gli elementi nell'elenco dei preferiti dell'utente. Quando l'utente seleziona questa azione, scambiala con Preferiti e chiama sendResult con il tasto EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM per aggiornare la UI.

Questo approccio offre agli utenti un modo chiaro e coerente per gestire i loro elementi preferiti. Questi esempi mostrano la flessibilità delle azioni di navigazione personalizzate e come puoi utilizzarle per implementare una serie di funzionalità con feedback in tempo reale per un'esperienza utente migliorata nell'app Media dell'auto.

Puoi vedere un'implementazione di esempio completa di questa funzionalità nel progetto TestMediaApp.