Android 14 (nivel de API 34) presenta 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 ampliamente compatible con Android TV y no era compatible con Google TV antes de Android 13. La función de multitarea para TV usa el modo PIP para permitir que dos apps independientes 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 superponga a la app en pantalla completa. Esto es muy similar al comportamiento estándar de la pantalla en pantalla de Android.
Ten en cuenta que, cuando integres la función de varias tareas, tu aplicación deberá declarar sus tipos de uso de conformidad con los lineamientos de calidad de las apps para TVs.
Ejecuta tu app en el modo PIP
En el caso de los dispositivos de TV que ejecutan Android 14 (nivel de API 34) o una versión posterior, llama a enterPictureInPictureMode() para ejecutar la app en el modo de pantalla en pantalla. Los dispositivos de TV que ejecutan versiones anteriores de Android no admiten el modo de PIP.
A continuación, se muestra un ejemplo de cómo implementar la lógica de un botón para ingresar al modo de pantalla en pantalla:
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 relación de aspecto 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.
Coexistencia con apps que se ejecutan en el modo de PIP
Cuando tu app se ejecuta en pantalla completa, es posible que deba adaptarse a otras apps que se ejecutan en el modo de PIP.
APIs de Keep-clear
En algunos casos, la app de pantalla en pantalla puede superponerse a componentes importantes de la IU dentro de la app de pantalla completa. Para mitigar este problema, existen APIs de mantener despejado que las apps pueden usar para identificar componentes críticos de la IU que no se deben superponer. El sistema intenta respetar las solicitudes para evitar cubrir estos componentes reposicionando la ventana de PiP.
Para especificar que una vista no se debe superponer, 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 despejada toda la View, sino solo una sección. setPreferKeepClearRects() se puede usar para
especificar regiones de 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 regiones que se mantengan despejadas. 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 el 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 relevante de la siguiente tabla.
Los tipos de uso que no se incluyen en ninguna de estas categorías, en particular, cualquier 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 de salud, como el seguimiento de la actividad física o el monitoreo de la salud |
"ticker" |
Casos de uso de cintas de información, como resultados deportivos en vivo o cintas de noticias y de cotizaciones 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" />