Android 14 (nivel de API 34) introduce algunas mejoras en las APIs de pantalla en pantalla (PIP) para permitir la realización de múltiples tareas. Si bien la compatibilidad con PIP se introdujo en Android 8.0 (nivel de API 26), no se admitió ampliamente en Android TV y no se admitió en absoluto en Google TV antes de Android 13. La función 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 otra en modo PIP. Existen diferentes requisitos para las apps que se ejecutan en cualquiera de estos modos.
El comportamiento predeterminado es que la app en PIP se superpone a la app en pantalla completa, que es muy similar al comportamiento estándar de pantalla en pantalla de Android.
Ten en cuenta que, cuando integres la función de multitarea, tu aplicación debe declarar sus tipos de uso de acuerdo con los lineamientos de calidad de las apps para TVs.
Ejecuta tu app en el modo de 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 modo PIP. Los dispositivos de TV que ejecutan versiones anteriores de Android no admiten el modo PIP.
A continuación, se muestra 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 para qué se usa generalmente este PIP.
Coexistir con apps que se ejecutan en modo de 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 zonas despejadas
En algunos casos, la app en PiP puede superponerse a componentes importantes de la IU dentro de la app en pantalla completa. Para mitigar esto, existen APIs de keep-clear que las apps pueden usar para identificar componentes críticos de la IU que no deberían superponerse. El sistema intenta cumplir con las solicitudes para evitar cubrir estos componentes reposicionando la ventana de PIP.
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 forma 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 despejado todo el View
, sino solo una sección. El setPreferKeepClearRects()
se puede usar para especificar 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 necesitan que las regiones se mantengan despejadas. Esta API se puede usar en 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 o los tipos principales de uso para el modo de pantalla en pantalla. Cualquier <activity>
que haya establecido android:supportsPictureInPicture="true"
debe declarar este atributo con un valor pertinente de la siguiente tabla.
Los tipos de uso que no se incluyen en ninguna de estas categorías, en particular la reproducción de contenido multimedia, no se permiten en el modo de pantalla en pantalla en la TV.
Valor | Descripción |
---|---|
"communication " |
Casos de uso de comunicaciones, como llamadas de voz o video |
"smartHome " |
Integraciones de casa inteligente, como timbres o monitores para bebés conectados |
"health " |
Casos de uso relacionados con la salud, como el monitoreo de la actividad física o de la salud |
"ticker " |
Casos de uso de marcadores, como marcadores de deportes en vivo o marcadores de noticias y 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" />