Compatibilidad con decoraciones del sistema

A continuación, se incluyen las actualizaciones realizadas en estas áreas específicas de la pantalla:

Decoraciones del sistema

Android 10 agrega compatibilidad con la configuración de pantallas secundarias para mostrar 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 están habilitadas de forma opcional. La compatibilidad con un editor de método de entrada (IME) se puede configurar de forma independiente de otras decoraciones del sistema.

Usa DisplayWindowSettings#setShouldShowSystemDecorsLocked() para agregar compatibilidad con decoraciones del sistema en una pantalla específica o proporcionar 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. El disparo de este método con la intención de habilitar las decoraciones del sistema no agrega ventanas de decoración que faltaban anteriormente ni las quita si estaban presentes anteriormente. En la mayoría de los casos, el cambio de compatibilidad con las decoraciones del sistema se aplica 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 esta 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 la ventana de decoración del sistema solo para la barra de navegación, ya que esta barra es esencial para navegar entre actividades y apps. De forma predeterminada, la barra de navegación muestra las indicaciones visuales de Atrás y Página 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 complicada, ya que también contiene el panel de notificaciones, la configuración rápida y la pantalla de bloqueo. En Android 10, la barra de estado no es compatible con las pantallas secundarias. Por lo tanto, las notificaciones, la configuración y un protector de pantalla completo solo están disponibles en la pantalla principal.

La ventana del sistema Resumen/Recientes no es compatible con pantallas secundarias. En Android 10, AOSP solo muestra Recientes en la pantalla predeterminada y contiene actividades de todas las pantallas. Cuando se inicia desde Recents, 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 IU del sistema que escuche cuando se agreguen o quiten pantallas y presente el contenido apropiado.

Un componente de IU del sistema compatible con pantallas múltiples (MD) debe manejar los siguientes casos:

  • Cómo inicializar varias pantallas al inicio
  • Se agregó la pantalla durante el tiempo de ejecución
  • Se quitó la pantalla durante el tiempo de ejecución

Cuando la IU del sistema detecta la adición de una pantalla antes de WindowManager, se crea una condición de carrera. Esto se puede evitar implementando una devolución de llamada personalizada de WindowManager a la IU del sistema cuando se agrega una pantalla en lugar de suscribirse a eventos de DisplayManager.DisplayListener. Si deseas obtener una implementación de referencia, consulta CommandQueue.Callbacks#onDisplayReady para obtener compatibilidad con la barra de navegación y WallpaperManagerInternal#onDisplayReady para fondos de pantalla.

Además, Android 10 proporciona las siguientes actualizaciones:

  • La clase NavigationBarController controla todas las funciones específicas 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 actualiza 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 actividades de selector con el tipo WindowConfiguration#ACTIVITY_TYPE_HOME de forma predeterminada. Cada pantalla usa una instancia independiente de la actividad del selector.

Figura 1: Ejemplo de selector de varias pantallas 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 diferente de experiencia en las pantallas secundarias o externas. Para proporcionar una actividad dedicada a las pantallas secundarias, Android 10 presenta 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 el uso de múltiples instancias y que pueda adaptarse 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 que una app maliciosa cree una pantalla virtual con decoraciones del sistema habilitadas y lea información sensible del usuario desde la plataforma, el selector solo aparece en pantallas virtuales que son propiedad del sistema. El selector no muestra contenido en pantallas virtuales que no sean del sistema.

Fondos de pantalla

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

Figura 2: Fondo animado en pantallas internas (arriba) y externas (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 los 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 manera independiente, con diferentes velocidades de fotogramas, respetando VSYNC.

Cómo seleccionar fondos de pantalla para pantallas individuales

Android 10 no proporciona compatibilidad directa con la plataforma para seleccionar fondos de pantalla para pantallas individuales. Para ello, 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 del reinicio.

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 para Android 10. La solución sugerida:

  1. Usa la API de WallpaperManager para configurar los fondos de pantalla.
  2. 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.
  3. En el lado del framework, usa displayId obtenido de un objeto Context y asócialo 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 selectores de fondo de pantalla. Si se abrió en una pantalla específica y usa el contexto correcto, cuando se llama para establecer un fondo de pantalla, el sistema puede identificar automáticamente la pantalla.

Si es necesario establecer un fondo de pantalla para una pantalla que no sea la actual, crea un nuevo objeto Context 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 sean de su propiedad. Esto se debe a un problema de seguridad que podría permitir que una app maliciosa cree una pantalla virtual con compatibilidad habilitada para decoraciones del sistema y lea 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, se crean controladores de fondo de pantalla para cada objeto DisplayContent durante la construcción, en lugar de un solo WallpaperController para todas las pantallas.

Algunas de las implementaciones públicas del método WallpaperManager (como WallpaperManager#getDesiredMinimumWidth()) se actualizaron para calcular y proporcionar información para las pantallas correspondientes. Se agregó 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 fondo 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 fondo de pantalla para pantallas secundarias