Le multitâche sur un téléviseur

Android 14 (niveau d'API 34) apporte des améliorations aux API Picture-in-picture (PiP) pour permettre le multitâche. Bien que la prise en charge du mode PIP ait été introduite dans Android 8.0 (niveau d'API 26), elle n'était pas largement prise en charge sur Android TV et pas du tout sur Google TV avant Android 13. Le multitâche pour téléviseur utilise le mode PIP pour permettre à deux applications distinctes de coexister à l'écran : l'une en plein écran et l'autre en mode PIP. Les exigences sont différentes pour les applications s'exécutant dans l'un ou l'autre de ces modes.

Par défaut, l'application PIP se superpose à l'application en plein écran. Ce comportement est très similaire à celui de la fonctionnalité Picture-in-picture d'Android.

Notez que lorsque vous intégrez le multitâche, votre application doit déclarer ses types d'utilisation conformément aux consignes relatives à la qualité des applications TV.

Exécuter votre application en mode PIP

Pour les appareils TV équipés d'Android 14 (niveau d'API 34) ou version ultérieure, exécutez votre application en mode PIP en appelant enterPictureInPictureMode(). Les téléviseurs équipés d'anciennes versions d'Android ne sont pas compatibles avec le mode PIP.

Voici un exemple d'implémentation de la logique d'un bouton pour passer en mode 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'action n'est ajoutée que si l'appareil dispose de la fonctionnalité système FEATURE_PICTURE_IN_PICTURE. De plus, lorsque l'action est déclenchée, le format du mode PIP est défini pour correspondre à celui de la vidéo en cours de lecture.

Veillez à ajouter un titre et un sous-titre pour informer l'utilisateur de l'objectif général de ce PIP.

Coexister avec les applications exécutées en mode PiP

Lorsque votre application s'exécute en mode plein écran, elle peut avoir besoin de s'adapter à d'autres applications exécutées en mode PIP.

API de zone dégagée

Dans certains cas, l'application PIP peut se superposer à des composants d'interface utilisateur importants dans l'application en plein écran. Pour éviter cela, il existe des API de dégagement que les applications peuvent utiliser pour identifier les composants d'interface utilisateur critiques qui ne doivent pas être masqués. Le système tente de respecter les demandes pour éviter de couvrir ces composants en repositionnant la fenêtre PiP.

Keep-Clear

Pour spécifier qu'une vue ne doit pas être superposée, utilisez preferKeepClear dans votre mise en page XML, comme dans l'exemple suivant :

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

Vous pouvez également effectuer cette opération de manière programmatique à l'aide de 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);
}

Il peut arriver que vous n'ayez pas besoin de laisser l'intégralité d'un View dégagé, mais seulement une partie. setPreferKeepClearRects() peut être utilisé pour spécifier les régions de View qui ne doivent pas être superposées. Les UI qui n'utilisent pas les View de manière native, comme Flutter, Jetpack Compose et WebView, peuvent comporter des sous-sections qui nécessitent que des régions restent dégagées. Cette API peut être utilisée dans ces cas.

Types d'utilisation

Votre application doit déclarer un attribut de valeur de métadonnées de com.google.android.tv.pip.category qui correspond au type ou aux types d'utilisation principaux du mode Picture-in-picture. Tout <activity> ayant défini android:supportsPictureInPicture="true" doit déclarer cet attribut avec une valeur pertinente du tableau ci-dessous.

Les types d'utilisation qui n'entrent dans aucune de ces catégories, en particulier la lecture de contenu multimédia, ne sont pas autorisés en mode Picture-in-picture sur un téléviseur.

Valeur Description
"communication" Cas d'utilisation des communications, comme les appels vidéo ou vocaux.
"smartHome" Les intégrations pour la maison connectée, comme les sonnettes ou les babyphones connectés.
"health" Cas d'utilisation liés à la santé, comme le suivi de la forme physique ou de l'état de santé.
"ticker" Cas d'utilisation des tickers, comme les résultats sportifs en direct, les actualités et les tickers boursiers.

Plusieurs valeurs sont séparées par une barre verticale (|). Exemple :

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