Aggiungere video utilizzando la funzionalità Picture in picture (PIP)

A partire da Android 8.0 (livello API 26), Android consente l'avvio delle attività in modalità Picture in picture (PIP). PIP è un tipo speciale di modalità multi-finestra per lo più utilizzata per la riproduzione video. Consente all'utente di guardare un video in una piccola finestra fissata in un angolo dello schermo mentre navighi tra le app o sfogli contenuti su schermata principale.

PIP sfrutta le API multi-finestra rese disponibili in Android 7.0 per fornire finestra overlay video fissata. Per aggiungere PIP alla tua app, devi registrare il tuo attività che supportano PIP, passa alla modalità PIP in base alle tue esigenze e assicurati che gli elementi UI siano nascosti e che la riproduzione del video continui quando l'attività è in modalità PIP.

La finestra PIP viene visualizzata nel livello più alto dello schermo, in un angolo scelto dal all'interno del sistema.

La funzionalità PIP è supportata anche sui dispositivi con sistema operativo Android TV compatibili che eseguono Android 14 (livello API 34) o versioni successive. Sebbene esistano molte somiglianze, ci sono considerazioni aggiuntive sull'utilizzo PIP sulla TV.

In che modo gli utenti possono interagire con la finestra PIP

Gli utenti possono trascinare la finestra PIP in un'altra posizione. A partire da Android 12, gli utenti può anche:

  • Tocca una volta la finestra per visualizzare l'opzione di attivazione/disattivazione dello schermo intero, un pulsante di chiusura, un il pulsante Impostazioni e le azioni personalizzate fornite dalla tua app (ad esempio, Riproduci ).

  • Tocca due volte la finestra per passare dalla dimensione attuale a quella massima e viceversa o dimensioni minime in PIP, ad esempio toccando due volte una finestra ingrandita lo minimizza, ed è vero anche il contrario.

  • Conserva la finestra trascinandola verso il bordo sinistro o destro. Per rimuovere dall'archivio finestra, tocca la parte visibile della finestra nascosta o trascinala fuori.

  • Ridimensiona la finestra PIP usando le dita per eseguire lo zoom.

L'app controlla quando viene attivata la modalità PIP per l'attività corrente. Ecco alcuni esempi esempi:

  • Un'attività può attivare la modalità PIP quando l'utente tocca il pulsante Home o scorre fino a casa. In questo modo, Google Maps continua a mostrare le indicazioni stradali l'utente esegue un'altra attività contemporaneamente.

  • L'app può spostare un video in modalità PIP quando l'utente torna dalla pagina il video per sfogliare altri contenuti.

  • La tua app può attivare la modalità PIP per un video mentre un utente guarda la fine di un episodio di contenuti. Nella schermata principale vengono visualizzati annunci promozionali o di riepilogo informazioni sull'episodio successivo della serie.

  • La tua app può offrire agli utenti un modo per mettere in coda contenuti aggiuntivi guarda un video. La riproduzione del video continua in modalità PIP mentre la modalità mostra un'attività di selezione dei contenuti.

Dichiara il supporto dei PIP

Per impostazione predefinita, il sistema non supporta automaticamente PIP per le app. Se vuoi supportare PIP nella tua app, registrare la tua attività video nel file manifest Impostazione di android:supportsPictureInPicture su true. Inoltre, specifica che l'attività gestisce le modifiche alla configurazione del layout in modo che Riavvia quando vengono apportate modifiche al layout durante le transizioni in modalità PIP.

<activity android:name="VideoActivity"
    android:supportsPictureInPicture="true"
    android:configChanges=
        "screenSize|smallestScreenSize|screenLayout|orientation"
    ...

Passa alla modalità PIP della tua attività

A partire da Android 12, puoi passare alla modalità PIP della tua attività impostando il flag setAutoEnterEnabled a true. Con questa impostazione, un'attività passa automaticamente alla modalità PIP in base alle esigenze senza dover chiamare esplicitamente enterPictureInPictureMode() in onUserLeaveHint. E questo ha in aggiunta al vantaggio di offrire transizioni molto più fluide. Per i dettagli, consulta Rendi le transizioni alla modalità PIP in modo più fluido dalla navigazione tramite gesti.

Se scegli come target Android 11 o versioni precedenti, un'attività deve chiamare enterPictureInPictureMode() per passare alla modalità PIP. Ad esempio, il codice che segue sposta un'attività in Modalità PIP quando l'utente fa clic su un pulsante dedicato nell'interfaccia utente dell'app:

Kotlin

override fun onActionClicked(action: Action) {
    if (action.id.toInt() == R.id.lb_control_picture_in_picture) {
        activity?.enterPictureInPictureMode()
        return
    }
}

Java

@Override
public void onActionClicked(Action action) {
    if (action.getId() == R.id.lb_control_picture_in_picture) {
        getActivity().enterPictureInPictureMode();
        return;
    }
    ...
}

Potresti voler includere una logica che trasferisca un'attività in modalità PIP. di andare in background. Ad esempio, Google Maps passa alla modalità PIP se l'utente preme il pulsante Home o Recenti durante la navigazione nell'app. Puoi individua questo caso eseguendo l'override onUserLeaveHint():

Kotlin

override fun onUserLeaveHint() {
    if (iWantToBeInPipModeNow()) {
        enterPictureInPictureMode()
    }
}

Java

@Override
public void onUserLeaveHint () {
    if (iWantToBeInPipModeNow()) {
        enterPictureInPictureMode();
    }
}

Consigliato: offri agli utenti un'esperienza di transizione PIP migliorata

Android 12 ha aggiunto miglioramenti estetici significativi alle transizioni animate tra le finestre a schermo intero e PIP. Ti consigliamo vivamente di implementare modifiche applicabili; dopo averlo fatto, queste modifiche vengono scalate automaticamente schermi di grandi dimensioni, come pieghevoli e tablet, senza che sia necessario svolgere altro.

Se la tua app non include aggiornamenti applicabili, le transizioni PIP vengono comunque funzionale, ma le animazioni sono meno rifinite. Ad esempio, la transizione dalla modalità a schermo intero alla modalità PIP può far scomparire la finestra PIP prima che riappari quando la transizione è completata.

Queste modifiche includono quanto segue.

  • Rendi più fluide le transizioni alla modalità PIP dalla navigazione tramite gesti
  • Imposta un valore sourceRectHint corretto per entrare e uscire dalla modalità PIP
  • Disattivazione del ridimensionamento continuo per i contenuti non video

Fai riferimento al Esempio di Kotlin PictureInPicture come riferimento per offrire un'esperienza di transizione ottimale.

Rendi più fluide le transizioni alla modalità PIP dalla navigazione tramite gesti

A partire da Android 12, il flag setAutoEnterEnabled fornisce animazione più fluida per passare ai contenuti video in modalità PIP usando i gesti di navigazione, ad esempio per scorrere verso l'alto dalla modalità a schermo intero.

Completa i seguenti passaggi per apportare questa modifica e consulta questo esempio per una riferimento:

  1. Usa setAutoEnterEnabled per creare PictureInPictureParams.Builder:

    Kotlin

    setPictureInPictureParams(PictureInPictureParams.Builder()
        .setAspectRatio(aspectRatio)
        .setSourceRectHint(sourceRectHint)
        .setAutoEnterEnabled(true)
        .build())
    

    Java

    setPictureInPictureParams(new PictureInPictureParams.Builder()
        .setAspectRatio(aspectRatio)
        .setSourceRectHint(sourceRectHint)
        .setAutoEnterEnabled(true)
        .build());
    
  2. Chiama setPictureInPictureParams con gli aggiornamenti PictureInPictureParams in anticipo. L'app non attende Callback onUserLeaveHint (come avrebbe fatto in Android 11).

    Ad esempio, potresti voler chiamare setPictureInPictureParams prima riproduzione e successivamente, se le proporzioni vengono modificate.

  3. Chiama setAutoEnterEnabled(false), ma solo quando è necessario. Ad esempio: probabilmente non vorrai inserire PIP se la riproduzione corrente è in pausa stato.

Imposta un valore sourceRectHint corretto per entrare e uscire dalla modalità PIP

A partire dall'introduzione di PIP in Android 8.0, setSourceRectHint indicato l'area dell'attività visibile dopo la transizione Picture in picture: ad esempio, i limiti della visualizzazione di un video in un video player.

Con Android 12, il sistema utilizza sourceRectHint per implementare un'implementazione sia all'entrata che all'uscita dalla modalità PIP.

Per impostare correttamente sourceRectHint per entrare e uscire dalla modalità PIP:

  1. Costruire PictureInPictureParams utilizzando i limiti corretti come sourceRectHint. Ti consigliamo anche di allegare listener delle modifiche del layout del video player:

    Kotlin

    val mOnLayoutChangeListener =
    OnLayoutChangeListener { v: View?, oldLeft: Int,
            oldTop: Int, oldRight: Int, oldBottom: Int, newLeft: Int, newTop:
            Int, newRight: Int, newBottom: Int ->
        val sourceRectHint = Rect()
        mYourVideoView.getGlobalVisibleRect(sourceRectHint)
        val builder = PictureInPictureParams.Builder()
            .setSourceRectHint(sourceRectHint)
        setPictureInPictureParams(builder.build())
    }
    
    mYourVideoView.addOnLayoutChangeListener(mOnLayoutChangeListener)
    

    Java

    private final View.OnLayoutChangeListener mOnLayoutChangeListener =
            (v, oldLeft, oldTop, oldRight, oldBottom, newLeft, newTop, newRight,
            newBottom) -> {
        final Rect sourceRectHint = new Rect();
        mYourVideoView.getGlobalVisibleRect(sourceRectHint);
        final PictureInPictureParams.Builder builder =
            new PictureInPictureParams.Builder()
                .setSourceRectHint(sourceRectHint);
        setPictureInPictureParams(builder.build());
    };
    
    mYourVideoView.addOnLayoutChangeListener(mOnLayoutChangeListener);
    
  2. Se necessario, aggiorna sourceRectHint prima che il sistema avvii la transizione di uscita. Quando il sistema sta per uscire dalla modalità PIP, l'attività la gerarchia di visualizzazione è stabilita in base alla sua configurazione di destinazione (ad esempio, schermo intero). L'app può collegare un listener delle modifiche del layout alla vista principale o vista target (come la visualizzazione del video player) per rilevare l'evento e aggiorna sourceRectHint prima dell'inizio dell'animazione.

    Kotlin

    // Listener is called immediately after the user exits PiP but before animating.
    playerView.addOnLayoutChangeListener { _, left, top, right, bottom,
                        oldLeft, oldTop, oldRight, oldBottom ->
        if (left != oldLeft
            || right != oldRight
            || top != oldTop
            || bottom != oldBottom) {
            // The playerView's bounds changed, update the source hint rect to
            // reflect its new bounds.
            val sourceRectHint = Rect()
            playerView.getGlobalVisibleRect(sourceRectHint)
            setPictureInPictureParams(
                PictureInPictureParams.Builder()
                    .setSourceRectHint(sourceRectHint)
                    .build()
            )
        }
    }
    
    

    Java

    // Listener is called right after the user exits PiP but before
    // animating.
    playerView.addOnLayoutChangeListener((v, left, top, right, bottom,
                        oldLeft, oldTop, oldRight, oldBottom) -> {
        if (left != oldLeft
            || right != oldRight
            || top != oldTop
            || bottom != oldBottom) {
            // The playerView's bounds changed, update the source hint rect to
            // reflect its new bounds.
            final Rect sourceRectHint = new Rect();
            playerView.getGlobalVisibleRect(sourceRectHint);
            setPictureInPictureParams(
                new PictureInPictureParams.Builder()
                    .setSourceRectHint(sourceRectHint)
                    .build());
        }
    });
    
    

Disattiva il ridimensionamento continuo per i contenuti non video

Android 12 aggiunge il flag setSeamlessResizeEnabled, che offre un'animazione con dissolvenza incrociata più fluida quando si ridimensionano contenuti non video in PIP finestra. In precedenza, il ridimensionamento di contenuti non video in una finestra PIP poteva creare artefatti visivi sgradevoli.

Per disattivare il ridimensionamento continuo per i contenuti non video:

Kotlin

setPictureInPictureParams(PictureInPictureParams.Builder()
    .setSeamlessResizeEnabled(false)
    .build())

Java

setPictureInPictureParams(new PictureInPictureParams.Builder()
    .setSeamlessResizeEnabled(false)
    .build());

Gestire l'UI durante la modalità PIP

Quando l'attività entra o esce dalla modalità PIP, il sistema chiama Activity.onPictureInPictureModeChanged() oppure Fragment.onPictureInPictureModeChanged().

Devi eseguire l'override di questi callback per riorganizzare gli elementi dell'interfaccia utente dell'attività. Conserva ricorda che in modalità PIP la tua attività viene visualizzata in una piccola finestra. Gli utenti non possono interagire con gli elementi UI dell'app in modalità PIP e con i dettagli elementi UI di piccole dimensioni potrebbero essere difficili da vedere. Le attività di riproduzione di video con con un'interfaccia utente minima offre la migliore esperienza utente.

Se la tua app deve fornire azioni personalizzate per PIP, consulta Aggiungere controlli in questa pagina. Rimuovi gli altri elementi UI prima di l'attività entra in modalità PIP e le ripristina quando viene visualizzata la modalità a schermo intero di nuovo:

Kotlin

override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean,
                                           newConfig: Configuration) {
    if (isInPictureInPictureMode) {
        // Hide the full-screen UI (controls, etc.) while in PiP mode.
    } else {
        // Restore the full-screen UI.
    }
}

Java

@Override
public void onPictureInPictureModeChanged (boolean isInPictureInPictureMode, Configuration newConfig) {
    if (isInPictureInPictureMode) {
        // Hide the full-screen UI (controls, etc.) while in PiP mode.
    } else {
        // Restore the full-screen UI.
        ...
    }
}

Aggiungi controlli

La finestra PIP può visualizzare i controlli quando l'utente apre il menu della finestra (tramite toccando la finestra su un dispositivo mobile o selezionando il menu dalla TV telecomando.)

Se un'app include contenuti multimediali attivi sessione, quindi riproduci i controlli pausa, avanti e indietro.

Puoi anche specificare esplicitamente azioni personalizzate creando PictureInPictureParams con PictureInPictureParams.Builder.setActions() prima di entrare in modalità PIP e passa i parametri quando entri in modalità PIP enterPictureInPictureMode(android.app.PictureInPictureParams) o setPictureInPictureParams(android.app.PictureInPictureParams). Fai attenzione. Se provi ad aggiungere più di getMaxNumPictureInPictureActions(), verrà visualizzato solo il numero massimo.

La riproduzione del video continua in modalità PIP

Quando le tue attività passano a PIP, il sistema la mette nella posizione in pausa e chiama lo stato dell'attività onPause(). Video la riproduzione non deve essere messa in pausa, ma continua la riproduzione se l'attività viene messo in pausa durante la transizione alla modalità PIP.

In Android 7.0 e versioni successive, devi mettere in pausa e riprendere la riproduzione video quando sistema chiama la tua attività onStop() e onStart(). In questo modo, puoi evitare di dover controllare se la tua app è in modalità PIP in onPause() continuare esplicitamente la riproduzione.

Se non hai impostato il flag setAutoEnterEnabled su true e devi metti in pausa la riproduzione nell'implementazione onPause(), verifica la modalità PIP chiamando isInPictureInPictureMode() e gestire la riproduzione in modo appropriato. Ad esempio:

Kotlin

override fun onPause() {
    super.onPause()
    // If called while in PiP mode, do not pause playback
    if (isInPictureInPictureMode) {
        // Continue playback
    } else {
        // Use existing playback logic for paused Activity behavior.
    }
}

Java

@Override
public void onPause() {
    // If called while in PiP mode, do not pause playback
    if (isInPictureInPictureMode()) {
        // Continue playback
        ...
    } else {
        // Use existing playback logic for paused Activity behavior.
        ...
    }
}

Quando l'attività passa dalla modalità PIP alla modalità a schermo intero, il sistema riprende la tua attività e chiama i tuoi onResume().

Usare una singola attività di riproduzione per PIP

Nella tua app, un utente potrebbe selezionare un nuovo video durante la ricerca di contenuti nella schermata principale, mentre un'attività di riproduzione video è in modalità PIP. Riproduci il nuovo video nell'attività di riproduzione esistente in modalità a schermo intero, invece di avviare un nuove attività che potrebbero confondere l'utente.

Per garantire che una singola attività venga utilizzata per le richieste di riproduzione video e cambiato attivare o disattivare la modalità PIP in base alle tue esigenze, imposta android:launchMode dell'attività su singleTask nel file manifest:

<activity android:name="VideoActivity"
    ...
    android:supportsPictureInPicture="true"
    android:launchMode="singleTask"
    ...

Nella tua attività, sostituisci onNewIntent() e gestire il nuovo video, interrompendo qualsiasi riproduzione video esistente se necessario.

Best practice

PIP potrebbe essere disattivato sui dispositivi con poca RAM. Prima che l'app utilizzi PIP, verifica che sia disponibile chiamando hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE).

PIP è destinato ad attività che riproducono video a schermo intero. Quando cambi la modalità attività in modalità PIP, evita di mostrare nulla ad eccezione dei contenuti video. Registra quando l'attività entra in modalità PIP e nasconde gli elementi UI, come descritto in Gestione dell'interfaccia utente durante la modalità PIP.

Quando un'attività è in modalità PIP, per impostazione predefinita non viene attivato l'input. A ricevi eventi di input in modalità PIP, utilizza MediaSession.setCallback(). Per ulteriori informazioni sull'utilizzo di setCallback(), consulta la sezione Visualizzazione di un evento Now Playing dell'utente.

Quando l'app è in modalità PIP, la riproduzione di video nella finestra PIP può causare interferenze con un'altra app, ad esempio un'app di lettore musicale o un'app di ricerca vocale. Per evitare che questo accada, richiedi lo stato attivo dell'audio quando avvii la riproduzione del video e gestisci notifiche di modifica del focus audio, come descritto in Gestione dell'audio Obiettivo. Se ricevi una notifica di perdita della messa a fuoco audio in modalità PIP, mette in pausa o interrompi la riproduzione del video.

Quando l'app sta per attivare PIP, tieni presente che solo l'attività principale entra la funzione Picture in picture. In alcune situazioni, ad esempio sui dispositivi multi-finestra, è possibile che l'attività riportata di seguito verrà ora visualizzata e sarà di nuovo visibile insieme l'attività PIP. Dovresti gestire la richiesta di conseguenza, incluse le attività di seguito relativa a come ricevere una chiamata onResume() o onPause(). È inoltre possibile è possibile che l'utente possa interagire con l'attività. Ad esempio, se disponi un'attività elenco video visualizzata e l'attività video in riproduzione in modalità PIP, l'utente può selezionare un nuovo video dall'elenco e l'attività PIP dovrebbe aggiornarsi di conseguenza.

Codice campione aggiuntivo

Per scaricare un'app di esempio scritta in Kotlin, vedi Esempio di PictureInPicture per Android (Kotlin).