Compatibilidad con decoraciones del sistema

En esta página, se proporcionan las actualizaciones realizadas en estas áreas específicas de la pantalla.

Decoraciones del sistema

Android 10 agrega compatibilidad para configurar pantallas secundarias para que muestren ciertas decoraciones del sistema, como el fondo de pantalla, la barra de navegación y el selector. De forma predeterminada, la pantalla principal muestra todas las decoraciones del sistema, y las pantallas secundarias muestran las que se habilitan de forma opcional. Puedes configurar la compatibilidad con un editor de métodos de entrada (IME) por separado de otras decoraciones del sistema.

Usa DisplayWindowSettings#setShouldShowSystemDecorsLocked() para agregar compatibilidad con las decoraciones del sistema en una pantalla específica o proporciona un valor predeterminado en /data/system/display_settings.xml. Para ver ejemplos, consulta Configuración de la ventana de visualización.

Implementación

DisplayWindowSettings#setShouldShowSystemDecorsLocked() también se expone en WindowManager#setShouldShowSystemDecors() para realizar pruebas. Si se activa este método con la intención de habilitar las decoraciones del sistema, no se agregan las ventanas de decoración que faltaban anteriormente ni se quitan las que estaban presentes. En la mayoría de los casos, el cambio de compatibilidad con las decoraciones del sistema surte efecto por completo solo después de reiniciar el dispositivo.

Las verificaciones de compatibilidad con las decoraciones del sistema en la base de código de WindowManager suelen pasar por DisplayContent#supportsSystemDecorations(), mientras que las verificaciones de servicios externos (como la IU del sistema para verificar si se debe mostrar la barra de navegación) usan WindowManager#shouldShowSystemDecors(). Para comprender qué controla este parámetro de configuración, explora los puntos de llamada de estos métodos.

Ventanas de decoración de la IU del sistema

Android 10 agrega compatibilidad con ventanas de decoración del sistema solo para la barra de navegación, ya que esta es esencial para navegar entre actividades y apps. De forma predeterminada, la barra de navegación muestra las opciones Atrás y Principal. Esto solo se incluye si la pantalla de destino admite decoraciones del sistema (consulta DisplayWindowSettings).

La barra de estado es una ventana del sistema más compleja, ya que también contiene el panel de notificaciones, la configuración rápida y la pantalla de bloqueo. En Android 10, no se admite la barra de estado en pantallas secundarias. Por lo tanto, las notificaciones, la configuración y el protector de teclado completo solo están disponibles en la pantalla principal.

La ventana del sistema Visión general/Recientes no es compatible con pantallas secundarias. En Android 10, el AOSP solo muestra Recientes en la pantalla predeterminada y contiene actividades de todas las pantallas. Cuando se inicia desde Recientes, una actividad que estaba en una pantalla secundaria se muestra en primer plano en esa pantalla de forma predeterminada. Este enfoque tiene algunos problemas conocidos, como no actualizarse de inmediato cuando las apps aparecen en otras pantallas.

Implementación

Para implementar funciones adicionales de la IU del sistema, los fabricantes de dispositivos deben usar un solo componente de la IU del sistema que detecte la adición o eliminación de pantallas y presente el contenido adecuado.

Un componente de IU del sistema que admite la función de varias pantallas (MD) debe controlar los siguientes casos:

  • Inicialización de varias pantallas al inicio
  • Pantalla agregada en el tiempo de ejecución
  • La pantalla se quitó durante el tiempo de ejecución

Cuando la IU del sistema detecta la incorporación de una pantalla antes que WindowManager, se genera una condición de carrera. Para evitar esto, implementa una devolución de llamada personalizada de WindowManager a la IU del sistema cuando se agregue una pantalla en lugar de suscribirte a los eventos de DisplayManager.DisplayListener. Para ver una implementación de referencia, consulta CommandQueue.Callbacks#onDisplayAddSystemDecorations para obtener compatibilidad con la barra de navegación y WallpaperManagerInternal#onDisplayAddSystemDecorations para obtener fondos de pantalla.

Además, Android 10 proporciona las siguientes actualizaciones:

  • La clase NavigationBarController controla toda la funcionalidad específica de las barras de navegación.
  • Para ver una barra de navegación personalizada, consulta CarStatusBar.
  • TYPE_NAVIGATION_BAR ya no se limita a una sola instancia y se puede usar por pantalla.
  • IWindowManager#hasNavigationBar() se actualizó para incluir el parámetro displayId solo para la IU del sistema.

Selector

En Android 10, cada pantalla configurada para admitir decoraciones del sistema tiene una pila principal dedicada para las actividades del launcher con el tipo WindowConfiguration#ACTIVITY_TYPE_HOME de forma predeterminada. Cada pantalla usa una instancia separada de la actividad del selector:

Figura 1: Ejemplo de selector de pantallas múltiples para platform/development/samples/MultiDisplay.

La mayoría de los selectores existentes no admiten varias instancias y no están optimizados para tamaños de pantalla grandes. Además, a menudo se espera un tipo de experiencia diferente en las pantallas secundarias o externas. Para proporcionar una actividad dedicada para las pantallas secundarias, Android 10 introdujo la categoría SECONDARY_HOME en los filtros de intents. 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 se adapte a diferentes tamaños de pantalla. El modo de lanzamiento no puede ser singleInstance ni singleTask.

Implementación

En Android 10, RootActivityContainer#startHomeOnDisplay() selecciona automáticamente el componente y el intent deseados según la pantalla en la que se inicia la pantalla principal. RootActivityContainer#resolveSecondaryHomeActivity() contiene la lógica para buscar el componente de actividad del selector según el selector seleccionado actualmente y puede usar el valor predeterminado del sistema, si es necesario (consulta ActivityTaskManagerService#getSecondaryHomeIntent()).

Restricciones de seguridad

Además de las restricciones que se aplican a las actividades en pantallas secundarias, para evitar la posibilidad de que una app maliciosa cree una pantalla virtual con decoraciones del sistema habilitadas y lea información sensible del usuario desde la superficie, el selector solo aparece en las pantallas virtuales que son propiedad del sistema. El selector no muestra contenido en pantallas virtuales que no son del sistema.

Fondos de pantalla

En Android 10 y versiones posteriores, los fondos de pantalla son compatibles con pantallas secundarias:

Figura 2: Fondo animado en las pantallas interna (arriba) y externa (abajo).

Los desarrolladores pueden declarar la compatibilidad con la función de fondo de pantalla proporcionando android:supportsMultipleDisplays="true" en la definición XML de WallpaperInfo. También se espera que los desarrolladores de fondos de pantalla carguen recursos usando el contexto de visualización en WallpaperService.Engine#getDisplayContext().

El framework crea una instancia de WallpaperService.Engine por pantalla, por lo que cada motor tiene su propia superficie y contexto de visualización. El desarrollador debe asegurarse de que cada motor pueda dibujar de forma independiente, con diferentes velocidades de fotogramas y respetando la sincronización vertical.

Selecciona fondos de pantalla para pantallas individuales

Android 10 no proporciona asistencia directa de la plataforma para seleccionar fondos de pantalla para pantallas individuales. Para lograr esto, se necesita un identificador de pantalla estable para conservar la configuración del fondo de pantalla por pantalla. Display#getDisplayId() es dinámico, por lo que no hay garantía de que una pantalla física tenga el mismo ID después de reiniciar.

Sin embargo, Android 10 agregó DisplayInfo.mAddress, que contiene identificadores estables para pantallas físicas y se puede usar para una implementación completa en el futuro. Lamentablemente, ya es demasiado tarde para implementar la lógica de Android 10. La solución sugerida es la siguiente:

  1. Usa la clase WallpaperManager para establecer los fondos de pantalla.

    WallpaperManager se obtiene de un objeto Context, y cada objeto Context tiene información sobre la pantalla correspondiente (Context#getDisplay()/getDisplayId()). Por lo tanto, puedes obtener displayId de una instancia de WallpaperManager sin agregar métodos nuevos.

  2. En el framework, usa displayId obtenido de un objeto Context y asígnalo a un identificador estático (como un puerto de una pantalla física). Usa el identificador estático para conservar el fondo de pantalla elegido.

Esta solución alternativa usa implementaciones existentes para los selectores de fondos de pantalla. Si se abrió en una pantalla específica y usa el contexto correcto, cuando llame para establecer un fondo de pantalla, el sistema podrá identificar automáticamente la pantalla.

Si es necesario establecer un fondo de pantalla para una pantalla que no sea la actual, crea un objeto Context nuevo para la pantalla de destino (Context#createDisplayContext) y obtén la instancia WallpaperManager de esa pantalla.

Restricciones de seguridad

El sistema no mostrará fondos de pantalla en pantallas virtuales que no le pertenezcan. Esto se debe a un problema de seguridad que podría ocurrir si una app maliciosa crea una pantalla virtual con compatibilidad habilitada para las decoraciones del sistema y lee información sensible del usuario desde la superficie (como una foto personal).

Implementación

En Android 10, las interfaces IWallpaperConnection#attachEngine() y IWallpaperService#attach() aceptan el parámetro displayId para crear conexiones por pantalla. WallpaperManagerService.DisplayConnector encapsula un motor y una conexión de fondo de pantalla por pantalla. En WindowManager, los controladores de fondos de pantalla se crean para cada objeto DisplayContent en la construcción en lugar de un solo WallpaperController para todas las pantallas.

Se actualizaron algunas de las implementaciones del método público WallpaperManager (como WallpaperManager#getDesiredMinimumWidth()) para calcular y proporcionar información para las pantallas correspondientes. Se agregaron WallpaperInfo#supportsMultipleDisplays() y un atributo de recurso correspondiente para que los desarrolladores de apps puedan informar qué fondos de pantalla están listos para varias pantallas.

Si el servicio de fondos de pantalla que se muestra en la pantalla predeterminada no admite varias pantallas, el sistema mostrará el fondo de pantalla predeterminado en las pantallas secundarias:

Figura 3: Lógica de resguardo de fondos de pantalla para pantallas secundarias.