Multitasking sulla TV

Android 14 (livello API 34) introduce alcuni miglioramenti alle API picture in picture (PIP) per consentire il multitasking. Sebbene il supporto di PiP sia stato introdotto in Android 8.0 (livello API 26), non era ampiamente supportato su Android TV e non era affatto supportato su Google TV prima di Android 13. Il multitasking per la TV utilizza la modalità PIP per consentire a due app separate di coesistere sullo schermo: una in esecuzione a schermo intero e l'altra in modalità PIP. Esistono requisiti diversi per le app in esecuzione in una di queste modalità.

Il comportamento predefinito prevede che l'app PIP si sovrapponga all'app a schermo intero. È molto simile al comportamento standard di Picture in picture di Android.

Tieni presente che, quando integri il multitasking, la tua applicazione deve dichiarare i propri tipi di utilizzo in conformità alle norme sulla qualità delle app TV.

Esegui l'app in modalità PIP

Per i dispositivi TV con Android 14 (livello API 34) o versioni successive, esegui l'app in modalità PIP chiamando enterPictureInPictureMode(). I dispositivi TV con versioni precedenti di Android non supportano la modalità PiP.

Ecco un esempio di come implementare la logica di un pulsante per attivare la modalità PiP:

Kotlin

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    pictureInPictureButton.visibility =
        if (requireActivity().packageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
            pictureInPictureButton.setOnClickListener {
                val aspectRatio = Rational(view.width, view.height)
                val params = PictureInPictureParams.Builder()
                    .setAspectRatio(aspectRatio)
                    .build()
                val result = requireActivity().enterPictureInPictureMode(params)
            }
            View.VISIBLE
        } else {
            View.GONE
        }
}

Java

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if (requireActivity().getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
        pictureInPictureButton.setVisibility(View.VISIBLE);
        pictureInPictureButton.setOnClickListener(v -> {
            Rational aspectRatio = new Rational(view.getWidth(), view.getHeight());
            PictureInPictureParams params = new PictureInPictureParams.Builder()
                    .setAspectRatio(aspectRatio)
                    .setTitle("My Streaming App")
                    .setSubtitle("My On-Demand Content")
                    .build();
            Boolean result = requireActivity().enterPictureInPictureMode(params);
        });
    } else {
        pictureInPictureButton.setVisibility(View.GONE);
    }
}

L'azione viene aggiunta solo se il dispositivo dispone della funzionalità di sistema FEATURE_PICTURE_IN_PICTURE. Inoltre, quando l'azione viene attivata, le proporzioni della modalità PIP vengono impostate in modo da corrispondere alle proporzioni del video in riproduzione.

Assicurati di aggiungere un titolo e un sottotitolo per fornire all'utente informazioni sull'utilizzo generale di questo PIP.

Coesistenza con le app in esecuzione in modalità PiP

Quando la tua app è in esecuzione a schermo intero, potrebbe dover adattarsi ad altre app in esecuzione in modalità PIP.

API Keep-clear

In alcuni casi, l'app PiP potrebbe sovrapporsi a componenti importanti della UI all'interno dell'app a schermo intero. Per mitigare questo problema, esistono API keep-clear che le app possono utilizzare per identificare i componenti critici della UI che non devono essere sovrapposti. Il sistema tenta di soddisfare le richieste per evitare di coprire questi componenti riposizionando la finestra PiP.

Posizionamento della finestra PiP per evitare di coprire componenti importanti dell'interfaccia utente
Figura 1. Posizionamento della finestra PiP in modo da evitare di coprire componenti importanti dell'interfaccia utente.

Per specificare che una visualizzazione non deve essere sovrapposta, utilizza preferKeepClear nel layout XML come nell'esempio seguente:

<TextView
    android:id="@+id/important_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:preferKeepClear="true"
    android:text="@string/app_name"/>

Puoi farlo anche in modo programmatico utilizzando setPreferKeepClear():

Kotlin

private lateinit var binding: MyLayoutBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    binding = MyLayoutBinding.inflate(layoutInflater)
    setContentView(binding.root)
    binding.importantText.isPreferKeepClear = true
}

Java

private MyLayoutBinding binding;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    binding = MyLayoutBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());
    binding.importantText.setPreferKeepClear(true);
}

In alcuni casi, potrebbe non essere necessario mantenere libera un'intera View, ma solo una sezione. La proprietà setPreferKeepClearRects() può essere utilizzata per specificare le regioni di View che non devono essere sovrapposte. Le UI che non utilizzano View in modo nativo, come Flutter, Jetpack Compose e WebView, potrebbero avere sezioni secondarie che richiedono che le regioni rimangano libere. Questa API può essere utilizzata per questi casi.

Tipi di utilizzo

L'app deve dichiarare un attributo del valore dei metadati di com.google.android.tv.pip.category che corrisponde al tipo o ai tipi di utilizzo principali per la modalità Picture in picture. Qualsiasi <activity> che ha impostato android:supportsPictureInPicture="true" deve dichiarare questo attributo con un valore pertinente della tabella seguente.

I tipi di utilizzo che non rientrano in nessuna di queste categorie, in particolare la riproduzione di contenuti multimediali, non sono consentiti in modalità Picture in picture sulla TV.

Valore Descrizione
"communication" Casi d'uso delle comunicazioni, ad esempio chiamate vocali o videochiamate.
"smartHome" Integrazioni per la smart home, come campanelli o baby monitor connessi.
"health" Casi d'uso relativi alla salute, come il fitness tracker o il monitoraggio della salute.
"ticker" Casi d'uso di ticker, come risultati sportivi in tempo reale o ticker di notizie e azioni.

I valori multipli sono separati da una barra verticale (|). Ad esempio:

<meta-data android:name="com.google.android.tv.pip.category" android:value="smartHome|health" />