Utilizzare una sessione multimediale

Le sessioni multimediali offrono un modo universale di interagire con un lettore audio o video. Se comunichi ad Android che i contenuti multimediali sono in riproduzione in un'app, è possibile delegare all'app i controlli di riproduzione. L'integrazione con la sessione multimediale consente a un'app di pubblicizzare la riproduzione di contenuti multimediali esternamente e di ricevere comandi di riproduzione da fonti esterne. Queste fonti possono essere pulsanti fisici (come il pulsante di riproduzione sulle cuffie o il telecomando della TV) o comandi indiretti (come l'istruzione di "mettere in pausa" all'Assistente Google). La sessione multimediale delega quindi questi comandi all'app che li applica al media player per il quale è chiaro dove hanno avuto origine i comandi.

Una sessione multimediale è affiancata al player che gestisce. Devi creare e inizializzare una sessione multimediale nel metodo onCreate() dell'attività o del servizio proprietario della sessione multimediale e del player associato.

Inizializzare la sessione multimediale

Una sessione multimediale appena creata non ha funzionalità. È necessario inizializzare la sessione svolgendo i seguenti passaggi:

  • Imposta i flag in modo che la sessione multimediale possa ricevere callback dai controller multimediali e dai pulsanti multimediali.
  • Crea e inizializza un'istanza di PlaybackStateCompat e assegnala alla sessione. Lo stato di riproduzione cambia nel corso della sessione, quindi consigliamo di memorizzare PlaybackStateCompat.Builder nella cache per poterlo riutilizzare.
  • Crea un'istanza di MediaSessionCompat.Callback e assegnala alla sessione (ulteriori informazioni sui callback di seguito).

Devi creare e inizializzare una sessione multimediale nel metodo onCreate() dell'attività o del servizio proprietario della sessione.

Affinché i pulsanti multimediali funzionino quando l'app viene appena inizializzata (o arrestata), il relativo PlaybackState deve contenere un'azione di riproduzione corrispondente all'intent inviato dal pulsante multimediale. Questo è il motivo per cui ACTION_PLAY viene assegnato allo stato della sessione durante l'inizializzazione. Per ulteriori informazioni, consulta la sezione Risposta ai pulsanti multimediali.

Mantieni lo stato di riproduzione e i metadati

Esistono due classi che rappresentano lo stato di una sessione multimediale.

La classe PlaybackStateCompat descrive l'attuale stato operativo del player. Alcuni esempi sono:

  • Lo stato di trasporto (se il player è in riproduzione/in pausa/nel buffer e così via. Vedi getState())
  • Un codice e un messaggio di errore facoltativo, se applicabile. (vedi getErrorCode() e leggi Stati ed errori di seguito).
  • La posizione del player
  • Le azioni valide del controller che possono essere gestite nello stato attuale

La classe MediaMetadataCompat descrive il materiale in riproduzione:

  • Il nome dell'artista, dell'album e della traccia
  • La durata della traccia
  • Copertina dell'album da visualizzare sulla schermata di blocco. L'immagine è una bitmap con una dimensione massima di 320 x 320 dp (se più grande, viene ridotta).
  • Un'istanza di ContentUris che rimanda a una versione più grande dell'artwork

Lo stato del player e i metadati possono cambiare nel corso della durata di una sessione multimediale. Ogni volta che lo stato o i metadati cambiano, devi utilizzare il builder corrispondente per ogni classe, PlaybackStateCompat.Builder() o MediaMetadataCompat.Builder(), e poi passare la nuova istanza alla sessione multimediale chiamando setPlaybackState() o setMetaData(). Per ridurre il consumo complessivo di memoria da queste operazioni frequenti, è consigliabile creare i builder una volta e riutilizzarli per tutta la durata della sessione.

Stati ed errori

Tieni presente che PlaybackState è un oggetto che contiene valori separati per lo stato di riproduzione della sessione (getState()) e, se necessario, un codice di errore (getErrorCode()) associato. Gli errori possono essere irreversibili o non irreversibili:

Ogni volta che la riproduzione viene interrotta, devi generare un errore irreversibile. Imposta lo stato di trasporto su STATE_ERROR e specifica un errore associato con setErrorMessage(int, CharSequence). Se la riproduzione è bloccata dall'errore, l'PlaybackState dovrebbe continuare a segnalare STATE_ERROR e l'errore.

Si verifica un errore non irreversibile quando la tua app non può gestire una richiesta, ma può continuare a essere riprodotta: Il trasporto rimane in uno stato "normale" (ad esempio STATE_PLAYING), ma PlaybackState contiene un codice di errore. Ad esempio, se è in riproduzione l'ultimo brano e l'utente richiede di passare al brano successivo, la riproduzione può continuare, ma devi creare un nuovo PlaybackState con il codice di errore ERROR_CODE_END_OF_QUEUE e chiamare setPlaybackState(). I controller multimediali collegati alla sessione riceveranno il callback onPlaybackStateChanged() e spiegheranno all'utente cosa è successo. Un errore non irreversibile deve essere segnalato una sola volta, nel momento in cui si verifica. Al successivo aggiornamento della sessione, PlaybackState non imposta di nuovo lo stesso errore non irreversibile (a meno che l'errore non si sia verificato in risposta a una nuova richiesta).

Schermate di blocco delle sessioni multimediali

A partire da Android 4.0 (livello API 14) il sistema può accedere allo stato di riproduzione e ai metadati di una sessione multimediale. In questo modo la schermata di blocco può mostrare i controlli multimediali e l'artwork. Il comportamento varia in base alla versione di Android.

Copertina dell'album

Da Android 4.0 (livello API 14) ad Android 10 (livello API 29), lo sfondo della schermata di blocco visualizza la copertina dell'album, ma solo se i metadati della sessione multimediale includono una bitmap di sfondo.

Controlli del trasporto

In Android 4.0 (livello API 14) e Android 4.4 (livello API 19), quando una sessione multimediale è attiva e i metadati della sessione multimediale includono una bitmap di sfondo, la schermata di blocco visualizza automaticamente i controlli di trasporto.

In Android 5.0 (livello API 21) o versioni successive, il sistema non fornisce controlli di trasporto nella schermata di blocco. Utilizza invece una notifica MediaStyle per visualizzare i controlli di trasporto.

Aggiungi azioni personalizzate

Le applicazioni multimediali possono definire azioni personalizzate, ad esempio Mi piace, Mi piace o Indietro di 30 secondi. Un'azione personalizzata dovrebbe implementare un comportamento completamente nuovo. Non utilizzare un'azione personalizzata per sostituire una delle azioni standard di controllo del trasporto definite in PlaybackStateCompat.

Aggiungi azioni personalizzate con addCustomAction(). L'esempio seguente mostra come aggiungere un controllo per un'azione Mi piace:

Kotlin

stateBuilder.addCustomAction(
        PlaybackStateCompat.CustomAction.Builder(
                CUSTOM_ACTION_THUMBS_UP,
                resources.getString(R.string.thumbs_up),
                thumbsUpIcon
        ).run {
            setExtras(customActionExtras)
            build()
        }
)

Java

stateBuilder.addCustomAction(new PlaybackStateCompat.CustomAction.Builder(
    CUSTOM_ACTION_THUMBS_UP, resources.getString(R.string.thumbs_up), thumbsUpIcon)
    .setExtras(customActionExtras)
    .build());

Per un esempio completo, vedi Universal Music Player.

Rispondi all'azione con onCustomAction().

Kotlin

override fun onCustomAction(action: String, extras: Bundle?) {
    when(action) {
        CUSTOM_ACTION_THUMBS_UP -> {
            ...
        }
    }
}

Java

@Override
public void onCustomAction(@NonNull String action, Bundle extras) {
    if (CUSTOM_ACTION_THUMBS_UP.equals(action)) {
        ...
    }
}

Vedi anche Universal Music Player.

Callback delle sessioni multimediali

I principali metodi di callback delle sessioni multimediali sono onPlay(), onPause() e onStop(). Qui puoi aggiungere il codice che controlla il player.

Poiché crei un'istanza e imposti il callback della sessione in fase di runtime (in onCreate()), la tua app può definire callback alternativi che utilizzano player diversi e scegliere la combinazione di callback/player appropriata in base al livello di dispositivo e/o di sistema. Puoi cambiare il player senza modificare il resto dell'app. Ad esempio, puoi utilizzare ExoPlayer su Android 4.1 (livello API 16) o versioni successive e utilizzare MediaPlayer su sistemi precedenti.

Oltre a controllare il player e gestire le transizioni dello stato della sessione multimediale, i callback consentono anche di attivare e disattivare funzionalità della tua app e di stabilire il modo in cui interagisce con altre app e con l'hardware del dispositivo. (vedi Controllo dell'uscita audio).

L'implementazione dei metodi di callback delle sessioni multimediali dipende dalla struttura dell'app. Consulta le pagine separate che descrivono come utilizzare i callback nelle app audio e nelle app video, descrivi come devono essere implementati i callback per ogni tipo di app.