A partire da Android 8.0 (livello API 26), Android consente di avviare le attività in modalità Picture in picture (PIP). La modalità PiP è un tipo speciale di modalità multi-finestra utilizzata per la riproduzione di video, le videochiamate e la navigazione. Consente all'utente di bloccare la finestra dell'attività esistente in un angolo dello schermo mentre naviga tra le app o sfoglia i contenuti nella schermata principale.
PIP sfrutta le API multi-finestra rese disponibili in Android 7.0 per fornire la finestra di overlay video bloccata. Per aggiungere la modalità PIP alla tua app, devi registrare le attività che la supportano, passare alla modalità PIP quando necessario e assicurarti che gli elementi dell'interfaccia utente 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 sistema.
La modalità PIP è supportata anche sui dispositivi Android TV OS compatibili con Android 14 (livello API 34) o versioni successive. Sebbene ci siano molte somiglianze, ci sono ulteriori considerazioni da fare quando si utilizza la funzionalità 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 possono anche:
Tocca una volta la finestra per visualizzare un pulsante di attivazione/disattivazione a schermo intero, un pulsante di chiusura, un pulsante delle impostazioni e le azioni personalizzate fornite dalla tua app (ad esempio i controlli del player).
Tocca due volte la finestra per passare dalle dimensioni attuali di PiP a quelle massime o minime. Ad esempio, se tocchi due volte una finestra ingrandita, questa viene ridotta a icona e viceversa.
Nascondi la finestra trascinandola verso il bordo sinistro o destro. Per ripristinare la finestra, tocca la parte visibile della finestra nascosta o trascinala verso l'esterno.
Ridimensiona la finestra PIP utilizzando la funzionalità di pizzicamento per lo zoom.
La tua app controlla quando l'attività corrente entra in modalità PIP. Ecco alcuni esempi:
Un'attività può attivare la modalità PIP quando l'utente tocca il pulsante Home o scorre verso l'alto per tornare alla schermata Home. In questo modo, Google Maps continua a mostrare le indicazioni stradali mentre l'utente esegue un'altra attività contemporaneamente.
La tua app può spostare un video in modalità PIP quando l'utente torna indietro dal video per sfogliare altri contenuti.
La tua app può passare un video alla modalità PIP mentre un utente guarda la fine di un episodio di contenuti. La schermata principale mostra informazioni promozionali o di riepilogo sulla puntata successiva della serie.
La tua app può fornire agli utenti un modo per mettere in coda contenuti aggiuntivi mentre guardano un video. La riproduzione del video continua in modalità PiP, mentre lo schermo principale mostra un'attività di selezione dei contenuti.
Dichiara il supporto di PIP
Per impostazione predefinita, il sistema non supporta automaticamente la modalità PIP per le app. Se vuoi supportare la modalità PiP nella tua app, registra l'attività video nel manifest impostando android:supportsPictureInPicture su true. Inoltre, specifica che la tua attività gestisce le modifiche alla configurazione del layout in modo che non venga riavviata quando si verificano modifiche al layout durante le transizioni della modalità PiP.
<activity android:name="VideoActivity"
android:supportsPictureInPicture="true"
android:configChanges=
"screenSize|smallestScreenSize|screenLayout|orientation"
...
Implementare il PIP con Jetpack
Utilizza la libreria Jetpack Picture in picture per implementare l'esperienza Picture in picture, in quanto semplifica l'integrazione e riduce i problemi comuni all'interno dell'app. Consulta la nostra app di esempio della piattaforma per vedere un esempio del suo utilizzo. Tuttavia, se preferisci implementare la funzionalità PIP utilizzando le API della piattaforma, consulta la documentazione seguente.
Passa l'attività a PiP
A partire da Android 12, puoi passare alla modalità PIP impostando il flag setAutoEnterEnabled su true. Con questa impostazione, un'attività passa automaticamente alla modalità PIP in base alle necessità, senza dover chiamare esplicitamente enterPictureInPictureMode() in onUserLeaveHint. Inoltre, questo approccio offre il vantaggio aggiuntivo di fornire transizioni molto più fluide. Per maggiori dettagli, consulta Rendi più fluide le transizioni alla modalità PIP 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 seguente codice passa un'attività alla modalità PiP quando l'utente fa clic su un pulsante dedicato nell'interfaccia utente dell'app:
override fun onActionClicked(action: Action) {
if (action.id.toInt() == R.id.lb_control_picture_in_picture) {
activity?.enterPictureInPictureMode()
return
}
}
Potresti voler includere una logica che passa un'attività alla modalità PiP anziché
passare in background. Ad esempio, Google Maps passa alla modalità PiP se l'utente preme il pulsante Home o Recenti mentre l'app è in modalità di navigazione. Puoi
gestire questo caso eseguendo l'override di onUserLeaveHint():
override fun onUserLeaveHint() {
if (iWantToBeInPipModeNow()) {
enterPictureInPictureMode()
}
}
Consigliato: offri agli utenti un'esperienza di transizione PiP ottimizzata
Android 12 ha aggiunto significativi miglioramenti estetici alle transizioni animate tra le finestre a schermo intero e PiP. Ti consigliamo vivamente di implementare tutte le modifiche applicabili. Una volta fatto, queste modifiche si adattano automaticamente agli schermi di grandi dimensioni, come quelli di pieghevoli e tablet, senza ulteriori interventi.
Se la tua app non include gli aggiornamenti applicabili, le transizioni PiP sono comunque funzionali, ma le animazioni sono meno rifinite. Ad esempio, il passaggio dalla modalità a schermo intero alla modalità PIP può causare la scomparsa della finestra PIP durante la transizione prima che riappaia al termine della transizione.
Queste modifiche includono quanto segue.
- Transizioni più fluide alla modalità PIP dalla navigazione tramite gesti
- Impostazione di un
sourceRectHintappropriato per l'attivazione e la disattivazione della modalità PIP - Disattivazione del ridimensionamento continuo per i contenuti non video
Consulta l'esempio PictureInPicture di Android Kotlin come riferimento per attivare un'esperienza di transizione ottimizzata.
Rendere più fluide le transizioni alla modalità PIP dalla navigazione tramite gesti
A partire da Android 12, il flag setAutoEnterEnabled fornisce un'animazione molto più fluida per la transizione ai contenuti video in modalità PiP utilizzando la navigazione tramite gesti, ad esempio quando scorri verso l'alto per tornare alla schermata Home dalla modalità a schermo intero.
Per apportare questa modifica, completa i seguenti passaggi:
- Utilizza
setAutoEnterEnabledper crearePictureInPictureParams.Builder:
setPictureInPictureParams(PictureInPictureParams.Builder()
.setAspectRatio(aspectRatio)
.setSourceRectHint(sourceRectHint)
.setAutoEnterEnabled(true)
.build())
Note: When `setAutoEnterEnabled` is enabled, you don't need to explicitly
call [`enterPictureInPictureMode`][5] in [`onUserLeaveHint`][6].
Chiama
setPictureInPictureParamsconPictureInPictureParamsaggiornato in anticipo. L'app non attende il callbackonUserLeaveHint(come avrebbe fatto in Android 11).Ad esempio, potresti voler chiamare
setPictureInPictureParamsalla prima riproduzione e a qualsiasi riproduzione successiva se le proporzioni vengono modificate.Chiama
setAutoEnterEnabled(false), ma solo se necessario. Ad esempio, probabilmente non vuoi attivare la modalità PIP se la riproduzione corrente è in pausa.
Imposta un sourceRectHint appropriato per l'attivazione e la disattivazione della modalità PIP
A partire dall'introduzione di PiP in Android 8.0, setSourceRectHint
indicava l'area dell'attività visibile dopo la transizione alla modalità
picture-in-picture, ad esempio i limiti di visualizzazione del video in un video player.
Con Android 12, il sistema utilizza sourceRectHint per implementare un'animazione molto più fluida sia quando si entra sia quando si esce dalla modalità PIP.
Per impostare correttamente sourceRectHint per l'attivazione e la disattivazione della modalità PIP:
- Costruisci
PictureInPictureParamsutilizzando i limiti appropriati comesourceRectHint. Ti consigliamo inoltre di collegare un listener di modifica del layout al video player:
val mOnLayoutChangeListener =
OnLayoutChangeListener { v: View?, left: Int,
top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop:
Int, oldRight: Int, oldBottom: Int ->
val sourceRectHint = Rect()
mYourVideoView.getGlobalVisibleRect(sourceRectHint)
val builder = PictureInPictureParams.Builder()
.setSourceRectHint(sourceRectHint)
setPictureInPictureParams(builder.build())
}
mYourVideoView.addOnLayoutChangeListener(mOnLayoutChangeListener)
- Se necessario, aggiorna
sourceRectHintprima che il sistema avvii la transizione di uscita. Quando il sistema sta per uscire dalla modalità PiP, la gerarchia di oggetti View dell'attività viene disposta in base alla configurazione di destinazione (ad esempio, schermo intero). L'app può collegare un listener di modifica del layout alla visualizzazione principale o alla visualizzazione di destinazione (ad esempio la visualizzazione del video player) per rilevare l'evento e aggiornaresourceRectHintprima dell'inizio dell'animazione.
// 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()
)
}
}
Disattiva il ridimensionamento continuo per i contenuti non video
Android 12 aggiunge il flag setSeamlessResizeEnabled, che fornisce un'animazione di dissolvenza incrociata molto più fluida durante il ridimensionamento dei contenuti non video nella finestra PiP. In precedenza, il ridimensionamento di contenuti non video in una finestra PIP poteva creare artefatti visivi fastidiosi.
Per attivare il ridimensionamento continuo per i contenuti video:
setPictureInPictureParams(PictureInPictureParams.Builder()
.setSeamlessResizeEnabled(true)
.build())
Gestisci la UI durante il PiP
Quando l'attività entra o esce dalla modalità Picture in picture (PIP), il sistema chiama Activity.onPictureInPictureModeChanged() o Fragment.onPictureInPictureModeChanged().
Android 15 introduce modifiche che garantiscono una transizione ancora più fluida quando si entra in modalità PiP. Questo è utile per le app che hanno elementi UI sovrapposti alla UI principale, che entra in PiP.
Gli sviluppatori utilizzano il callback onPictureInPictureModeChanged() per definire la logica che attiva/disattiva la visibilità degli elementi UI in overlay. Questo callback viene attivato al termine dell'animazione di entrata o uscita dalla modalità PIP. A partire da Android 15, la classe PictureInPictureUiState include un nuovo stato.
Con questo nuovo stato della UI, le app che hanno come target Android 15 osservano il callback Activity#onPictureInPictureUiStateChanged() richiamato con isTransitioningToPip() non appena inizia l'animazione PiP. Esistono molti elementi UI che non sono pertinenti per l'app quando è in modalità PiP, ad esempio visualizzazioni o layout che includono informazioni come suggerimenti, video imminenti, valutazioni e titoli. Quando l'app entra in modalità PIP, utilizza il callback onPictureInPictureUiStateChanged() per nascondere questi elementi UI. Quando l'app passa alla modalità a schermo intero dalla finestra PiP, utilizza il callback onPictureInPictureModeChanged() per mostrare questi elementi, come mostrato negli esempi seguenti:
override fun onPictureInPictureUiStateChanged(pipState: PictureInPictureUiState) {
if (pipState.isTransitioningToPip()) {
// Hide UI elements.
}
}
override fun onPictureInPictureModeChanged(
isInPictureInPictureMode: Boolean,
newConfig: Configuration
) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
if (!isInPictureInPictureMode) {
// Unhide UI elements.
}
}
Questa rapida attivazione/disattivazione della visibilità degli elementi UI non pertinenti (per una finestra PiP) contribuisce a garantire un'animazione di attivazione della modalità PiP più fluida e senza sfarfallio.
Esegui l'override di questi callback per ridisegnare gli elementi UI dell'attività. Tieni presente che, in modalità PiP, la tua attività viene mostrata in una piccola finestra. Gli utenti non possono interagire con gli elementi UI dell'app quando questa è in modalità PIP e i dettagli degli elementi UI di piccole dimensioni potrebbero essere difficili da vedere. Le attività di riproduzione video con un'interfaccia utente minima offrono la migliore esperienza utente.
Se la tua app deve fornire azioni personalizzate per la modalità PIP, consulta Aggiungi controlli in questa pagina. Rimuovi altri elementi UI prima che l'attività entri in PIP e ripristinali quando l'attività torna a schermo intero.
Aggiungi controlli
La finestra PiP può mostrare i controlli quando l'utente apre il menu della finestra (toccando la finestra su un dispositivo mobile o selezionando il menu dal telecomando TV).
Se un'app ha una sessione multimediale attiva, verranno visualizzati i controlli di riproduzione, pausa, successivo e precedente.
Puoi anche specificare azioni personalizzate in modo esplicito creando
PictureInPictureParams con
PictureInPictureParams.Builder.setActions() prima di attivare la modalità PiP,
e passare i parametri quando attivi la modalità PiP utilizzando
enterPictureInPictureMode(android.app.PictureInPictureParams) o
setPictureInPictureParams(android.app.PictureInPictureParams). Fai attenzione. Se provi ad aggiungere più di getMaxNumPictureInPictureActions(),
verrà visualizzato solo il numero massimo.
Riproduzione video continua in modalità PIP
Quando l'attività passa alla modalità PIP, il sistema la mette in pausa e chiama il metodo onPause() dell'attività. La riproduzione del video non deve essere messa in pausa, ma deve continuare se l'attività viene messa in pausa durante la transizione alla modalità PIP.
In Android 7.0 (livello API 24) e versioni successive, devi mettere in pausa e riprendere la riproduzione dei video quando il sistema chiama onStop() e onStart() della tua attività. In questo modo, puoi evitare di dover controllare se la tua app è in modalità PIP in onPause() e continuare esplicitamente la riproduzione.
Se non hai impostato il flag setAutoEnterEnabled su true e devi mettere in pausa la riproduzione nella tua implementazione di onPause(), verifica la modalità PiP chiamando isInPictureInPictureMode() e gestisci la riproduzione in modo appropriato. Ad esempio:
override fun onPause() {
super.onPause()
// If called while in PiP mode, don't 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 l'attività e chiama il metodo onResume().
Utilizza un'unica attività di riproduzione per PiP
Nella tua app, un utente potrebbe selezionare un nuovo video durante la navigazione dei 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, anziché avviare una nuova attività che potrebbe confondere l'utente.
Per assicurarti che venga utilizzata una singola attività per le richieste di riproduzione video e che venga attivata o disattivata la modalità PIP in base alle esigenze, imposta android:launchMode dell'attività su singleTask nel manifest:
<activity android:name="VideoActivity"
...
android:supportsPictureInPicture="true"
android:launchMode="singleTask"
...
Nella tua attività, esegui l'override di onNewIntent() e gestisci il nuovo video, interrompendo la riproduzione di eventuali video esistenti, se necessario.
Supporto della modalità PIP per le app della fotocamera
Per attivare la modalità PiP per le app della fotocamera, devi assicurarti che la fotocamera rimanga attiva in modalità PiP non chiudendola quando viene chiamato onPause():
override fun onPause() {
super.onPause()
// Don't close the camera if the app is entering PiP mode
if (!isInPictureInPictureMode) {
closeCamera()
}
}
Come per altri casi d'uso, nascondi gli elementi UI non essenziali (come controlli e overlay) e aggiungi azioni personalizzate per controllare la fotocamera (ad esempio, interrompi la registrazione o capovolgi la fotocamera).
Calcola sourceRectHint per transizioni fluide
Fornire un sourceRectHint accurato con le coordinate esatte dello schermo del mirino della fotocamera è essenziale per un'animazione di ingresso fluida. Puoi ottenere i
limiti dalla visualizzazione di anteprima utilizzando getGlobalVisibleRect() come segue:
val previewView = findViewById<View>(R.id.preview_view)
val globalRect = Rect()
// Ensure the view is laid out before calling getGlobalVisibleRect() to get valid screen coordinates.
previewView.getGlobalVisibleRect(globalRect)
val params = PictureInPictureParams.Builder()
.setSourceRectHint(globalRect)
.build()
setPictureInPictureParams(params)
Considerazioni aggiuntive
La modalità PIP potrebbe essere disattivata sui dispositivi con RAM ridotta. Prima che l'app utilizzi PiP,
verifica che sia disponibile chiamando
hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE).
La modalità PIP è destinata alle attività che riproducono video a schermo intero. Quando passi alla modalità PIP, evita di mostrare qualsiasi cosa che non sia un contenuto video. Monitora quando la tua attività entra in modalità PiP e nascondi gli elementi UI, come descritto in Gestione della UI durante il PiP.
Per impostazione predefinita, quando un'attività è in modalità PiP, non riceve lo stato attivo dell'input. Per ricevere eventi di input in modalità PiP, utilizza MediaSession.setCallback().
Per maggiori informazioni sull'utilizzo di setCallback(), consulta
Visualizza una scheda Now Playing.
Quando l'app è in modalità PIP, la riproduzione di video nella finestra PIP può causare interferenze audio con un'altra app, ad esempio un'app di riproduzione musicale o di ricerca vocale. Per evitare questo problema, richiedi l'audio focus quando inizi a riprodurre il video e gestisci le notifiche di modifica dell'audio focus, come descritto in Gestione dell'audio focus. Se ricevi una notifica di perdita del focus audio in modalità PiP, metti in pausa o interrompi la riproduzione del video.
Quando la tua app sta per attivare la modalità PIP, tieni presente che solo l'attività principale entra in modalità Picture in picture. In alcune situazioni, ad esempio sui dispositivi Multi-finestra, è possibile che l'attività sottostante venga mostrata e diventi nuovamente visibile insieme all'attività PIP. Devi gestire questo caso di conseguenza, ad esempio
facendo in modo che l'attività sottostante riceva un callback onResume() o onPause().
È anche possibile che l'utente interagisca con l'attività.
Ad esempio, se hai un'attività di elenco di video visualizzata e l'attività di riproduzione di video in modalità PIP, l'utente potrebbe 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, consulta Android PictureInPicture Sample (Kotlin).