Android activa un modo de compatibilidad para las apps que declaran restricciones de orientación o cambio de tamaño. El modo de compatibilidad garantiza un comportamiento aceptable de la app en dispositivos con pantallas grandes y teléfonos plegables, pero con una usabilidad deficiente.
Las anulaciones por app permiten que los fabricantes de dispositivos, los propietarios de dispositivos virtuales1 y los usuarios cambien el comportamiento de las apps para mejorar su diseño o evitar que fallen en dispositivos seleccionados.
Android 16
Android 16 (nivel de API 36) ignora las restricciones de orientación de la pantalla, relación de aspecto y capacidad de cambio de tamaño de la app para mejorar el diseño de las apps en factores de forma con un ancho más pequeño >= 600 dp.
Las siguientes anulaciones por app no funcionan para las apps que segmentan el nivel de API 36:
- FORCE_RESIZE_APP
- FORCE_NON_RESIZE_APP
- OVERRIDE_MIN_ASPECT_RATIO
- OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY
- OVERRIDE_MIN_ASPECT_RATIO_MEDIUM
- OVERRIDE_MIN_ASPECT_RATIO_LARGE
- OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN
- OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN
- OVERRIDE_ANY_ORIENTATION
- OVERRIDE_ANY_ORIENTATION_TO_USER
- OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT
- OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR
- OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE
- OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA
- OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION
- OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION
- OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED
- OVERRIDE_RESPECT_REQUESTED_ORIENTATION
- OVERRIDE_EXCLUDE_CAPTION_INSETS_FROM_APP_BOUNDS
Inhabilitar
Tu app puede segmentarse para el nivel de API 36, pero inhabilitar el comportamiento de Android 16, en cuyo caso OVERRIDE_ANY_ORIENTATION_TO_USER no es aplicable.
Cómo declarar la propiedad del manifiesto
Para inhabilitar el comportamiento del nivel de API 36, declara la propiedad del manifiesto PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY
.
Para inhabilitar una actividad específica, configura la propiedad en el elemento <activity>
:
<activity ...>
<property
android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"
android:value="true" />
...
</activity>
Para inhabilitar la función en toda la app, establece la propiedad en el elemento <application>
:
<application ...>
<property
android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"
android:value="true" />
...
</application>
Dispositivos de referencia
Los siguientes dispositivos pueden requerir anulaciones por app debido a configuraciones inusuales o que no son bien compatibles con las apps:
- Tablets: La orientación natural de algunas tablets, como la Pixel Tablet, es horizontal. Un dispositivo se encuentra en su orientación natural cuando
Display#getRotation()
devuelveSurface.ROTATION_0
. Si las apps suponen queROTATION_0
es vertical, los diseños de las apps y la vista previa de la cámara pueden no coincidir con la pantalla del dispositivo. - Dispositivos plegables horizontales: Algunos dispositivos plegables, como el Pixel Fold, están en orientación vertical cuando están plegados, pero en orientación horizontal cuando están desplegados. Si las apps suponen que la orientación desplegada es vertical, es probable que se produzcan bucles parpadeantes o problemas de diseño.
- Teléfonos plegables: Los teléfonos plegables desplegados suelen estar en orientación vertical. Sin embargo, cuando están plegados, los teléfonos suelen tener una pantalla pequeña en orientación horizontal. Las apps deben identificar y adaptarse a las diferentes orientaciones de las pantallas.
- Pantallas externas: Algunos dispositivos pueden iniciar una sesión de ventanas de escritorio en pantallas externas conectadas. Las apps deben consultar pantallas externas para obtener información como el tamaño y la resolución de la pantalla. De lo contrario, es posible que las apps hagan suposiciones incorrectas sobre las pantallas, lo que puede generar un comportamiento incorrecto de la app.
- Pantallas de automóviles: Muchas pantallas de automóviles son horizontales, pero no todas. El desarrollo de apps para usar en el vehículo estacionado para pantallas de automóviles es similar al desarrollo para tablets.
Problemas comunes de compatibilidad
Las apps experimentan problemas de compatibilidad con mayor frecuencia debido a restricciones en su orientación, en la relación de aspecto y en la capacidad de cambiar el tamaño; el control incorrecto de la orientación de la vista previa de la cámara y las APIs que se usan de manera inadecuada.
Formato letterbox
El formato letterbox posiciona la app en el centro de la pantalla o, en pantallas grandes, a un lado o al otro para facilitar el acceso. Los elementos mate (barras de colores sólidos o fondos de pantalla desenfocados) ocupan el área de visualización sin usar a los costados o en la parte inferior o superior de la app.
El formato letterbox suele utilizarse en dispositivos con pantallas grandes, ya que las dimensiones y la relación de aspecto de los dispositivos suelen ser distintas de las de los teléfonos estándar, para los que se diseñan la mayoría de las apps.
Figura 1: La app solo con orientación vertical tiene formato letterbox cuando la tablet o el dispositivo plegable está en posición horizontal.
Problema
La app no es compatible con todas las configuraciones de pantalla porque tiene una orientación o relación de aspecto fijas, o bien no puede cambiar de tamaño.
Entre los parámetros de configuración que controlan la orientación y el ajuste de tamaño de la app, se incluyen los siguientes:
screenOrientation
: Especifica una orientación fija para una app. Las apps también pueden establecer la orientación en el tiempo de ejecución conActivity#setRequestedOrientation()
.resizeableActivity
: Indica si el sistema puede cambiar el tamaño de las apps para que se ajusten a ventanas de diferentes dimensiones. En Android 11 (nivel de API 30) y versiones anteriores, especifica si las apps admiten el modo multiventana. En Android 12 (nivel de API 31) y versiones posteriores, especifica si las apps admiten el modo multiventana en pantallas pequeñas (clase de tamaño de ventana compacta). En Android 12 y versiones posteriores, las apps admiten el modo multiventana en pantallas grandes (clase de tamaño de ventana medio o expandido), independientemente de este parámetro de configuración.maxAspectRatio
: Especifica la relación de aspecto máxima que admite la app. Solo las apps conresizeableActivity
establecido enfalse
pueden establecermaxAspectRatio
.minAspectRatio
: Especifica la relación de aspecto mínima que admite la app. Solo las apps conresizeableActivity
establecido enfalse
pueden establecerminAspectRatio
.
La app con solo orientación vertical no se puede usar en dispositivos en posición horizontal
Optimización
La app debe admitir todas las orientaciones y tamaños de pantallas y dispositivos en modo multiventana. Quita todas las restricciones de orientación y relación de aspecto fijas de los diseños de tu app y del archivo de manifiesto de la app.
La app admite todas las orientaciones del dispositivo
Solución al problema de compatibilidad
Si una app con orientación o relación de aspecto fijas se ejecuta en una ventana en la que no es compatible directamente con el tamaño o la orientación de la ventana, Android aplica el formato letterbox para preservar la continuidad.
A partir de Android 12 (nivel de API 31) y hasta la versión 12L (nivel de API 32), la plataforma aplica una variedad de mejoras a las apps en formato letterbox. Los fabricantes de dispositivos implementan las mejoras en la IU. No es necesario que realices ninguna tarea de desarrollo adicional para que la app aproveche las mejoras.
Android 12 (nivel de API 31) incorpora las siguientes mejoras estéticas que los fabricantes de dispositivos pueden configurar:
- Esquinas redondeadas: Las esquinas de la ventana de la app lucen un aspecto más refinado.
- Transparencia de la barra del sistema: Las barras de estado y navegación, que se superponen sobre la app, son semitransparentes, lo que hace que los íconos de las barras siempre sean visibles sobre el fondo del formato letterbox.
- Relación de aspecto configurable: Se puede ajustar la relación de aspecto de la app para mejorar su apariencia.
Figura 2: App en formato letterbox con mejoras en la IU.
La versión 12L (nivel de API 32) agrega las siguientes mejoras funcionales:
Posicionamiento configurable: En pantallas grandes, los fabricantes de dispositivos pueden posicionar la app en el lado izquierdo o derecho de la pantalla, lo que facilita la interacción.
Botón Reiniciar rediseñado: Los fabricantes de dispositivos pueden brindarle una nueva apariencia al botón Reiniciar para el modo de compatibilidad de tamaño, de manera que los usuarios lo reconozcan mejor.
Android 13 (nivel de API 33) agrega un diálogo de información para el usuario sobre el posicionamiento de la app en formato letterbox en pantalla o la inclusión del formato letterbox en el modo de pantalla dividida:
Figura 3: App en formato letterbox con un diálogo de información para el usuario.
Modo de compatibilidad de tamaño
El modo de compatibilidad de tamaño es el formato letterbox que mantiene la relación de aspecto de la app y que incluye un control de reinicio. El control permite a los usuarios reiniciar la app y volver a dibujar la pantalla. Android invoca el modo de compatibilidad de tamaño para las apps que no pueden cambiar de tamaño. Cuando una actividad se mueve a un contenedor de pantalla que es incompatible con las dimensiones de la actividad, el sistema puede cambiar la escala de la app para que ocupe la pantalla del dispositivo en, al menos, una dimensión.
Entre los cambios de configuración del dispositivo que pueden activar el modo de compatibilidad de tamaño, se incluyen los siguientes:
- Rotación del dispositivo
- Plegar o desplegar un dispositivo plegable
- Cambiar entre los modos de visualización de pantalla completa y pantalla dividida
Problema
Por lo general, el modo de compatibilidad de tamaño se aplica a actividades que tienen una restricción de orientación o relación de aspecto y que se configuran (o que el sistema determina) para que no puedan cambiar de tamaño.
Se considera que tu app puede cambiar de tamaño y que no se colocará en el modo de compatibilidad de tamaño si cumple con alguno de los siguientes criterios:
- Se puede cambiar el tamaño con
resizeableActivity="true"
. - Admite el modo pantalla en pantalla (PIP).
- Está incorporada.
- Tiene la anulación por app de
FORCE_RESIZE_APP
aplicada por el fabricante del dispositivo (se ignoran las propiedades que estableció la app).
Si tu app no cumple con ninguna de las condiciones, se considera que no puede cambiar de tamaño y se puede establecer en modo de compatibilidad de tamaño.
La app que no puede cambiar de tamaño falla en el modo multiventana
Optimización
La app debe admitir todos los tamaños de visualización. Para hacer que tu app pueda cambiar de tamaño, configura el atributo android:resizeableActivity
del elemento <activity>
o <application>
como true
en el manifiesto de la app. Crea diseños responsivos o adaptables para tu app. Para obtener más información, consulta Cómo brindar compatibilidad con diferentes tamaños de pantalla y Compatibilidad con el modo multiventana.
La app funciona en todos los tamaños de ventana
Solución al problema de compatibilidad
Android coloca una app en el modo de compatibilidad de tamaño cuando el sistema determina que se puede mejorar la visualización de la app en formato letterbox si se ajusta su escala para que ocupe toda la ventana de la pantalla en, al menos, una dimensión. El sistema muestra un control de reinicio que recrea el proceso de la app, reproduce la actividad y vuelve a dibujar la pantalla. Consulta también la Descripción general de los procesos y subprocesos.
Se agrega formato letterbox en orientación horizontal a la app solo con modo vertical; el control de reinicio modifica la escala
Modo de compatibilidad de pantalla
El modo de compatibilidad de pantalla evita que se reinicie una app cuando se mueve entre diferentes pantallas, lo que puede activar un cambio de configuración, como un cambio de modo de color, disponibilidad de pantalla táctil o densidad de pantalla.
El modo de compatibilidad de pantalla está habilitado de forma predeterminada para los juegos (según la marca android:appCategory
) para mejorar la estabilidad y la continuidad.
A diferencia del modo de compatibilidad de tamaño, el modo de compatibilidad de pantalla no inmoviliza la configuración de la app. La app aún puede recibir todas las actualizaciones de configuración a través de APIs como la devolución de llamada onConfigurationChanged()
, pero se evita un reinicio disruptivo. Esto significa que los juegos que admiten correctamente APIs como onConfigurationChanged() pueden actualizar su IU de forma responsiva incluso si están en modo de compatibilidad de pantalla.
Para inhabilitar el modo de compatibilidad de pantalla y controlar los cambios de configuración en tu app, declara la compatibilidad con los cambios de configuración en el archivo AndroidManifest.xml
de la app y controla los cambios de configuración en la devolución de llamada onConfigurationChanged().
<activity
android:name=".MyGameActivity"
android:configChanges="colorMode|touchscreen|density|...">
...
</activity>
Bucles parpadeantes
Cuando una app no admite todas las orientaciones de pantalla, puede solicitar de manera reiterada orientaciones nuevas cuando se produce un cambio de configuración, lo que crea un bucle infinito que hace que la pantalla parpadee o que la app rote sin fin.
Problema
En Android 12 (nivel de API 31) y versiones posteriores, los fabricantes de dispositivos pueden configurar sus dispositivos para ignorar las restricciones de orientación que especifican las apps y, en su lugar, aplicar modos de compatibilidad. Por ejemplo, un dispositivo plegable podría ignorar el parámetro de configuración android:screenOrientation="portrait"
de una actividad cuando esta se muestra en la pantalla interior en tamaño tablet en orientación horizontal del dispositivo.
Cuando se ignoran las restricciones de orientación de una app, esta puede establecer su orientación de manera programática si se llama a Activity#setRequestedOrientation()
. La llamada activa el reinicio de una app si esta no controla los cambios de configuración (consulta Cómo administrar los cambios en la configuración). Después del reinicio, las restricciones de orientación de la app se vuelven a ignorar, la app repite la llamada a setRequestedOrientation()
, la llamada activa un reinicio de la app, y así sucesivamente, en un bucle infinito.
Otra forma en la que puedes encontrar esto es cuando la orientación natural (la orientación habitual que determina Android) de la pantalla de un dispositivo es horizontal (es decir, al llamar a Display#getRotation()
, se devuelve Surface.ROTATION_0
mientras que el dispositivo tiene una relación de aspecto horizontal). Históricamente, las apps suponen que Display.getRotation() =
Surface.ROTATION_0
significa que el dispositivo se encuentra en orientación vertical, pero no siempre es así (por ejemplo, en la pantalla interior de algunos dispositivos plegables y en algunas tablets).
Una app con orientación horizontal en una pantalla interior plegable puede comprobar la rotación de la pantalla, recibir un valor de ROTATION_0
, dar por sentado que la orientación natural del dispositivo es vertical y llamar a setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
)
para reconfigurar el diseño de la app. Después de que se reinicia la app (en orientación horizontal), es posible que vuelva a verificar la rotación de la pantalla, reciba un valor de ROTATION_0
, llame a setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
y continúe el bucle infinito.
La app solo con modo horizontal en la pantalla vertical realiza llamadas repetidas a Activity#setRequestedOrientation()
Optimización
Las apps no deben hacer lo siguiente:
- Establecer una orientación predeterminada con
Activity#setRequestedOrientation()
en el métodoonCreate()
de la actividad porque la solicitud de orientación puede activarse de forma inesperada por cambios de configuración no controlados - Dar por sentado que la orientación natural del dispositivo (
ROTATION_0
) es vertical - Configurar la orientación en función de indicadores no relacionados con el tamaño actual de la ventana, como
Display#getRotation()
, la presencia deFoldingFeature
o las APIs obsoletas
La app controla los cambios de configuración, no tiene restricciones de orientación, por lo que no entra a un bucle parpadeante
Solución al problema de compatibilidad
Android ignora las llamadas a Activity#setRequestedOrientation()
en las siguientes situaciones:
La actividad ya se reinició a partir de una llamada anterior al método o se habilitó el tratamiento de rotación de compatibilidad forzada con la cámara (consulta Vista previa de la cámara a continuación).
Los fabricantes de dispositivos pueden aplicar este comportamiento a una app con
OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION
.La actividad realizó más de dos solicitudes de orientación en un segundo, lo que indica que se produjo un bucle. De las dos solicitudes en el bucle, Android usa la que maximiza el área de visualización de la app.
Los fabricantes de dispositivos pueden aplicar este comportamiento a una app con
OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED
.Los propietarios de dispositivos virtuales anularon la llamada al método en dispositivos seleccionados.
Vista previa de cámara
La vista previa (o el visor) de la cámara de las apps de cámara puede desalinearse o distorsionarse en pantallas de tablets, laptops y plegables.
Problema
El documento de definición de compatibilidad de Android especifica que un sensor de imagen de la cámara "SE DEBE orientar para que la dimensión larga de la cámara se alinee con la dimensión larga de la pantalla".
A menudo, las apps suponen que la orientación del dispositivo y el sensor de la cámara son verticales, una suposición razonable en los teléfonos celulares estándar. Sin embargo, la orientación natural de las tablets, las laptops y los sensores de la cámara puede ser horizontal. Además, los nuevos factores de forma, como los dispositivos plegables, pueden tener varias orientaciones naturales y distintos sensores de la cámara en diferentes orientaciones.
Iniciar una actividad con una orientación de cámara que la app no espera o cambiar entre diferentes cámaras o pantallas de dispositivos (en el caso de dispositivos plegables) puede generar una vista previa de la cámara desalineada o distorsionada.
Vista previa de la cámara desalineada y distorsionada en un plegable de pantalla grande
Optimización
Las apps de cámara deben identificar y administrar correctamente la orientación del dispositivo y del sensor de la cámara para mostrar una vista previa de la cámara alineada y ajustada de manera adecuada. Las apps deben calcular la rotación del dispositivo y del sensor, y la relación de aspecto de la pantalla o la ventana y, luego, aplicar los resultados a la vista previa de la cámara. Para obtener ayuda detallada, consulta Vista previa de la cámara y Presentación del visor de la cámara.
La vista previa de la cámara está alineada y ajustada correctamente en todas las orientaciones del dispositivo
Solución al problema de compatibilidad
Un dispositivo se encuentra en orientación natural cuando Display#getRotation()
devuelve Surface.ROTATION_0
. El sistema calcula CameraCharacteristics.SENSOR_ORIENTATION
a partir de la orientación natural del dispositivo. Android alinea la ventana vertical de las apps con restricción vertical con la orientación natural del dispositivo, que es lo que espera la mayoría de las apps. Android también recorta la imagen del sensor de la cámara cuando la orientación del sensor es horizontal y la vista previa de la cámara es vertical. Las soluciones específicas incluyen las siguientes:
Forzar la rotación de la vista previa de la cámara en apps con restricción vertical: Las apps restringidas en orientación vertical esperan que la orientación natural del dispositivo y la del sensor de la cámara sean verticales. Sin embargo, en Android 12 (nivel de API 31) y versiones posteriores, las apps pueden ejecutarse en varias orientaciones si los fabricantes ignoran la especificación de orientación.
Cuando se conecta una app con restricción vertical a la cámara, Android rota de manera forzosa la app para alinear la ventana vertical de la app con la orientación natural del dispositivo.
En algunas tablets (consulta los dispositivos de referencia), la ventana vertical de la app se rota a la pantalla completa vertical para alinearse con la orientación natural del dispositivo. La app ocupa la pantalla completa después de forzar la rotación.
Tablet: Rotación forzada de una app solo con orientación vertical
En la pantalla interior horizontal de los dispositivos plegables (consulta los dispositivos de referencia), las actividades solo verticales se rotan a la posición horizontal para alinearse con la orientación natural desplegada. La app tiene formato letterbox después de forzar la rotación.
Dispositivo plegable: Rotación forzada de una app solo con orientación vertical; la app también tiene formato letterbox
Recorte del interior de la cámara frontal: El sensor interno de la cámara frontal de algunos teléfonos plegables se encuentra en orientación horizontal. Además de forzar la rotación de la vista previa de la cámara en la pantalla interior del dispositivo plegable, Android recorta el campo visual interno de la cámara frontal (horizontal) para que el sensor capture una vista opuesta a la orientación del dispositivo.
Forzar la actualización de las vistas previas de la cámara: El sistema alterna entre los métodos de actividad
onStop()
yonStart()
(de forma predeterminada) oonPause()
yonResume()
(que aplica la anulación por app OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE) después de forzar la rotación para garantizar que la vista previa de la cámara se muestre correctamente.Ajuste de relación de aspecto: El sistema cambia de forma dinámica la relación de aspecto de la vista previa de la cámara rotada de manera forzosa para que tenga una relación de aspecto mínima más alta, lo que garantiza que se ajuste bien la vista previa de la cámara.
Los desarrolladores de apps pueden anular estas soluciones alternativas si las apps controlan la vista previa de la cámara correctamente. Consulta Anulaciones por app.
APIs que suelen usarse de manera inadecuada
Como Android agregó compatibilidad con funciones, como el modo multiventana, y dispositivos, como los plegables, las APIs heredadas dejaron de estar disponibles y se reemplazaron por APIs actualizadas que funcionan con todos los tamaños de visualización y factores de forma de dispositivos. Sin embargo, las APIs obsoletas aún están disponibles para brindar retrocompatibilidad.
Algunas APIs de View
se diseñaron con fines especiales que los desarrolladores no siempre comprenden bien.
Problema
Los desarrolladores siguen usando las APIs de Display
obsoletas y suponen erróneamente que las APIs devuelven los límites de la app en lugar de los límites del área de visualización del dispositivo. O bien, los desarrolladores usan por error APIs de View para fines especiales para obtener métricas de visualización generales.
El resultado son errores de cálculo cuando se reubican elementos de la IU después de los eventos de cambio de tamaño de la ventana de la app, lo que causa problemas de diseño.
APIs de Display obsoletas y que suelen usarse de manera inadecuada:
Para obtener más información, consulta Compatibilidad con el modo multiventana.
APIs de View que se usan de manera inadecuada:
La API obsoleta calcula erróneamente los límites de la app. El contenido de la app desaparece de la pantalla.
Optimización
Nunca dependas del tamaño de la pantalla física para posicionar elementos de la IU. Migra tu app a las APIs basadas en WindowMetrics
, incluidas las siguientes APIs de WindowManager
:
Plataforma:
Jetpack:
La API calcula correctamente las métricas de la ventana de la app
Solución al problema de compatibilidad
Dos anulaciones ajustan las APIs de Display
obsoletas y las APIs de View
que se usan de manera inadecuada para devolver los límites de la app: ALWAYS_SANDBOX_DISPLAY_APIS
para las APIs de Display
; OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS
para las APIs de View
. ALWAYS_SANDBOX_DISPLAY_APIS
también se aplica de forma predeterminada a las apps que califican para el modo de compatibilidad de tamaño.
Actividades transparentes
Las actividades transparentes son el resultado de estilos de fondo transparentes, por ejemplo:
<style name="Transparent" parent="AppTheme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
Los temas relacionados con los diálogos, como Theme.MaterialComponents.Dialog
, pueden incluir estilos que hacen que las actividades sean transparentes.
Las actividades transparentes no abarcan todo el espacio de visualización disponible, lo que dificulta su administración, ya que el área de visualización disponible puede cambiar en función de los cambios de configuración, como la rotación, el plegado y el desplegado de dispositivos, y el modo multiventana.
Problema
Una actividad transparente debe cumplir con los límites de la primera actividad opaca debajo de la actividad transparente en la pila de actividades de tareas. Sin embargo, una actividad opaca que inicia un diálogo de permisos puede ser un trampolín (una actividad que inicia otra actividad y luego desaparece). Por lo tanto, el sistema no puede determinar los límites de la actividad de trampolín que inició la actividad transparente del diálogo de permisos.
El diálogo está mal posicionado porque la actividad se inició desde un trampolín.
Optimización
Las actividades transparentes heredan sus restricciones de la actividad opaca superior que se encuentra debajo de ellas en la pila de actividades de una tarea. La actividad opaca debe estar disponible durante todo el ciclo de vida de la actividad transparente, desde la creación de la actividad hasta la destrucción. Por este motivo, no inicies solicitudes de permisos desde actividades de trampolín.
Si una actividad de trampolín inicia una solicitud de permiso, es posible que el usuario no pueda ver el diálogo de permiso porque la actividad de trampolín se habrá destruido antes de que el usuario haya tenido la oportunidad de responder el diálogo, y es posible que las dimensiones y la posición de la actividad de diálogo se hayan calculado de forma incorrecta.
Las apps siempre deben iniciar solicitudes de permisos desde actividades que permanecen visibles hasta que el usuario toma una decisión respecto del permiso.
Esquinas redondeadas
Una actividad puede ser transparente debido a un estilo que especifica la transparencia del fondo o porque el contenido de la actividad no ocupa el espacio de visualización disponible. Si una actividad transparente llena el espacio de visualización disponible, el sistema aplica automáticamente esquinas redondeadas a la actividad si el fabricante del dispositivo lo configuró de esa manera. Sin embargo, si una actividad transparente (como un diálogo de permiso) no ocupa el espacio disponible, tú decides si aplicar esquinas redondeadas.
Los diálogos de permiso no ocupan el espacio de visualización disponible porque el diseño del diálogo generalmente usa LayoutParams.WRAP_CONTENT en lugar de LayoutParams.MATCH_PARENT.
Diálogo con esquinas redondeadas que se posiciona correctamente sobre la actividad de inicio visible.
Solución al problema de compatibilidad
Mantener visibles las actividades que inician actividades de diálogo hasta que el usuario haya respondido el diálogo.
El sistema garantiza que una actividad transparente herede todas las restricciones de la primera actividad opaca debajo de la transparente en la pila, incluidas las restricciones relacionadas con lo siguiente:
- Modo de compatibilidad de tamaño
- Orientación
- Relación de aspecto
Juegos de Unity
Los juegos de Unity se ejecutan en modo multiventana o en pantalla completa en Android. Sin embargo, muchos juegos de Unity pierden el enfoque y dejan de dibujar contenido cuando la app se coloca en el modo multiventana.
Problema
Unity agregó una opción Resizable Window
en Unity 2019.4 para admitir el modo multiventana en Android. Sin embargo, la implementación inicial no reaccionó de forma correcta al ciclo de vida de la actividad en el modo multiventana, lo que provocó que UnityPlayer suspendiera la reproducción cuando la app perdía el enfoque. El reproductor renderizó una pantalla negra o el último fotograma congelado del juego. El juego solo se reanudó cuando el usuario presionó la pantalla. Muchas apps que usan el motor de Unity tienen este problema y se renderizan como una ventana negra en el modo multiventana.
El juego pierde el foco en el modo multiventana y se renderiza como una ventana negra
Optimización
Actualiza Unity a la versión 2019.4.40 o una posterior y vuelve a exportar el juego. Mantén marcada la opción Resizable Window
en la configuración del reproductor de Android; de lo contrario, el juego se detendrá cuando no esté en primer plano, incluso si está completamente visible en el modo multiventana.
El juego procesa el contenido correctamente en el modo multiventana, incluso cuando no está en foco.
Solución al problema de compatibilidad
Los fabricantes de dispositivos pueden aplicar la anulación por app OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS
para proporcionar un evento de enfoque falso a una app en el modo multiventana. La anulación permite que la actividad vuelva a dibujar el contenido y no se oscurezca.
Modo de ventanas de escritorio
Cuando las apps se ejecutan en un entorno de ventanas de escritorio, es posible que se encuentren con modos de compatibilidad adicionales.
Las apps con orientación bloqueada se pueden cambiar de tamaño libremente. Incluso si una actividad está bloqueada en orientación vertical, los usuarios pueden cambiar el tamaño de la app a orientación horizontal.
Las apps con orientación bloqueada se pueden redimensionar libremente.
Sin embargo, si una actividad se declara como no redimensionable (resizeableActivity = false), la IU de la actividad se ajusta manteniendo la misma relación de aspecto.
La IU de las actividades declaradas como no redimensionables se ajusta.
Vista previa de la cámara en ventanas de escritorio
Cuando las apps en ventanas de escritorio inician una vista previa de la cámara, la IU del visor se ajusta, pero se mantiene la relación de aspecto original. El resto de la ventana de la app se puede redimensionar libremente.
Cómo cambiar el tamaño de una ventana con un visor de cámara
Prueba tu app para detectar problemas de compatibilidad
Para probar tu app y entender cómo se comporta en diferentes factores de forma, aprovecha los siguientes recursos:
- Transmisión de dispositivos: Para probar tu app en dispositivos de producción (incluidos los dispositivos de referencia) alojados en centros de datos de Google, consulta Transmisión de dispositivos Android con tecnología de Firebase .
- Emuladores en Android Studio: Si deseas obtener información para crear emuladores para dispositivos de referencia, consulta Cómo crear y administrar dispositivos virtuales.
- Emulador de Android Studio con cambio de tamaño: Si quieres obtener información para acceder a dispositivos virtuales, consulta Cómo ejecutar apps en Android Emulator.
Formato letterbox
Verifica que cada actividad pueda usar todo el espacio de visualización disponible para la app. Primero, declara el siguiente código en tu carpeta de prueba:
Kotlin
fun isLetterboxed(activity: AppCompatActivity): Boolean { if (isInMultiWindowMode) return false val wmc = WindowMetricsCalculator.getOrCreate() val currentBounds = wmc.computeCurrentWindowMetrics(this).bounds val maxBounds = wmc.computeMaximumWindowMetrics(this).bounds val isScreenPortrait = maxBounds.height() > maxBounds.width() return if (isScreenPortrait) { currentBounds.height() < maxBounds.height() } else { currentBounds.width() < maxBounds.width() } }
Java
public boolean isLetterboxed(AppCompatActivity activity) { if (activity.isInMultiWindowMode()) { return false; } WindowMetricsCalculator wmc = WindowMetricsCalculator.getOrCreate(); Rect currentBounds = wmc.computeCurrentWindowMetrics(activity).getBounds(); Rect maxBounds = wmc.computeMaximumWindowMetrics(activity).getBounds(); boolean isScreenPortrait = maxBounds.height() > maxBounds.width(); return (isScreenPortrait) ? currentBounds.height() < maxBounds.height() : currentBounds.width() < maxBounds.width(); }
Luego, ejecuta una prueba para confirmar el comportamiento y asegurarte de que la actividad objetivo no esté en formato letterbox:
Kotlin
@get:Rule val activityRule = ActivityScenarioRule(MainActivity::class.java) @Test fun activity_launched_notLetterBoxed() { activityRule.scenario.onActivity { assertFalse(it.isLetterboxed()) } }
Java
@Rule public ActivityScenarioRule<MainActivity> rule = new ActivityScenarioRule<>(MainActivity.class); @Test public void activity_launched_notLetterBoxed() { try (ActivityScenario<MainActivity> scenario = ActivityScenario.launch(MainActivity.class)) { scenario.onActivity( activity -> { assertFalse(activity.isLetterboxed()); }); } }
Lo ideal es que ejecutes este tipo de prueba solo hasta que se complete y confirme que las actividades de tu app ocupan todo el espacio de visualización disponible para ella. Prueba tu app en todos los tipos de dispositivos para garantizar un comportamiento coherente.
Anulaciones por app
Android proporciona anulaciones que cambian el comportamiento configurado de las apps. Por ejemplo, la anulación FORCE_RESIZE_APP
le indica al sistema que omita el modo de compatibilidad de tamaño y cambie el tamaño de la app para que se ajuste a las dimensiones de la pantalla, incluso si se especificó resizeableActivity="false"
en el manifiesto de la app.
Los fabricantes de dispositivos aplican anulaciones a apps seleccionadas (o a todas las apps) en dispositivos con pantalla grande específicos. En Android 14 (nivel de API 34) y versiones posteriores, los usuarios pueden aplicar anulaciones a las apps a través de la configuración del dispositivo. En Android 16 (nivel de API 36) y versiones posteriores, los propietarios de dispositivos virtuales aplican anulaciones en dispositivos seleccionados que administran.
Anulaciones por app del usuario
En Android 14 y versiones posteriores, un menú de configuración permite a los usuarios cambiar la relación de aspecto de las apps. Los dispositivos con pantalla grande, como los dispositivos de referencia, implementan el menú.
El menú contiene una lista de todas las apps instaladas en el dispositivo. Los usuarios eligen una app y, luego, configuran la relación de aspecto de la app en 3:4, 1:1, pantalla completa o cualquier otro valor que haya configurado el fabricante del dispositivo. Los usuarios también pueden restablecer la relación de aspecto a la predeterminada de la app, que se especifica en el manifiesto de la app.
Las apps pueden rechazar la anulación de compatibilidad configurando las siguientes etiquetas PackageManager.Property
:
PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE
Para inhabilitar la anulación de compatibilidad con la relación de aspecto del usuario, agrega la propiedad al manifiesto de tu app y establece el valor en
false
:<application> <property android:name="android.window. PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE" android:value="false" /> </application>
Tu app se excluirá de la lista de apps en la configuración del dispositivo. Los usuarios no podrán anular la relación de aspecto de la app.
Establecer la propiedad en
true
no tiene ningún efecto.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE
Para inhabilitar la opción de pantalla completa de la anulación de la compatibilidad con la relación de aspecto del usuario, agrega la propiedad al manifiesto de tu app y establece el valor en
false
:<application> <property android:name="android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE" android:value="false" /> </application>
Se quitó la opción de pantalla completa de la lista de opciones de relación de aspecto en la configuración del dispositivo. Los usuarios no podrán aplicar la anulación de pantalla completa a tu app.
Establecer esta propiedad en
true
no tiene ningún efecto.
Optimiza tu app para todas las pantallas: No establezcas restricciones de relación de aspecto en tu app. Usa clases de tamaño de ventana para admitir diferentes diseños según la cantidad de espacio de pantalla disponible.
Anulaciones por app en el dispositivo
Los fabricantes de dispositivos y los propietarios de dispositivos virtuales (seleccionan apps privilegiadas y de confianza) aplican anulaciones por app en dispositivos específicos, incluidas tablets, plegables, dispositivos ChromeOS y pantallas de automóviles. Los dispositivos de referencia pueden aplicar algunas de las anulaciones a varias apps de forma predeterminada.
Las apps pueden inhabilitar la mayoría de las anulaciones (consulta la tabla Anulaciones por app que aparece más abajo).
Puedes probar la app con las anulaciones habilitadas o inhabilitadas usando el marco de compatibilidad (consulta Herramientas del marco de compatibilidad). Cuando se habilitan, las anulaciones se aplican a toda la app.
También puedes usar Android Debug Bridge (adb) para habilitar o inhabilitar anulaciones y determinar cuáles se aplican a tu app.
Habilita o inhabilita las anulaciones de la siguiente manera:
adb shell am compat enable/disable <override name/id> <package>
En el caso de los dispositivos de referencia, verifica qué anulaciones se aplican a tu app:
adb shell dumpsys platform_compat | grep <package name>
En la siguiente tabla, se detallan las anulaciones disponibles junto con la guía sobre cómo optimizar tu app para que no tenga que depender de las anulaciones. Puedes agregar marcas de propiedad al manifiesto de la app para inhabilitar algunas anulaciones.
Anulaciones por app | |||
---|---|---|---|
Tipo | Nombre | ID | Descripción |
Capacidad de cambio de tamaño | FORCE_RESIZE_APP | 174042936 | Omite el modo de compatibilidad de tamaño para la app en los cambios de configuración. |
FORCE_NON_RESIZE_APP | 181136395 | Fuerza el modo de compatibilidad de tamaño en la app en los cambios de configuración. | |
Relación de aspecto | OVERRIDE_MIN_ASPECT_RATIO | 174042980 | Anulación de control que debe estar habilitada para aplicar cualquier otra anulación de relación de aspecto. |
OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY | 203647190 | Si se habilita (configuración predeterminada), limita el alcance de la anulación a las actividades que solo usan el modo vertical. | |
OVERRIDE_MIN_ASPECT_RATIO_SMALL | 349045028 | Cambia la relación de aspecto mínima a 4:3. | |
OVERRIDE_MIN_ASPECT_RATIO_MEDIUM | 180326845 | Cambia la relación de aspecto mínima a 3:2. | |
OVERRIDE_MIN_ASPECT_RATIO_LARGE | 180326787 | Cambia la relación de aspecto mínima a 16:9. | |
OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN | 208648326 | Cambia la relación de aspecto mínima para que se adapte al 50% del tamaño de visualización (o la relación de aspecto de pantalla dividida). | |
OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN | 218959984 | Inhabilita la anulación de relación de aspecto mínima para que las apps se vean en pantalla completa cuando el dispositivo esté en modo vertical. | |
Orientación | OVERRIDE_ANY_ORIENTATION | 265464455 | Permite anular cualquier orientación. |
OVERRIDE_ANY_ORIENTATION_TO_USER | 310816437 | Anula las restricciones de orientación, cambio de tamaño y relación de aspecto. | |
OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT | 265452344 | Anula la orientación para que sea vertical cuando una actividad tiene una orientación no definida. | |
OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR | 265451093 | Anula la orientación para que sea nosensor (usa la orientación natural del dispositivo) cuando una actividad tiene una orientación no definida. |
|
OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE | 266124927 | Gira 180 grados las apps que solo tienen modo horizontal. | |
OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA | 265456536 | Limita el alcance de la anulación de orientación cuando la app está conectada a la cámara. | |
OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION | 255940284 | Fija la pantalla en orientación natural horizontal cuando una tarea está en pantalla completa (incluso en formato letterbox). | |
OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION | 254631730 | Ignora las solicitudes de orientación de la app para evitar los bucles infinitos de rotación. | |
OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED | 273509367 | Ignora las solicitudes de orientación repetidas mientras se reinicia una actividad. Si Android detecta que una app solicita al menos dos orientaciones nuevas en un segundo, el sistema considera que se trata de un bucle infinito de rotación y aplica la anulación. | |
OVERRIDE_RESPECT_REQUESTED_ORIENTATION | 236283604 | Impide el formato letterbox inhabilitando el parámetro de configuración para solicitar que se ignore la solicitud de orientación del fabricante del dispositivo. | |
APIs de Sandbox | NEVER_SANDBOX_DISPLAY_APIS | 184838306 | Impide el cambio del comportamiento de cualquier API de Display. |
ALWAYS_SANDBOX_DISPLAY_APIS | 185004937 | Fuerza las APIs de Display en la app para que se devuelvan los límites. Las APIs de Display devuelven límites lógicos del área de visualización, pero, a veces, la app da por sentado que estas APIs devuelven los límites de la app, lo que genera problemas con la IU.Display |
|
OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS | 237531167 | Fuerza las APIs de View que se usan en la app para que se devuelvan los límites. Las APIs de View devuelven límites lógicos del área de visualización, pero, a veces, la app da por sentado que estas APIs devuelven los límites de la app, lo que genera problemas con la IU.View |
|
Compatibilidad con la cámara | OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION | 263959004 | Desactiva la rotación forzada. De forma predeterminada, todas las apps de cámara con orientación fija se giran de manera forzosa cuando la vista previa de la cámara está abierta. |
OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH | 264304459 | Quita la actualización forzada predeterminada que se aplica cuando se gira de manera forzosa la vista previa de una cámara. | |
OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE | 264301586 | Cambia la actualización forzada a una actualización desde la caché si la vista previa de una cámara se gira de manera forzosa, lo que ayuda a preservar el estado durante esta rotación. De forma predeterminada, Android aplica una actualización forzada cuando se gira la vista previa de la cámara de manera forzosa. La actualización forzosa puede causar problemas con las apps que pierden el estado o se oscurecen según la forma en que almacenaron en caché su estado anterior. | |
OVERRIDE_CAMERA_LANDSCAPE_TO_PORTRAIT | 250678880 | Recorta el búfer de imagen de la cámara frontal interior. Si se inhabilita la anulación, se quita el recorte de la cámara frontal interior y se aumenta el campo visual de la vista previa de la cámara. De forma predeterminada, en algunos dispositivos plegables (consulta los dispositivos de referencia), el sistema recorta la vista previa de todas las apps de cámara cuando se usa la cámara frontal interior. | |
Varios | OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS | 263259275 | Evita que se oscurezca la app cuando pierde el enfoque en el modo de pantalla dividida. La app espera el enfoque antes de dibujar el contenido, lo que puede hacer que se inmovilice o se oscurezca. La anulación permite que Android envíe un evento de enfoque falso a la app para indicarle que vuelva a dibujar contenido. |
FORCE_RESIZE_APP
Fuerza los paquetes a los que se aplica la anulación a que puedan cambiar de tamaño y entrar en el modo multiventana. Se aplica a todos los tamaños de pantalla.
Cómo las apps pueden obtener el mismo resultado que la anulación
En el manifiesto de la app, establece el atributo android:resizeableActivity
en true
.
Cómo optimizar apps
Usa diseños responsivos o adaptativos para permitir que las apps se adapten a todos los tamaños de visualización y las relaciones de aspecto. Consulta Cómo brindar compatibilidad con diferentes tamaños de pantalla.
Cómo inhabilitar o rechazar la anulación
Establece la marca de propiedad PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES
en false
.
Marcas de propiedad para ajustar la anulación
<property android:name="android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES"
android:value="true|false"/>
Comandos de adb para probar la anulación
Comando para aplicar la anulación y hacer que la app pueda cambiar de tamaño:
adb shell am compat enable FORCE_RESIZE_APP <package>
Comando para quitar la anulación:
adb shell am compat disable FORCE_RESIZE_APP <package>
Nota: Los comandos aplican o quitan la anulación solo de manera temporal.
FORCE_NON_RESIZE_APP
Fuerza los paquetes a los que se aplica la anulación a que no puedan cambiar de tamaño y entren al modo de compatibilidad de tamaño en los cambios de configuración. Se aplica a todos los tamaños de pantalla.
Cómo las apps pueden obtener el mismo resultado que la anulación
Establece el atributo android:resizeableActivity
y la marca de metadatos android.supports_size_changes
en false
en el manifiesto de la app y declara una restricción de orientación o de relación de aspecto.
Cómo optimizar apps
Todas las apps que funcionan bien si se les cambia el tamaño deben tener el valor de android:resizeableActivity
o android.supports_size_changes
establecido en true
.
Se deben mejorar otras apps para que funcionen bien cuando se les cambie el tamaño. Consulta android:resizeableActivity.
Cómo inhabilitar o rechazar la anulación
Establece la marca de propiedad PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES
en false
.
Marcas de propiedad para ajustar la anulación
<property android:name="android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES"
android:value="true|false"/>
Comandos de adb para probar la anulación
Comando para aplicar la anulación y hacer que la app no pueda cambiar de tamaño:
adb shell am compat enable FORCE_NON_RESIZE_APP <package>
Comando para quitar la anulación:
adb shell am compat disable FORCE_NON_RESIZE_APP <package>
Nota: Los comandos aplican o quitan la anulación solo de manera temporal.
OVERRIDE_MIN_ASPECT_RATIO
Es el controlador para todas las anulaciones que fuerzan una relación de aspecto mínima determinada.
Cómo las apps pueden obtener el mismo resultado que la anulación
Establece