Home
Android 9: come programmare l’effetto PIP (Picture in Picture)

04 Ottobre 2019

Android 9: come programmare l’effetto PIP (Picture in Picture)

di

Le esigenze di uso degli smartphone sono giunte (anche) ad avere un effetto di immagine nell’immagine sullo schermo, come accade con i televisori. Android dispone delle strutture di programmazione per ottenere l’effetto in qualsiasi applicazione.

Un pulsante in HelloPIP

Nello scrivere codice per Android è possibile utilizzare una funzionalità chiamata Picture in Picture (PIP) e che, come dice il nome stesso, permette di visualizzare l’output di un’applicazione all’interno di un rettangolo di piccole dimensioni che si posiziona in una zona dello schermo dipendente dal device. È una feature che viene utilizzata il più delle volte per la visualizzazione di un filmato. Mentre rimando alla documentazione ufficiale per i dettagli, in questa occasione voglio semplicemente creare una piccola applicazione che si chiama HelloPIP e permette semplicemente di attivare la modalità PIP attraverso la selezione di un Button. Avere le cognizioni di programmazione Android per seguire il resto dell’articolo implica avere quelle per creare una nuova applicazione; pertanto mi limito a suggerire la creazione di una nuova applicazione di nome HelloPIP, che deve utilizzare un API Level superiore al 26, e aggiungiamo un semplice Button al centro dello schermo, come nella figura che segue.

Un Button in HelloPIP

Applicazione HelloPIP in esecuzione.

Un’applicazione non è abilitata di default al PIP, per cui si rende necessario applicare le seguenti configurazioni nel file AndroidManifest.xml per la particolare Activity, che nel nostro caso è:

<activity android:name=".MainActivity"
        android:supportsPictureInPicture="true"    android:resizeableActivity="true"    android:configChanges=        "screenSize|smallestScreenSize|screenLayout|orientation">    ...
    </activity>

Attraverso l’attributo android:supportsPictureInPicture dobbiamo abilitare la funzionalità di PIP in modo esplicito. Ovviamente se si utilizza il PIP l’activity deve poter cambiare le proprie dimensioni, per cui è necessario impostare l’attributo android:resizableActivity al valore true. Infine, è importante non riavviare l’Activity nel caso di abilitazione del PIP e questo è il motivo dell’utilizzo dell’attributo android:configChanges. A questo punto è possibile chiedere al sistema di mettere un’Activity nello stato PIP semplicemente invocando il seguente codice che abbiamo associato alla pressione del Button:

fun goPip(button: View) = enablePip()
    
    private fun enablePip() {
      val aspectRatio = Rational(4, 3)
      val params = PictureInPictureParams.Builder()
      .setAspectRatio(aspectRatio)
      .build()
      enterPictureInPictureMode(params)
    }

Il metodo goPip() viene invocato alla pressione del Button e non fa altro che richiamare un altro metodo privato incaricato dell’abilitazione vera e propria del PIP. Inizialmente creiamo un oggetto di tipo Rational, che è un modo elegante per definire un numero razionale, ovvero un numero che può essere rappresentato come numeratore/denominatore e che ci permette di indicare il rapporto tra larghezza e altezza della finestra di PIP. Attraverso il corrispondente Builder creiamo un oggetto di tipo PictureInPictureParams che può contenere alcuni parametri di configurazione. Nel nostro caso impostiamo solamente la proprietà aspectRatio. Infine, passiamo l’oggetto ottenuto invocando il metodo build() come parametro del metodo, che permette, appunto, il passaggio alla modalità PIP:

fun enterPictureInPictureMode(params: PictureInPictureParams?): Boolean

Se ora eseguiamo l’applicazione e premiamo il Button notiamo quanto rappresentato nella prossima figura, dove l’Activity è stata ridimensionata secondo il rapporto che avevamo indicato in precedenza.

Prima esecuzione nella modalità PIP

Prima esecuzione nella modalità PIP.

Nascondere il Button

Quella delle dimensioni non è comunque l’unica modifica che dovremmo fare, in quanto il Button è ancora disponibile. Per nasconderlo quando l’applicazione è in modalità PIP possiamo utilizzare il seguente codice:

override fun onPictureInPictureModeChanged(
        isInPictureInPictureMode: Boolean,
        newConfig: Configuration?
    ) {
      super.onPictureInPictureModeChanged(
          isInPictureInPictureMode,
          newConfig
      )
      if (isInPictureInPictureMode) {
        pipButton.visibility = View.INVISIBLE
        supportActionBar?.hide()
      } else {
        pipButton.visibility = View.VISIBLE
        supportActionBar?.show()
      }}

Avendo indicato, attraverso l’attributo android:configChanges, che la gestione delle configurazioni è di responsabilità dell’Activity, abbiamo la possibilità di eseguire l’overriding del metodo:

fun onPictureInPictureModeChanged(
        isInPictureInPictureMode: Boolean,
        newConfig: Configuration?
    )

Questo ci fornisce informazioni sullo stato del PIP che andiamo a utilizzare per nascondere il Button e l’ActionBar come nel codice evidenziato sopra.

A questo punto possiamo eseguire l’applicazione e ottenere quanto rappresentato nella figura qui sotto.

Modalità PIP senza Button e ActionBar

Modalità PIP senza Button e ActionBar.

Per tornare allo stato iniziale è possibile fare clic sul PIP ottenendo quanto rappresentato nella figura sottostante, dove notiamo un rettangolo nella parte centrale, selezionando il quale è possibile ritornare allo stato iniziale.

Tornare alla modalità iniziale

Tornare alla modalità iniziale.

Avere PIP in modo automatico

In precedenza, abbiamo accennato al fatto di come questa modalità venga utilizzata nel caso di video. È interessante allora vedere come sia possibile fare in modo che la modalità PIP avvenga in modo automatico in corrispondenza della pressione, per esempio, del tasto Home da parte dell’utente. Per fare questo è sufficiente utilizzare il seguente codice:

override fun onUserLeaveHint() {
      super.onUserLeaveHint()
      enablePip()
    }

Il metodo onUserLeaveHint() è infatti un metodo di callback che viene invocato quando l’Activity perde il focus a seguito di un’azione dell’utente che non distrugga l’Activity stessa come potrebbe essere un Back. Aggiungiamo quindi il precedente codice e notiamo come alla pressione del tasto Home, l’Activity vada effettivamente nella modalità PIP.

Come ultima funzionalità notiamo la possibilità di aggiungere delle azioni visibili solamente nella modalità PIP. Il classico esempio è, appunto, quello che video o della videochiamata che l’utente può interrompere o mettere in pausa. Per fare questo è sufficiente utilizzare un altro metodo della classe PictureInPictureParams.Builder il quale accetta come parametro una List di RemoteAction:

fun setActions(actions: List<RemoteAction>): Builder

Come dice il nome stesso, una RemoteAction descrive un concetto simile a quello del PendingIntent e permette di rappresentare un’azione che dovrà essere eseguita in un processo differente da quello nel quale è stata definita. Nel nostro caso abbiamo modificato il metodo enabled nel seguente modo, mettendo in evidenza la creazione della RemoteAction.

private fun enablePip() {
      val aspectRatio = Rational(4, 3)
      val remoteAction = RemoteAction(
          Icon.createWithResource(this, R.drawable.abc_btn_check_to_on_mtrl_000),
          "Act",
          "Act Descr",      PendingIntent.getActivity(this, 37, Intent(), 0)
      )  val params = PictureInPictureParams.Builder()
      .setAspectRatio(aspectRatio)
      .setActions(listOf(remoteAction))  .build()
      enterPictureInPictureMode(params)
    }

Esistono differenti modi per creare una RemoteAction, per i quali rimando alla documentazione ufficiale. L’aspetto fondamentale riguarda il fatto che, insieme alle varie label e icone, debba essere presente anche la definizione di un PendingIntent, che è quello che viene lanciato nel caso della selezione della corrispondente azione. Concludo evidenziando il fatto che l’azione venga messa a disposizione dell’utente qualora lo stesso selezionasse il PIP, come vediamo nell’ultima figura, dove l’azione è rappresentata da un piccolo quadrato nella parte centrale in basso.

Esempio di RemoteAction in PIP

Esempio di RemoteAction in PIP.

Questo articolo richiama contenuti dal capitolo 2 di Android 9.

L'autore

  • Massimo Carli
    Massimo Carli, dopo essersi occupato per più di dieci anni di applicazioni enterprise in ambiente Java, nel 2003 ha iniziato a interessarsi alle applicazioni mobile, sviluppando per dispositivi Blackberry, iOS e Android. Ha lavorato come Software Engineer per Yahoo! e Facebook ed è attualmente Lead Mobile Engineer per Lloyds Banking Group.

Iscriviti alla newsletter

Novità, promozioni e approfondimenti per imparare sempre qualcosa di nuovo

Gli argomenti che mi interessano:
Iscrivendomi dichiaro di aver preso visione dell’Informativa fornita ai sensi dell'art. 13 e 14 del Regolamento Europeo EU 679/2016.

Libri che potrebbero interessarti

Tutti i libri

Kotlin

Guida al nuovo linguaggio di Android e dello sviluppo mobile

19,99

di Massimo Carli

Android 9

Guida completa per lo sviluppo di applicazioni mobile

58,65

84,89€ -31%

47,41

49,90€ -5%

34,99

di Massimo Carli

Sviluppare applicazioni per Android

41,00

58,99€ -30%

33,25

35,00€ -5%

23,99

di Massimo Carli


Articoli che potrebbero interessarti

Tutti gli articoli