Android 14 (nivel de API 34) introduce algunas mejoras a las APIs de pantalla en pantalla (PIP) para permitir realizar varias tareas a la vez. Si bien la compatibilidad con PIP se introdujo en Android 8.0 (nivel de API 26), no era ampliamente compatible con Android TV y no era compatible con Google TV antes de Android 13. La función de varias tareas para TV usa el modo de PIP para permitir que dos apps independientes coexistan en la pantalla: una se ejecuta en pantalla completa y la segunda se ejecuta en modo de PIP. Existen diferentes requisitos 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. Este comportamiento es muy similar al comportamiento estándar de pantalla en pantalla de Android.
Ten en cuenta que, cuando integres la función de varias tareas a la vez, tu aplicación debe declarar sus tipos de uso de acuerdo con los lineamientos de calidad de apps para TV.
Cómo ejecutar tu app en modo de PIP
En dispositivos de TV que ejecutan Android 14 (nivel de API 34) o versiones posteriores, llama a enterPictureInPictureMode()
para ejecutar tu app en modo de PIP. Los dispositivos de TV que ejecutan versiones anteriores de Android no admiten el modo de 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 configura para que coincida con la relación de aspecto del video que se está reproduciendo.
Asegúrate de agregar un título y un subtítulo para proporcionarle al usuario información sobre el uso general de este PIP.
Coexiste con apps que se ejecutan en modo de PIP
Cuando tu app se ejecuta como una app en 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, hay APIs claras que las apps pueden usar para identificar componentes fundamentales de la IU que no se deben superponer. El sistema intenta respetar las solicitudes para evitar cubrir estos componentes mediante el reposicionamiento de la ventana de PIP.
Para especificar que no se debe superponer una vista, 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 algunas ocasiones, es posible que no necesites mantener claro un View
completo, sino solo una sección. El setPreferKeepClearRects()
se puede usar para especificar las regiones del View
que no se deben superponer. Las IU que no usan View
de forma nativa, como Flutter, Jetpack Compose y WebView, pueden tener subsecciones que requieran 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 con los tipos principales de uso para el modo de pantalla en pantalla. Cualquier <activity>
que haya configurado android:supportsPictureInPicture="true"
debe declarar este atributo con un valor relevante de la tabla que aparece a continuación.
Los tipos de uso que no se incluyen en ninguna de estas categorías, en particular en la reproducción de contenido multimedia, no se permiten en el modo de pantalla en pantalla en TV.
Valor | Descripción |
---|---|
"communication " |
Casos de uso de comunicaciones, como videollamadas o llamadas de voz |
"smartHome " |
Integraciones de casa inteligente, como timbres conectados o monitores para bebés |
"health " |
Casos de uso relacionados con la salud, como monitoreo del estado físico o de la salud. |
"ticker " |
Casos de uso de cotizaciones, como resultados deportivos en vivo o noticias y teletipos de acciones. |
Si hay varios valores, se separan con una barra vertical (|
). Por ejemplo:
<meta-data android:name="com.google.android.tv.pip.category" android:value="smartHome|health" />.