Android permite que varias apps compartan la misma pantalla al mismo tiempo. El sistema puede mostrar dos apps, una al lado de la otra (modo de pantalla dividida), una app en una ventana pequeña que se superpone con otras apps (modo de pantalla en pantalla) o apps individuales en diferentes ventanas que se pueden mover y a las que se les puede cambiar el tamaño (modo de formato libre).
Figura 1: Dos apps que se ejecutan una al lado de la otra en el modo de pantalla dividida.
La experiencia del usuario depende de la versión del SO Android y del tipo de dispositivo que tenga:
-
Android 7.0 ofrece el modo de pantalla dividida en dispositivos de mano y el modo de pantalla en pantalla en TV.
El modo de pantalla dividida ocupa la pantalla con dos apps y las muestra una al lado de la otra o una encima de la otra. Los usuarios pueden arrastrar la línea que divide las dos apps para ver una más grande que la otra.
El modo de pantalla en pantalla permite que los usuarios continúen con la reproducción de video mientras interactúan con otra app (consulta Compatibilidad con pantalla en pantalla).
Los fabricantes de dispositivos más grandes pueden optar por habilitar el modo de formato libre, en el que los usuarios pueden cambiar el tamaño de cada actividad como más les guste.
Para configurar la manera en que la app controla la visualización multiventana, puedes especificar las dimensiones mínimas permitidas de tu actividad. Además, si deseas inhabilitar la visualización multiventana para tu app, puedes establecer
resizeableActivity="false"
a fin de asegurarte de que el sistema siempre muestre la app en pantalla completa. - Android 8.0 extiende el modo de pantalla en pantalla a los dispositivos de mano.
Android 12 establece el modo multiventana como comportamiento estándar.
En pantallas grandes (ancho mínimo >= 600 dp), la plataforma admite todas las apps en el modo multiventana, independientemente de la configuración de la app. Si se establece
resizeableActivity="false"
, la app se pone en modo de compatibilidad cuando es necesario para adaptarse a las dimensiones de la pantalla.En pantallas pequeñas (ancho mínimo < 600 dp), el sistema verifica
minWidth
yminHeight
de una actividad para determinar si esta puede ejecutarse en el modo multiventana Si se estableceresizeableActivity="false"
, se evita que la app se ejecute en el modo multiventana, independientemente del ancho y de la altura mínimos.Nota: Los fabricantes de dispositivos pueden anular estos comportamientos.
Activación del modo de pantalla dividida
Para activar el modo de pantalla dividida los usuarios pueden hacer lo siguiente:
- Abrir la pantalla Recientes
- Deslizar una app para verla
- Presionar el ícono de la app en la barra de título
- Seleccionar la opción del menú Pantalla dividida
- Seleccionar otra app desde la pantalla Recientes o cerrar esta pantalla y ejecutar otra app
Para salir del modo de pantalla dividida, los usuarios pueden arrastrar la línea divisoria de las ventanas hacia el borde de la pantalla en cualquier dirección.
Ciclo de vida en el modo multiventana
El modo multiventana no cambia el ciclo de vida de la actividad. Sin embargo, el estado reanudado de las apps en varias ventanas varía según la versión de Android.
Reanudación múltiple
En Android 10 (nivel de API 29) y versiones posteriores, todas las actividades permanecen en el estado RESUMED
cuando el dispositivo está en el modo multiventana. La función se denomina reanudación múltiple.
Ten en cuenta que una actividad se puede pausar si hay una actividad transparente encima o si la actividad no se puede enfocar (p. ej., en el modo pantalla en pantalla). También es posible que ninguna actividad esté enfocada en un momento dado, por ejemplo, si el panel de notificaciones está abierto. El método onStop
funciona como de costumbre. Se lo llamará cada vez que se quite la actividad de la pantalla.
La reanudación múltiple también está disponible en ciertos dispositivos con Android 9. Para habilitar la reanudación múltiple en esos dispositivos, agrega los siguientes metadatos de manifiesto:
<meta-data android:name="android.allow_multiple_resumed_activities" android:value="true" />
Para verificar que un dispositivo en particular admita estos metadatos de manifiesto, consulta sus especificaciones.
Android 9
En el modo multiventana de Android 9 (nivel de API 28) y versiones anteriores, solo está activa en un momento determinado la actividad con la que el usuario interactuó más recientemente. Esta actividad se considera principal y es la única actividad que tiene el estado RESUMED
. Todas las demás actividades visibles tienen el estado STARTED
, pero no pueden aparecer como RESUMED
. No obstante, el sistema les da a esas actividades visibles pero no reanudadas una prioridad más alta que a las actividades que no están visibles. Si el usuario interactúa con una de las actividades visibles, esta se reanuda, y la actividad principal anterior pasa al estado STARTED
.
Cuando hay varias actividades dentro de un solo proceso de app activo, se reanuda la actividad con el orden Z más alto, y se pausan las otras.
Nota: En el modo multiventana de Android 9 y versiones anteriores, una app puede no aparecer con el estado RESUMED
aunque sea visible para el usuario. Es posible que una app necesite seguir ejecutándose mientras no sea la principal. Por ejemplo, una app de video en este estado debería seguir reproduciendo su contenido. Por este motivo, recomendamos que las actividades que reproduzcan videos no pausen la reproducción en respuesta al evento de ciclo de vida ON_PAUSE
. En su lugar, la actividad debe comenzar a reproducirse en respuesta a ON_START
y pausar la reproducción en respuesta a ON_STOP
. Si controlas los eventos de ciclo de vida de forma directa en lugar de utilizar el paquete Lifecycle, detén la reproducción de video en tu controlador onStop()
y reanuda la reproducción en
onStart()
.
Cambios de configuración
Cuando el usuario coloca una app en el modo multiventana, el sistema notifica a la actividad de un cambio de configuración, como se especifica en Cómo manejar cambios de configuración. Esto también sucede cuando el usuario modifica el tamaño de la app o la coloca nuevamente en el modo de pantalla completa.
Este cambio tiene en esencia las mismas consecuencias en el ciclo de vida de la actividad que cuando el sistema notifica a la app que el dispositivo cambió de la orientación vertical a la horizontal, excepto porque se modifican las dimensiones del dispositivo en lugar de intercambiarse solamente. Como se explica en Cómo manejar cambios de configuración, tu actividad puede procesar el cambio de configuración por sí misma o puede permitir que el sistema destruya la actividad y la vuelva a crear con las nuevas dimensiones.
Si el usuario cambia el tamaño de una ventana y la agranda en cualquier dirección, el sistema modifica el tamaño de la actividad para que coincida con la acción del usuario y emite cambios de configuración según sea necesario. Si la app se retrasa en el dibujo de áreas recientemente expuestas, el sistema rellena de forma temporal esas áreas con el color especificado por el atributo windowBackground
o por el atributo de estilo predeterminado windowBackgroundFallback
.
Acceso a recursos exclusivos
Para ayudar a admitir la reanudación múltiple, hay una nueva función de devolución de llamada de ciclo de vida: onTopResumedActivityChanged()
.
Este método se invoca cuando una actividad gana o pierde la posición de más reanudada. Esto es importante para saber cuándo una actividad utiliza un recurso compartido de singleton, como el micrófono o la cámara.
Kotlin
override fun onTopResumedActivityChanged(topResumed: Boolean) { if (topResumed) { // Top resumed activity // Can be a signal to re-acquire exclusive resources } else { // No longer the top resumed activity } }
Java
@Override public void onTopResumedActivityChanged(boolean topResumed) { if (topResumed) { // Top resumed activity // Can be a signal to re-acquire exclusive resources } else { // No longer the top resumed activity } }
Ten en cuenta que una app puede perder recursos debido a otras razones, como quitar una pieza de hardware compartida.
En cualquier caso, una app debe administrar de manera fluida los eventos y los cambios de estado que afectan a los recursos disponibles.
Para las apps que utilizan una cámara, CameraManager.AvailabilityCallback#onCameraAccessPrioritiesChanged()
brinda una sugerencia de que podría ser un buen momento para intentar acceder a la cámara. Este método está disponible a partir de Android 10 (nivel de API 29).
Recuerda que resizeableActivity=false
no es una garantía de acceso exclusivo a la cámara, ya que otras apps que la utilizan se pueden abrir en otras pantallas.
Figura 2: Cámara en modo Multiventana
No es necesario que tu app libere la cámara cuando pierde el enfoque. Por ejemplo, es posible que quieras continuar con la vista previa de la cámara mientras el usuario interactúa con la app recién enfocada que se reanudó más arriba. No hay problema si tu app sigue ejecutando la cámara cuando no es la app que se reanudó más arriba, pero debe administrar el caso de desconexión correctamente. Cuando la app más reanudada quiera usar la cámara, podrá usarla, y tu app perderá el acceso. Esta luego podrá reabrir la cámara cuando recupere el enfoque.
Después de que una app reciba una devolución de llamada CameraDevice.StateCallback#onDisconnected()
, las llamadas subsecuentes del dispositivo de cámara arrojarán un CameraAccessException
.
Varias pantallas
Android 10 (nivel de API 29) admiten actividades en pantallas secundarias. Si una actividad se ejecuta en un dispositivo con pantallas múltiples, los usuarios pueden mover la actividad de una pantalla a otra. La reanudación múltiple también se aplica a los casos con multipantallas. Varias actividades pueden recibir la entrada del usuario al mismo tiempo.
Una app puede especificar en qué pantalla debe ejecutarse cuando se inicia o cuando crea otra actividad. Este comportamiento depende del modo de inicio de la actividad definido en el archivo de manifiesto, y de las opciones y los marcadores de intent establecidos por la entidad que inicia la actividad. Consulta ActivityOptions
para obtener más información.
Cuando una actividad se traslada a una pantalla secundaria, puede atravesar una actualización de contexto, un cambio de tamaño de ventana, y modificaciones en la configuración y los recursos. Si la actividad administra el cambio de configuración, se le notificará en onConfigurationChanged()
. Si no lo hace, se volverá a iniciar.
Una actividad debe verificar la visualización actual en onCreate
y onConfigurationChanged
si se administra el cambio de configuración. Asegúrate de actualizar los recursos y diseños cuando cambie la pantalla.
Si el modo de inicio seleccionado para una actividad permite varias instancias, el inicio en una pantalla secundaria puede crear una nueva instancia de la actividad. Se reanudarán ambas actividades al mismo tiempo.
Figura 3: Varias instancias de una actividad en múltiples pantallas.
También recomendamos leer acerca de las API de pantallas múltiples que se agregaron en Android 8.0.
Contexto de la actividad frente a contexto de la aplicación
Usar el contexto correcto es crucial en las pantallas múltiples. Cuando se accede a recursos, el contexto de la actividad (que se muestra) difiere del contexto de la aplicación (que no se muestra).
El contexto de la actividad contiene información sobre la pantalla y siempre se ajusta de acuerdo con el área de visualización donde aparece la actividad. Esto te permite obtener la información correcta sobre la densidad de la pantalla o las métricas de la ventana que tu app tiene en la actualidad. Siempre debes usar el contexto de la actividad (u otro contexto basado en la IU) para obtener información sobre la ventana o la pantalla actual. Esto también influye en algunas API del sistema que usan información del contexto (por ejemplo, consulta Descripción general de los avisos).
La configuración de la ventana de la actividad y la pantalla superior definen recursos y contexto. Para obtener la pantalla actual, usa lo siguiente:
Kotlin
val activityDisplay = activity.getDisplay()
Java
Display activityDisplay = activity.getDisplay();
Para obtener las métricas de la ventana de la actividad actual, usa lo siguiente:
Kotlin
val windowMetrics = activity.getWindowManager().getCurrentWindowMetrics()
Java
WindowMetrics windowMetrics = activity.getWindowManager().getCurrentWindowMetrics();
Si quieres obtener las métricas máximas de la ventana para la configuración actual del sistema, usa el siguiente comando:
Kotlin
val maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics()
Java
WindowMetrics maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics();
Las métricas máximas de la ventana son para realizar cálculos, elegir el diseño o determinar el tamaño de los recursos que se deben recuperar con anticipación. Tener esta información disponible en onCreate()
te permite tomar estas decisiones antes del primer pase de diseño. Estas métricas no se deben utilizar para distribuir elementos de vista específicos y, en su lugar, usa información del objeto Configuration
.
Cortes de pantalla
Los dispositivos plegables pueden tener una geometría de cortes diferente cuando se pliegan y se despliegan. A fin de evitar problemas relacionados con los cortes, lee las prácticas recomendadas para admitir el corte de pantalla.
Pantallas secundarias
Puedes obtener las pantallas disponibles del servicio del sistema DisplayManager
:
Kotlin
val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager val displays = displayManager.getDisplays()
Java
DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE); Display[] displays = displayManager.getDisplays();
Usa la clase Display
para obtener información sobre una pantalla en particular, como su tamaño o las marcas que indican si una pantalla es segura. Sin embargo, no supongas que el tamaño de la pantalla será el mismo que el área de visualización asignado a tu aplicación. Recuerda que, en el modo multiventana, tu aplicación ocupa una parte de la pantalla.
Determina si una actividad puede iniciarse en una pantalla:
Kotlin
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val activityAllowed = activityManager.isActivityStartAllowedOnDisplay(context, displayId, intent)
Java
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); boolean activityAllowed = activityManager.isActivityStartAllowedOnDisplay(context, displayId, intent);
Luego, inicia la actividad en la pantalla:
Kotlin
val options = ActivityOptions.makeBasic() options.setLaunchDisplayId(targetDisplay.displayId) startActivity(intent, options.toBundle())
Java
ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchDisplayId(targetDisplay.displayId); startActivity(intent, options.toBundle());
Compatibilidad con pantallas múltiples
Android brinda compatibilidad con pantallas múltiples en teclados en pantalla, fondos de pantalla y selectores.
Teclado de software
Se puede mostrar un teclado en una pantalla secundaria si está configurada para admitir decoraciones del sistema. El editor del método de entrada aparecerá automáticamente si un campo de texto solicita una entrada en esa pantalla.
Figura 4: Teclado en una pantalla secundaria
Fondo de pantalla
En Android 10 (nivel de API 29), las pantallas secundarias pueden tener un fondo de pantalla. El framework crea una instancia separada de WallpaperService.Engine
para cada pantalla. Asegúrate de que se dibuje la superficie de cada motor de forma independiente. Los desarrolladores pueden cargar recursos utilizando el contexto de visualización de WallpaperService.Engine#getDisplayContext()
.
Además, asegúrate de que tu archivo WallpaperInfo.xml
establezca android:supportsMultipleDisplays="true"
.
Figura 5: Fondo de pantalla en el teléfono y en la pantalla secundaria.
Selectores
Una nueva categoría SECONDARY_HOME
de filtro de intents proporciona una actividad dedicada para las pantallas secundarias. Las instancias de esta actividad se utilizan en todas las pantallas que admiten decoraciones del sistema, una por cada pantalla.
<activity>
...
<intent-filter>
<category android:name="android.intent.category.SECONDARY_HOME" />
...
</intent-filter>
</activity>
La actividad debe tener un modo de inicio que no impida múltiples instancias y que pueda adaptarse a diferentes tamaños de pantalla. El modo de lanzamiento no puede ser singleInstance
ni singleTask
.
Por ejemplo, la implementación de AOSP de Launcher3
admite una actividad SECONDARY_HOME
.
Figura 6: Selector con aspecto de Material Design en un teléfono.
Figura 7: Selector con aspecto de Material Design en una pantalla secundaria.
Métricas de la ventana
Android 11 (nivel de API 30) introdujo los siguientes métodos WindowManager
para proporcionar los límites de las apps que se ejecutan en el modo multiventana:
getCurrentWindowMetrics()
: muestra un objetoWindowMetrics
para el estado actual de la renderización en ventanas del sistema.getMaximumWindowMetrics()
: muestra el objetoWindowMetrics
para el estado posible más grande de la renderización en ventanas del sistema.
Los métodos computeCurrentWindowMetrics()
y computeMaximumWindowMetrics()
de la biblioteca de WindowManager de Jetpack ofrecen una funcionalidad similar respectivamente, pero con retrocompatibilidad con el nivel de API 14.
Métodos obsoletos
Los métodos getSize()
y getMetrics()
de Display
dejaron de estar disponibles en el nivel de API 30 y se reemplazaron por los nuevos métodos WindowManager
.
En Android 12 (nivel de API 31), dejan de estar disponibles los métodos getRealSize()
y getRealMetrics()
de Display
, y se actualiza su comportamiento para que coincida mejor con el de getMaximumWindowMetrics()
.
Configuración del modo multiventana
Si tu app se orienta a Android 7.0 (nivel de API 24) o versiones posteriores, puedes configurar si las actividades de la app admiten la visualización multiventana y cómo lo hacen. Puedes establecer atributos en tu manifiesto para controlar el tamaño y el diseño. La configuración de atributos de una actividad raíz se aplica a todas las actividades de su pila de tareas.
Por ejemplo, si la actividad raíz tiene el objeto android:resizeableActivity="true"
, se puede cambiar el tamaño de todas las actividades de la pila de tareas. En algunos dispositivos más grandes, como las Chromebooks, tu app podría ejecutarse en una ventana que cambia de tamaño, incluso si especificas android:resizeableActivity="false"
. Si eso hace que tu app falle, puedes usar filtros para restringir la disponibilidad de la app en esos dispositivos.
Nota: Si compilas una app para varias orientaciones con un nivel de API 23 o inferior, y el usuario utiliza la app en el modo multiventana, el sistema redimensiona la app de manera forzosa. El sistema presenta un cuadro de diálogo en el que se advierte al usuario que la app puede comportarse de forma inesperada. El sistema no modifica el tamaño de apps con orientación fija; si el usuario intenta abrir una de esas aplicaciones en el modo multiventana, la app ocupará toda la pantalla.
De forma predeterminada, Android 12 (nivel de API 31) establece el modo multiventana. En pantallas grandes (ancho mínimo >= 600 dp), todas las apps se ejecutan en el modo multiventana, independientemente de la configuración de la app. En pantallas pequeñas, el sistema verifica la configuración de una actividad de minWidth
, minHeight
y resizeableActivity
para determinar si esta puede ejecutarse en el modo multiventana.
resizeableActivity
Establece este atributo en el elemento <activity>
o <application>
de tu manifiesto a fin de habilitar o inhabilitar la visualización en el modo multiventana para el nivel de API 30 y versiones anteriores:
<application android:name=".MyActivity" android:resizeableActivity=["true" | "false"] />
Si este atributo se establece en verdadero, la actividad puede iniciarse en los modos de pantalla dividida y formato libre. Si el atributo se establece en falso, la actividad no admite el modo multiventana. Si este valor es falso, y el usuario intenta iniciar la actividad en el modo multiventana, la actividad ocupará toda la pantalla.
Si tu app está orientada al nivel de API 24 o superior, pero no especificas un valor para este atributo, el valor predeterminado se establecerá como verdadero.
Si tu app se orienta al nivel de API 31 o superior, este atributo funciona de manera diferente en pantallas grandes y pequeñas.
- Pantallas grandes (ancho mínimo >= 600 dp): Todas las apps admiten el modo multiventana. El atributo indica si se puede cambiar el tamaño de una actividad. Si se establece
resizeableActivity="false"
, la app se pone en modo de compatibilidad cuando es necesario para ajustarse a las dimensiones de la pantalla. - Pantallas pequeñas (ancho mínimo < 600 dp): Si se establece
resizeableActivity="true"
, y el ancho y la altura mínimos de la actividad están dentro de los requisitos para multiventanas, la actividad admite el modo multiventana. Si se estableceresizeableActivity="false"
, la actividad no admite el modo multiventana, independientemente del ancho y de la altura mínimos de la actividad.
supportsPictureInPicture
Establece este atributo en el nodo <activity>
de tu manifiesto para indicar si la actividad admite el modo de pantalla en pantalla.
<activity android:name=".MyActivity" android:supportsPictureInPicture=["true" | "false"] />
Nota: Si se establece supportsPictureInPicture="true"
, debes configurar el atributo android:configChanges
para habilitar tu actividad a fin de controlar los cambios de configuración (consulta Compatibilidad con pantalla en pantalla).
configChanges
Para controlar los cambios de configuración del modo multiventana por tu cuenta, por ejemplo, lo que sucede cuando un usuario cambia el tamaño de una ventana, agrega el atributo android:configChanges
al nodo <activity>
del manifiesto de la app con al menos los siguientes valores:
<activity android:name=".MyActivity" android:configChanges="screenSize | smallestScreenSize | screenLayout | orientation" />
Después de agregar android:configChanges
, tu actividad y tus fragmentos recibirán una devolución de llamada a onConfigurationChanged()
en lugar de destruirse y volver a crearse. Luego, podrás actualizar manualmente las vistas, volver a cargar los recursos y realizar otras operaciones según sea necesario.
<layout>
Con Android 7.0, el elemento de manifiesto <layout>
admite varios atributos que afectan cómo se comporta una actividad en el modo multiventana:
-
android:defaultWidth
- Es el ancho predeterminado de la actividad cuando se inicia en modo de formato libre.
-
android:defaultHeight
- Es la altura predeterminada de la actividad cuando se inicia en modo de formato libre.
-
android:gravity
-
Es la ubicación inicial de la actividad cuando se inicia en el modo de formato libre. Consulta la referencia de
Gravity
para obtener valores adecuados. -
android:minHeight
,android:minWidth
- Son la altura y el ancho mínimos para la actividad tanto en el modo de pantalla dividida como en el de formato libre. Si el usuario mueve la línea divisoria en el modo de pantalla dividida para reducir el tamaño de la actividad a un valor menor al mínimo especificado, el sistema recorta la actividad para ajustarla a los requisitos del usuario.
El siguiente código muestra cómo especificar la ubicación y el tamaño predeterminados de una actividad, y su tamaño mínimo, cuando la actividad se visualiza en el modo de formato libre:
<activity android:name=".MyActivity"> <layout android:defaultHeight="500dp" android:defaultWidth="600dp" android:gravity="top|end" android:minHeight="450dp" android:minWidth="300dp" /> </activity>
Modo multiventana en tiempo de ejecución
A partir de Android 7.0, el sistema ofrece funcionalidad para admitir apps que pueden ejecutarse en el modo multiventana.
Funciones inhabilitadas en el modo multiventana
Ciertas funciones están inhabilitadas o se ignoran cuando un dispositivo se encuentra en el modo multiventana, ya que no resultan útiles para una actividad que podría estar compartiendo la pantalla del dispositivo con otras actividades o apps.
Algunas opciones de personalización de la IU del sistema están inhabilitadas; por ejemplo, las apps no pueden ocultar la barra de estado si no se están ejecutando en el modo multiventana (consulta Cómo controlar el nivel de visibilidad de la IU del sistema).
El sistema ignora los cambios del atributo android:screenOrientation
.
Consultas y devoluciones de llamadas del modo multiventana
La clase Activity
ofrece los siguientes métodos para admitir la visualización multiventana:
-
isInMultiWindowMode()
- Indica si la actividad está en el modo multiventana.
-
isInPictureInPictureMode()
- Indica si la actividad está en el modo de pantalla en pantalla.
-
Nota: El modo de pantalla en pantalla es un caso especial del modo multiventana. Si
myActivity.isInPictureInPictureMode()
muestra un valor verdadero,myActivity.isInMultiWindowMode()
también muestra el mismo valor. -
onMultiWindowModeChanged()
- El sistema llama a este método siempre que la actividad entra en el modo multiventana o sale de él. El sistema le pasa al método el valor verdadero si la actividad ingresa al modo multiventana o el valor falso si sale de él.
-
onPictureInPictureModeChanged()
- El sistema llama a este método siempre que la actividad entra en el modo de pantalla en pantalla o sale de él. El sistema le pasa al método el valor verdadero si la actividad ingresa al modo de pantalla en pantalla o el valor falso si sale de él.
La clase Fragment
expone versiones de muchos de estos métodos, como Fragment.onMultiWindowModeChanged()
.
Modo de pantalla en pantalla
Para que una actividad ingrese al modo de pantalla en pantalla, debes llamar a enterPictureInPictureMode()
. Este método no tiene efecto si el dispositivo no admite el modo de pantalla en pantalla. Para obtener más información, consulta Compatibilidad con pantalla en pantalla.
Nuevas actividades en el modo multiventana
Cuando inicias una nueva actividad, puedes indicar que la actividad nueva se debe mostrar adyacente a la actual si es posible. Usa la marca de intent
FLAG_ACTIVITY_LAUNCH_ADJACENT
, que le indica al sistema que intente crear la actividad nueva en una ventana adyacente, de modo que las dos compartan la pantalla. El sistema hace su mejor esfuerzo para llevarlo a cabo, pero no se garantiza que lo logre.
Si un dispositivo está en el modo de formato libre e inicias una actividad nueva, puedes especificar las dimensiones y la ubicación de la pantalla de la nueva actividad llamando a
ActivityOptions.setLaunchBounds()
. Este método no tiene efecto si el dispositivo no está en el modo multiventana.
En el nivel de API 30 y versiones anteriores, si inicias una actividad en una pila de tareas, esa actividad reemplazará la que esté en pantalla y heredará todas sus propiedades multiventana. Si quieres iniciar la actividad nueva en una ventana independiente en el modo multiventana, debes iniciarla en una nueva pila de tareas.
Android 12 (nivel de API 31) permite que las apps dividan la ventana de tareas de una aplicación entre varias actividades. Para determinar la manera en que la app muestra sus actividades (en pantalla completa, una al lado de la otra o apiladas), crea un archivo de configuración XML o realiza llamadas a la API de WindowManager de Jetpack.
Arrastrar y soltar
Los usuarios pueden arrastrar y soltar datos de una actividad a otra mientras las dos actividades comparten la pantalla. (Antes de Android 7.0, los usuarios solo podían arrastrar y soltar datos dentro de una sola actividad). A fin de agregar compatibilidad rápidamente para aceptar contenido que se soltó en widgets TextView
editables, consulta la interfaz de OnReceiveContentListener
. Para agregar compatibilidad más completa con la función de arrastrar y soltar, como habilitar la función de arrastrar contenido desde tu app, consulta Arrastrar y soltar.
Entre las clases y los métodos importantes para implementar la función de arrastrar y soltar, se incluyen los siguientes:
-
ClipData
- Representación de los datos en el portapapeles. Hace referencia a los datos que se transferirán mediante la operación de arrastrar y soltar.
-
DragAndDropPermissions
- Es el objeto token responsable de especificar los permisos otorgados a la app que recibe datos mediante la funcionalidad de arrastrar y soltar.
-
DragAndDropPermissions.release()
-
Actualiza los permisos necesarios para acceder a los datos en la URI de contenido que se proporcionan en
ClipData
. Si no llamas a este método, los permisos se actualizan automáticamente cuando se destruye la actividad que los contiene. -
View.startDragAndDrop()
-
Para habilitar la funcionalidad de arrastrar y soltar entre diferentes actividades, pasa la marca
DRAG_FLAG_GLOBAL
. Si necesitas otorgar permisos de URI a la actividad receptora, pasaDRAG_FLAG_GLOBAL_URI_READ
oDRAG_FLAG_GLOBAL_URI_WRITE
. -
View.cancelDragAndDrop()
- Cancela una operación de arrastre actualmente en curso. Solo lo puede llamar la app que originó la operación de arrastre.
-
View.updateDragShadow()
- Reemplaza la sombra de arrastre por una operación de arrastre actualmente en curso. Solo lo puede llamar la app que originó la operación de arrastre.
-
Activity.requestDragAndDropPermissions()
-
Solicita los permisos para los URI de contenido que se pasan con el
ClipData
incluido en unDragEvent
.
Instancias múltiples
Cada actividad raíz tiene su propia tarea, que se ejecuta en un proceso independiente y se muestra en su propia ventana. Para iniciar una instancia nueva de tu app en otra ventana, puedes iniciar actividades nuevas con la marca FLAG_ACTIVITY_NEW_TASK
.
Puedes combinar esto con algunos de los atributos de multiventanas para solicitar una ubicación específica de la ventana nueva. Por ejemplo, una app de compras puede mostrar varias ventanas para comparar productos.
Android 12 (nivel de API 31) te permite iniciar dos instancias de una actividad una al lado de la otra en la misma ventana de tareas.
No confundas las instancias múltiples con un diseño de varios paneles, como un diseño de lista y detalles que usa SlidingPaneLayout
, que se ejecuta en una sola ventana.
Ten en cuenta que cuando varias instancias se ejecutan en ventanas separadas en un dispositivo plegable, se pueden enviar una o más instancias a segundo plano si la cambia la posición. Por ejemplo, supongamos que un dispositivo está expandido y tiene dos instancias de apps ejecutándose en dos ventanas a ambos lados de la mitad superior. Si el dispositivo está plegado, una de las instancias podría finalizar en lugar de intentar ajustarse a las ventanas de ambas instancias en una pantalla más pequeña.
Verificación del modo multiventana
Independientemente de si tu app está orientada al nivel de API 24 o posterior, debes verificar cómo se comporta en el modo multiventana en caso de que un usuario intente iniciarla en un dispositivo que ejecute Android 7.0 o una versión posterior.
Cómo configurar un dispositivo de prueba
Si un dispositivo ejecuta Android 7.0 o una versión posterior, automáticamente admite el modo de pantalla dividida.
Si tu app está orientada al nivel de API 23 o inferior
Cuando el usuario intenta usar la app en el modo multiventana, el sistema cambia su tamaño de manera forzosa, a menos que la app declare una orientación fija.
Si tu app no declara una orientación fija, debes iniciarla en un dispositivo con Android 7.0 o una versión posterior, e intentar colocar la app en el modo de pantalla dividida. Cuando se modifique el tamaño de la app de manera forzosa, verifica que la experiencia del usuario sea aceptable.
Si la app declara una orientación fija, debes intentar colocarla en el modo multiventana. Cuando lo hagas, verifica que la app continúe en el modo de pantalla completa.
Si tu app está orientada desde el nivel de API 24 hasta el 30
Si tu app está orientada desde el nivel de API 24 hasta el 30 y no inhabilita la compatibilidad con el modo multiventana, verifica el siguiente comportamiento tanto en el modo de pantalla dividida como en el de formato libre:
- Inicia la app en el modo de pantalla completa y, luego, cambia al modo multiventana manteniendo presionado el botón Recientes. Verifica que la app pase de un modo al otro correctamente.
- Inicia la app directamente en el modo multiventana y verifica que se inicie en forma correcta. Puedes iniciar una app en el modo multiventana presionando el botón Recientes y, luego, manteniendo presionada la barra de título de la app y arrastrándola a una de las áreas resaltadas de la pantalla.
- Cambia el tamaño de tu app en el modo de pantalla dividida arrastrando la línea divisoria de la pantalla. Verifica que la app cambie de tamaño sin presentar fallas y que estén visibles los elementos necesarios de la IU.
- Si especificaste dimensiones mínimas para tu app, intenta cambiar el tamaño a dimensiones menores que las especificadas. Verifica que no puedas cambiar el tamaño de la app para que sea más pequeña que las dimensiones mínimas especificadas.
- En todas las pruebas, verifica que el rendimiento de la app sea aceptable. Por ejemplo, verifica que la actualización de la IU después de cambiar el tamaño de la app no tarde mucho.
Si tu app está orientada al nivel de API 31 o superior:
Si tu app se orienta al nivel de API 31 o superior, y el ancho y la altura mínimos de la actividad principal son inferiores o iguales a las dimensiones respectivas del área de visualización disponible, verifica todos los comportamientos que se indican desde el nivel de API 24 hasta el 30.
Nota: Para determinar, de manera programática, si tu app está en el modo multiventana, puedes verificar el valor que se muestra de Activity#isInMultiWindowMode()
.
Lista de tareas para pruebas
Para verificar el rendimiento de tu app en el modo multiventana, realiza las siguientes operaciones. Debes probar estas operaciones tanto en el modo de pantalla dividida como en el modo de formato libre, excepto cuando se indique algo diferente.
- Ingresa en el modo multiventana y luego sal de él.
- Pasa de tu app a otra y verifica que la app se comporte correctamente mientras esté visible pero inactiva. Por ejemplo, si tu app está reproduciendo un video, comprueba que este se siga reproduciendo mientras el usuario interactúa con otra aplicación.
- En el modo de pantalla dividida, prueba mover la línea divisora de la pantalla para agrandar y achicar la app. Realiza estas operaciones en las configuraciones una al lado de la otra y una encima de la otra. Verifica que la app no presente fallas, que las funcionalidades necesarias estén visibles y que la operación de cambio de tamaño no tarde mucho.
- Realiza varias operaciones de cambio de tamaño en una sucesión rápida. Verifica que tu app no falle ni pierda memoria. El Generador de perfiles de memoria de Android Studio proporciona información sobre el uso de memoria de tu app (consulta Cómo inspeccionar el uso de memoria de tu app con el Generador de perfiles de memoria).
- Usa tu app en diferentes configuraciones de ventanas y verifica que se comporte correctamente. Verifica que el texto sea legible y que los elementos de la IU sean lo suficientemente grandes como para interactuar con ellos.
Si inhabilitaste la compatibilidad con el modo multiventana
Desde el nivel de API 24 hasta el 30, si inhabilitaste la compatibilidad con el modo multiventana configurando android:resizeableActivity="false"
, debes iniciar tu app en un dispositivo que ejecute desde Android 7.0 hasta 11 e intentar colocar la aplicación en los modos de formato libre y de pantalla dividida. Cuando lo hagas, verifica que la app continúe en el modo de pantalla completa.
Recursos adicionales
Si deseas obtener más información sobre la compatibilidad con el modo multiventana en Android, consulta: