Cambios de comportamiento: todas las apps

La plataforma de Android 12 incluye cambios de comportamiento que podrían afectar a tu app. Los siguientes cambios se aplican a todas las apps cuando se ejecutan en Android 12, independientemente de la targetSdkVersion. Debes probar tu app y, luego, modificarla según corresponda para admitir estos cambios.

Asegúrate también de revisar la lista de cambios de comportamiento que solo afectan a las apps orientadas a Android 12.

Experiencia del usuario

Efecto de desplazamiento lateral ampliado

En dispositivos que ejecutan Android 12 y versiones posteriores, cambia el comportamiento visual de los eventos de sobredesplazamiento.

En Android 11 y versiones anteriores, un evento de sobredesplazamiento causa que los elementos visuales brillen. En Android 12 y versiones posteriores, los elementos visuales se estiran y rebotan en un evento de arrastre, y se deslizan y rebotan en un evento de deslizamiento:

Para obtener más información, consulta la guía sobre cómo animar los gestos de desplazamiento.

Pantallas de presentación de la app

Si ya implementaste una pantalla de presentación personalizada en Android 11 o versiones anteriores, deberás migrar tu app a la API de SplashScreen para asegurarte de que se muestre correctamente a partir de Android 12. Si no la migras, la experiencia de lanzamiento de la app se verá degradada o será no deseada.

Para obtener instrucciones, consulta Cómo migrar la implementación existente de la pantalla de presentación a Android 12.

Además, a partir de Android 12, el sistema siempre aplica la nueva pantalla de presentación predeterminada del sistema Android en inicios semicalientes y fríos para todas las apps. Esta pantalla de presentación predeterminada del sistema se construye con el elemento del ícono de selector de la app y el objeto windowBackground del tema (si se trata de un solo color).

Para obtener más detalles, consulta la guía para desarrolladores sobre pantallas de presentación.

Resolución de intents web

A partir de Android 12 (nivel de API 31), un intent web genérico se resuelve en una actividad de la app solo si esta se aprobó para el dominio específico que se incluye en ese intent web. Si no se aprueba la app para el dominio, el intent web se resuelve en la app predeterminada del navegador del usuario.

Para que las apps obtengan esta aprobación, pueden hacer lo siguiente:

Si la app invoca intents web, procura agregar un mensaje o un diálogo que le solicite al usuario que confirme la acción.

Mejoras en el modo envolvente para la navegación por gestos

Android 12 consolida el comportamiento existente para facilitar que los usuarios realicen comandos de navegación por gestos en el modo envolvente. Además, brinda comportamiento de retrocompatibilidad para el modo envolvente fijo.

Display#getRealSize y getRealMetrics: baja y restricciones

Los dispositivos Android están disponibles en muchos factores de forma diferentes, como pantallas grandes, tablets y dispositivos plegables. A fin de procesar el contenido de manera correcta para cada dispositivo, la app debe determinar el tamaño de pantalla o visualización. Con el paso del tiempo, Android brindó diferentes API para recuperar esta información. En Android 11, introdujimos la API de WindowMetrics y dimos de baja estos métodos:

En Android 12, continuamos recomendándote que uses la clase WindowMetrics y dimos de baja estos métodos:

A fin de mitigar el comportamiento de las aplicaciones que usan las API de Display para recuperar los límites de la aplicación, en Android 12, se limitan los valores que muestran las API en las apps que no pueden cambiar de tamaño por completo. Este mecanismo podría afectar a las apps que usan esta información con MediaProjection.

Las apps deben usar las API de WindowMetrics para consultar los límites de su ventana y Configuration.densityDpi a fin de consultar la densidad actual.

Para obtener una compatibilidad más amplia con versiones anteriores de Android, puedes usar la biblioteca de WindowManager de Jetpack, que incluye una clase WindowMetrics compatible con Android 4.0 (nivel de API 14) y versiones posteriores.

Ejemplos de cómo usar WindowMetrics

Primero, asegúrate de que se pueda cambiar por completo el tamaño de las actividades de la app.

Una actividad debe depender de WindowMetrics desde un contexto de actividad para cualquier trabajo relacionado con la IU, especialmente WindowManager.getCurrentWindowMetrics() o WindowMetricsCalculator.computeCurrentWindowMetrics() de Jetpack.

Si tu app crea un elemento MediaProjection, los límites deben tener el tamaño correcto desde que la proyección captura la partición de pantalla en la que se ejecuta la app de proyector.

Si se puede cambiar por completo el tamaño de la app, el contexto de la actividad mostrará los límites correctos de la siguiente manera:

Kotlin

val projectionMetrics: WindowMetrics = activityContext
      .getSystemService(WindowManager::class.java).maximumWindowMetrics

Java

WindowMetrics projectionMetrics = activityContext
      .getSystemService(WindowManager.class).getMaximumWindowMetrics();

Si no se puede cambiar el tamaño de la app por completo, debe realizar una consulta desde una instancia de WindowContext y recuperar las WindowMetrics de los límites de la actividad mediante WindowManager.getMaximumWindowMetrics() o el método WindowMetricsCalculator.computeMaximumWindowMetrics() de Jetpack.

Kotlin

val windowContext = context.createWindowContext(mContext.display!!,
      WindowManager.LayoutParams.TYPE_APPLICATION, null)
val projectionMetrics = windowContext.getSystemService(WindowManager::class.java)
      .maximumWindowMetrics

Java

Context windowContext = context.createWindowContext(mContext.getDisplay(),
      WindowManager.LayoutParams.TYPE_APPLICATION, null);
WindowMetrics projectionMetrics = windowContext.getSystemService(WindowManager.class)
      .getMaximumWindowMetrics();

Todas las apps en el modo multiventana

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 y minHeight de una actividad para determinar si esta puede ejecutarse en el modo multiventana. Si se establece resizeableActivity="false", se evita que la app se ejecute en el modo multiventana, independientemente del ancho y de la altura mínimos.

Para obtener más información, consulta Compatibilidad con el modo multiventana.

Vista previa de la cámara en pantallas grandes

Por lo general, las apps de cámara suponen una relación fija entre la orientación del dispositivo y la relación de aspecto de la vista previa de la cámara. Sin embargo, los factores de forma de pantalla grande, como los dispositivos plegables, y los modos de pantalla, como multiventana y pantallas múltiples, desafían esa suposición.

En Android 12, las apps de cámara que solicitan una orientación de pantalla específica y no pueden cambiar de tamaño (resizeableActivity="false") ingresan automáticamente al modo de retrato en pantalla, lo que garantiza la orientación y la relación de aspecto adecuadas de la vista previa de la cámara. En dispositivos plegables y otros dispositivos que tengan una capa de abstracción de hardware de la cámara (HAL), se aplica una rotación adicional a la salida de la cámara para compensar la orientación del sensor, y la cámara se recorta para coincidir con la relación de aspecto de la vista previa de la cámara de la app. El recorte y la rotación adicional garantizan la presentación adecuada de la vista previa de la cámara, independientemente de la orientación del dispositivo y el estado plegado o desplegado del dispositivo.

Retraso de la UX en las notificaciones de servicios en primer plano

A fin de proporcionar una experiencia optimizada para los servicios en primer plano de ejecución breve, los dispositivos que ejecutan Android 12 o versiones posteriores pueden retrasar la visualización de las notificaciones de servicio en primer plano por 10 segundos, con algunas excepciones. Este cambio permite que se completen las tareas de corta duración antes de que aparezcan sus notificaciones.

Rendimiento

Intervalo restringido de App Standby

Android 11 (nivel de API 30) introdujo el intervalo restringido como un intervalo de App Standby. A partir de Android 12, este intervalo está activo de forma predeterminada. El intervalo restringido tiene la prioridad más baja (y las restricciones más altas) de todos los intervalos. A continuación, se ordenan los intervalos de prioridad alta a baja:

  1. Activo: La app está en uso o se usó muy recientemente.
  2. Conjunto de tareas: Se está haciendo un uso habitual de la app.
  3. Frecuente: Se usa con frecuencia la app, pero no todos los días.
  4. Poco frecuente: No se usa con frecuencia la app.
  5. Restringido: La app consume una gran cantidad de recursos del sistema o puede mostrar un comportamiento no deseado.

El sistema tiene en cuenta el comportamiento de la app, además de los patrones de uso, para decidir si debe ubicarla en el intervalo restringido.

Es menos probable que se coloque la app en este tipo de intervalo si esta usa recursos del sistema de manera más responsable. Además, el sistema coloca la app en un intervalo menos restringido si el usuario interactúa directamente con esta.

Cómo verificar si la app se encuentra en el intervalo restringido

Para comprobar si el sistema colocó la app en el intervalo restringido, llama a getAppStandbyBucket(). Si el valor que se muestra de este método es STANDBY_BUCKET_RESTRICTED, la app se encuentra en este tipo de intervalo.

Cómo probar el comportamiento del intervalo restringido

Para probar cómo se comporta la app cuando el sistema la coloca en el intervalo restringido, puedes moverla manualmente a ese intervalo. Para ello, ejecuta el siguiente comando en una ventana de terminal:

adb shell am set-standby-bucket PACKAGE_NAME restricted

Seguridad y privacidad

Ubicación aproximada

El diálogo tiene dos conjuntos de opciones: uno encima del otro
Figura 1: Diálogo de permisos del sistema que permite al usuario otorgar información de ubicación aproximada

En los dispositivos que ejecutan Android 12 o versiones posteriores, los usuarios pueden solicitar que tu app tenga acceso solo a información de ubicación aproximada.

.

Si tu app solicita el permiso de tiempo de ejecución ACCESS_FINE_LOCATION, también debes solicitar el permiso ACCESS_COARSE_LOCATION para controlar el caso en el que el usuario otorga el acceso a la ubicación aproximada a tu app. Debes incluir ambos permisos en una solicitud de tiempo de ejecución única.

El diálogo de permisos del sistema incluye las siguientes opciones para el usuario, como se muestra en la Figura 1.

  • Precisa: Brinda acceso a la información sobre la ubicación precisa.
  • Aproximada: Brinda acceso solo a la información sobre la ubicación aproximada.

Botones de activación del micrófono y de la cámara

En los dispositivos compatibles que ejecutan Android 12 o versiones posteriores, los usuarios pueden habilitar o inhabilitar el acceso a la cámara y al micrófono para todas las apps del dispositivo presionando una sola opción de activación. Los usuarios pueden acceder a opciones que se pueden activar o desactivar desde Configuración rápida, como se muestra en la Figura 1, o desde la pantalla de privacidad en la configuración del sistema.

Obtén más información sobre estos botones de activación y descubre cómo verificar que tu app siga las prácticas recomendadas para los permisos CAMERA y RECORD_AUDIO.

Indicadores de acceso al micrófono y a la cámara

En dispositivos que ejecutan Android 12 y versiones posteriores, cuando una app accede al micrófono o a la cámara, aparece un ícono en la barra de estado.

Obtén más información sobre estos indicadores y descubre cómo verificar que tu app cumpla con las prácticas recomendadas para los permisos CAMERA y RECORD_AUDIO.

Los azulejos de Configuración rápida se etiquetan como &quot;Acceso a la cámara&quot; y &quot;Acceso al micrófono&quot;.
Figura 2: Botones de activación del micrófono y de la cámara en Configuración rápida.
Rectángulo redondeado en la esquina superior derecha, que incluye el ícono de una cámara y de un micrófono
Figura 3: Indicadores de acceso al micrófono y a la cámara, que muestran el acceso reciente a los datos.

Visibilidad del paquete de permisos

En los dispositivos que ejecutan Android 12 o una versión posterior, las apps que se orientan a Android 11 (nivel de API 30) o versiones posteriores y que llaman a uno de los siguientes métodos reciben un conjunto filtrado de resultados, según la visibilidad del paquete de la app en otras aplicaciones:

Eliminación de la implementación de BouncyCastle

Android 12 quita muchas implementaciones de BouncyCastle de algoritmos criptográficos que anteriormente estaban obsoletos, incluidos todos los algoritmos AES. En cambio, el sistema usa las implementaciones de Conscrypt de esos algoritmos.

Este cambio afecta a la app si se cumple alguna de las siguientes condiciones:

  • La app usa tamaños de claves de 512 bits. Conscrypt no admite este tamaño. Si es necesario, actualiza la lógica criptográfica de la app para usar diferentes tamaños de claves.
  • La app usa tamaños de claves no válidos con KeyGenerator. La implementación de KeyGenerator de Conscrypt realiza una validación adicional de los parámetros clave, en comparación con BouncyCastle. Por ejemplo, Conscrypt no permite que la app genere una clave AES de 64 bits, ya que AES solo es compatible con claves de 128, 192 y 256 bits.

    Bouncy Castle permite generar claves de tamaños no válidos, pero luego falla si estas se usan con Cipher. Conscrypt falla antes.

  • Inicializa los algoritmos de cifrado en modo Galois/Counter (GCM) con un tamaño diferente a 12 bytes. La implementación de GcmParameterSpec de Conscrypt requiere una inicialización de 12 bytes, que NIST recomienda.

Notificaciones de acceso al portapapeles

En Android 12 y versiones posteriores, cuando una app llama a getPrimaryClip() para acceder a datos de clips desde una app diferente por primera vez, un aviso de aviso le notifica al usuario sobre el acceso de este portapapeles.

El texto dentro de este mensaje contiene el siguiente formato: APP pasted from your clipboard.

Información sobre el texto en la descripción del clip

En Android 12 y versiones posteriores, getPrimaryClipDescription() puede detectar los siguientes detalles:

Las apps no pueden cerrar los diálogos del sistema

Para mejorar el control del usuario cuando interactúa con apps y el sistema, la acción de intent ACTION_CLOSE_SYSTEM_DIALOGS deja de estar disponible a partir de Android 12. A excepción de algunos casos especiales, cuando tu app intenta invocar un intent que contiene esta acción, el sistema realiza una de las siguientes acciones según la versión del SDK de destino de la app:

  • Si la app se orienta a Android 12 o una versión posterior, se genera una SecurityException.
  • Si la app se orienta a Android 11 (nivel de API 30) o versiones anteriores, no se ejecuta el intent y aparece el siguiente mensaje en Logcat:

    E ActivityTaskManager Permission Denial: \
    android.intent.action.CLOSE_SYSTEM_DIALOGS broadcast from \
    com.package.name requires android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS, \
    dropping broadcast.
    

Excepciones

En los siguientes casos, una app puede cerrar diálogos del sistema en Android 12 o versiones posteriores:

  • La app ejecuta una prueba de instrumentación.
  • La app se orienta a Android 11 o versiones anteriores y muestra una ventana ubicada en el panel lateral de notificaciones.

  • La app se orienta a Android 11 o una versión anterior. Además, el usuario interactuó con una notificación, probablemente con los botones de acción de la notificación, y tu app procesa un servicio o receptor de emisión en respuesta a esa acción del usuario.

  • La app se orienta a Android 11 o versiones anteriores y tiene un servicio de accesibilidad activo. Si la app se orienta a Android 12 y desea cerrar la barra de notificaciones, usa la acción de accesibilidad GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE en su lugar.

Bloqueo de los eventos táctiles que no son de confianza

Con el objetivo de preservar la seguridad del sistema y una buena experiencia del usuario, Android 12 evita que las apps consuman eventos táctiles, en los que una superposición oculta la app de forma insegura. En otras palabras, el sistema bloquea los toques que pasan por determinadas ventanas, con algunas excepciones.

Apps afectadas

Este cambio afecta a las apps que permiten que los toques pasen por sus ventanas, por ejemplo, mediante la marca FLAG_NOT_TOUCHABLE. Entre los ejemplos, se incluyen los siguientes:

Excepciones

En los siguientes casos, se permiten los toques "de paso":

  • Interacciones dentro de tu app. La app muestra la superposición, y la superposición solo aparece cuando el usuario interactúa con la app.
  • Ventanas de confianza. Entre los ejemplos de estas ventanas, se incluyen los siguientes:

  • Ventanas invisibles. La vista raíz de la ventana es GONE o INVISIBLE.

  • Ventanas totalmente transparentes. La propiedad alpha es 0.0 para la ventana.

  • Ventanas de alerta de sistema lo suficientemente traslúcidas. El sistema considera que un conjunto de ventanas de alerta del sistema es lo suficientemente translúcido cuando la opacidad combinada es menor o igual que la opacidad máxima oculta del sistema para los toques. En Android 12, esta opacidad máxima es de 0.8 de forma predeterminada.

Detecta si se bloquea un toque no confiable

Si el sistema bloquea una acción táctil, Logcat registra el siguiente mensaje:

Untrusted touch due to occlusion by PACKAGE_NAME

Prueba el cambio

Los toques no confiables se bloquean de manera predeterminada en dispositivos que ejecutan Android 12 o versiones posteriores. Para permitir toques no confiables, ejecuta el siguiente comando de ADB en una ventana de terminal:

# A specific app
adb shell am compat disable BLOCK_UNTRUSTED_TOUCHES com.example.app

# All apps
# If you'd still like to see a Logcat message warning when a touch would be
# blocked, use 1 instead of 0.
adb shell settings put global block_untrusted_touches 0

Para revertir el comportamiento al valor predeterminado (en el que se bloquean los toques no confiables), ejecuta el siguiente comando:

# A specific app
adb shell am compat reset BLOCK_UNTRUSTED_TOUCHES com.example.app

# All apps
adb shell settings put global block_untrusted_touches 2

Ciclo de vida de la actividad

Las actividades del selector raíz ya no finalizan cuando se presiona Atrás.

Android 12 cambia el control predeterminado de las pulsaciones de actividades del selector del sistema que se encuentran en la raíz de sus tareas. En versiones anteriores, el sistema finalizaba esas actividades cuando se presionaba Atrás. En Android 12, el sistema ahora mueve la actividad y su tarea a segundo plano en lugar de finalizar la actividad. El nuevo comportamiento coincide con el actual cuando sales de una app con el gesto o botón de inicio.

Para la mayoría de las apps, este cambio significa que los usuarios que usan Atrás para navegar fuera de tu app pueden reanudar más rápido tu app desde un inicio semicaliente, en lugar de tener que reiniciarla por completo en un estado frío.

Te recomendamos que pruebes tus apps con este cambio. Si la app actualmente anula onBackPressed() para procesar la navegación hacia atrás y finalizar Activity, actualiza tu implementación para llamar a super.onBackPressed() en lugar de finalizarla. Llamar a super.onBackPressed() mueve la actividad y su tarea a segundo plano cuando corresponda, y proporciona una experiencia de navegación más coherente para los usuarios en todas las apps.

Además, ten en cuenta que, en general, recomendamos usar las API de actividad de AndroidX para proporcionar una navegación hacia atrás personalizada, en lugar de anular onBackPressed(). Las API de actividad de AndroidX difieren automáticamente al comportamiento adecuado del sistema si no hay componentes que intercepten la pulsación hacia Atrás del sistema.

Imágenes y gráficos

Mejora del cambio de frecuencia de actualización

En Android 12, los cambios de frecuencia de actualización mediante setFrameRate() pueden ocurrir independientemente de que la pantalla admita una transición fluida a la frecuencia de actualización nueva; una transición fluida es aquella en la que no se producen interrupciones visuales, como una pantalla negra durante uno o dos segundos. Anteriormente, si la pantalla no admitía una transición fluida, por lo general, continuaba usando la misma frecuencia de actualización después de llamar a setFrameRate(). Puedes llamar a getAlternativeRefreshRates() para determinar con anticipación si es probable que la transición a la actualización nueva se realice de manera fluida. Por lo general, se llama a la devolución de llamada onDisplayChanged() después de que se completa el cambio de frecuencia de actualización. Sin embargo, para algunas pantallas conectadas de forma externa, se llama durante una transición poco fluida.

Este es un ejemplo de cómo puedes implementarlo:

Kotlin

// Determine whether the transition will be seamless.
// Non-seamless transitions may cause a 1-2 second black screen.
val refreshRates = this.display?.mode?.alternativeRefreshRates
val willBeSeamless = Arrays.asList<FloatArray>(refreshRates).contains(newRefreshRate)

// Set the frame rate even if the transition will not be seamless.
surface.setFrameRate(newRefreshRate, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS)

Java

// Determine whether the transition will be seamless.
// Non-seamless transitions may cause a 1-2 second black screen.
Display display = context.getDisplay(); // API 30+
Display.Mode mode = display.getMode();
float[] refreshRates = mode.getAlternativeRefreshRates();
boolean willBeSeamless = Arrays.asList(refreshRates).contains(newRefreshRate);

// Set the frame rate even if the transition will not be seamless.
surface.setFrameRate(newRefreshRate, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS);

Conectividad

Actualizaciones de Passpoint

En Android 12, se agregaron las siguientes API:

  • isPasspointTermsAndConditionsSupported():Términos y condiciones es una función de Passpoint que permite que las implementaciones de redes reemplacen portales cautivos no seguros, que usan redes abiertas, por una red segura de Passpoint. Se le muestra una notificación al usuario cuando debe aceptar términos y condiciones. Las apps que sugieren redes de Passpoint que están restringidas por términos y condiciones deben llamar primero a esta API para asegurarse de que el dispositivo admita la función. Si el dispositivo no la admite, no podrá conectarse a esta red, y se sugerirá una red alternativa o heredada.
  • isDecoratedIdentitySupported(): Cuando te autenticas en redes extendidas con un prefijo, el prefijo con identidad extendido permite que los operadores de red actualicen el identificador de acceso a la red (NAI) para realizar el enrutamiento explícito a través de varios proxies dentro de una red AAA (consulta RFC 7542 para obtener más información al respecto).

    Android 12 implementa esta función a fin de cumplir con la especificación de WBA para extensiones PPS-MO. Las apps que sugieren redes de Passpoint que requieren una identidad extendida deben llamar primero a esta API para asegurarse de que el dispositivo admita la función. Si el dispositivo no la admite, la identidad no se extenderá, y es posible que falle la autenticación en la red.

Para crear una sugerencia de Passpoint, las apps deben usar las clases PasspointConfiguration, Credential y HomeSp. Estas clases describen el perfil de Passpoint, que se define en la especificación de Passpoint de Wi-Fi Alliance.

Para obtener más información, consulta la API de sugerencia de Wi-Fi para la conectividad a Internet.

Actualización de restricciones en interfaces que no pertenecen al SDK

Android 12 incluye listas actualizadas de este tipo de interfaces que están basadas en la colaboración con desarrolladores de Android y las pruebas internas más recientes. Siempre que sea posible, nos aseguramos de que las alternativas públicas estén disponibles antes de restringir las interfaces que no pertenecen al SDK.

Si tu app no está orientada a Android 12, es posible que algunos de estos cambios no te afecten de inmediato. Sin embargo, aunque actualmente puedes usar algunas interfaces que no pertenecen al SDK (según el nivel de API al que esté orientada la app), utilizar cualquier método o campo que no pertenezca al SDK siempre implica un gran riesgo de error para tu app.

En caso de no saber con certeza si tu app usa este tipo de interfaces, puedes probarla para verificarlo. Si tu app depende de interfaces que no pertenezcan al SDK, deberías planificar una migración hacia otras alternativas que sí lo hagan. Sin embargo, sabemos que algunas apps tienen casos prácticos válidos para usarlas. Si no encuentras una alternativa al uso de una interfaz que no pertenece al SDK para una función de tu app, deberías solicitar una nueva API pública.

Para obtener más información sobre los cambios implementados en esta versión de Android, consulta Actualizaciones a las restricciones de interfaces que no pertenecen al SDK en Android 12. Para obtener más información sobre interfaces que no pertenecen al SDK en general, consulta Restricciones en interfaces que no pertenecen al SDK.