Realiza varias tareas a la vez en la TV

Android 14 (nivel de API 34) introduce algunas mejoras en las APIs de pantalla en pantalla (PiP) para permitir la realización de varias tareas a la vez. Si bien la compatibilidad con PiP se introdujo en Android 8.0 (nivel de API 26), no era muy compatible con Android TV y no era compatible en absoluto con Google TV antes de Android 13. La multitarea para TV usa el modo PIP para permitir que dos apps separadas coexistan en la pantalla: una se ejecuta en pantalla completa y la segunda, en modo PIP. Existen requisitos diferentes para las apps que se ejecutan en cualquiera de estos modos.

El comportamiento predeterminado es que la app de PiP se superpone a la app de pantalla completa. Esto es similar al comportamiento estándar del modo pantalla en pantalla de Android.

Ten en cuenta que, cuando integras la multitarea, tu aplicación debe declarar sus tipos de uso de acuerdo con los lineamientos de calidad de las apps para TV.

Ejecuta tu app en el modo PiP

En el caso de los dispositivos de TV que ejecutan Android 14 (nivel de API 34) o versiones posteriores, llama a enterPictureInPictureMode() para ejecutar tu app en el modo PiP. Los dispositivos de TV que ejecutan versiones anteriores de Android no admiten el modo PiP.

Este es un ejemplo de cómo implementar la lógica de un botón para ingresar al modo 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);
    }
}

La acción solo se agrega si el dispositivo tiene la función del sistema FEATURE_PICTURE_IN_PICTURE. Además, cuando se activa la acción, la relación de aspecto del modo de PIP se establece para que coincida con la del video que se está reproduciendo.

Asegúrate de agregar un título y un subtítulo para brindarle al usuario información sobre el uso general de este PIP.

Coexiste con apps que se ejecutan en el modo PIP

Cuando tu app se ejecuta como una app de pantalla completa, es posible que deba adaptarse a otras apps que se ejecutan en modo de PIP.

APIs de Keep-clear

En algunos casos, la app de PiP puede superponer componentes importantes de la IU dentro de la app de pantalla completa. Para mitigar esto, existen APIs de Keep-Clear que las apps pueden usar para identificar los componentes críticos de la IU que no deben superponerse. El sistema intenta cumplir con las solicitudes para evitar cubrir estos componentes cambiando la posición de la ventana del PiP.

Mantener despejado

Para especificar que una vista no debe superponerse, usa preferKeepClear en tu diseño XML, como en el siguiente ejemplo:

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

También puedes hacerlo de manera programática con 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);
}

En ocasiones, es posible que no necesites mantener un View completo, sino solo una sección. Se puede usar setPreferKeepClearRects() para especificar las regiones de View que no deben superponerse. Es posible que las IU que no usan View de forma nativa, como Flutter, Jetpack Compose y WebView, tengan sub secciones que necesiten que las regiones se mantengan claras. Esta API se puede usar para esos casos.

Tipos de uso

Tu app debe declarar un atributo de valor de metadatos de com.google.android.tv.pip.category que corresponda al tipo principal o a los tipos de uso del modo de imagen en imagen. Cualquier <activity> que haya configurado android:supportsPictureInPicture="true" debe declarar este atributo con un valor relevante de la siguiente tabla.

No se permiten los tipos de uso que no se incluyan en ninguna de estas categorías, en particular, la reproducción de contenido multimedia, en el modo de pantalla en pantalla en la TV.

Valor Descripción
"communication" Casos de uso de comunicación, como llamadas de voz o video
"smartHome" Integraciones de casa inteligente, como timbres conectados o monitores para bebés
"health" Casos de uso de salud, como el seguimiento de fitness o la supervisión de salud
"ticker" Casos de uso de indicadores, como resultados deportivos en vivo o noticias y tickers de acciones.

Los valores múltiples se separan con una barra vertical (|). Por ejemplo:

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