Soporte de decoraciones del sistema

Las actualizaciones realizadas en estas áreas específicas de la pantalla se proporcionan a continuación:

Decoraciones del sistema

Android 10 agrega soporte para configurar pantallas secundarias para mostrar ciertas decoraciones del sistema, como fondo de pantalla, barra de navegación y iniciador. De forma predeterminada, la pantalla principal muestra todas las decoraciones del sistema y las pantallas secundarias muestran las habilitadas opcionalmente. La compatibilidad con un editor de métodos de entrada (IME) se puede configurar por separado de otras decoraciones del sistema.

Utilice DisplayWindowSettings#setShouldShowSystemDecorsLocked() para agregar soporte para decoraciones del sistema en una pantalla específica o proporcionar un valor predeterminado en /data/system/display_settings.xml . Para ver ejemplos, consulte Configuración de la ventana de visualización .

Implementación

DisplayWindowSettings#setShouldShowSystemDecorsLocked() también se expone en WindowManager#setShouldShowSystemDecors() para realizar pruebas. La activación 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 elimina si estaban presentes anteriormente. En la mayoría de los casos, el cambio de compatibilidad con las decoraciones del sistema entra en vigor por completo solo después de reiniciar el dispositivo.

Las comprobaciones de compatibilidad con decoraciones del sistema en el código base de WindowManager generalmente se realizan mediante DisplayContent#supportsSystemDecorations() mientras que las comprobaciones de servicios externos (como la interfaz de usuario del sistema para verificar si se debe mostrar la barra de navegación) usan WindowManager#shouldShowSystemDecors() . Para comprender qué controla esta configuración, explore los puntos de llamada de estos métodos.

Ventanas de decoración de la interfaz de usuario del sistema

Android 10 agrega compatibilidad con la ventana de decoración del sistema solo para la barra de navegación, porque la barra de navegación es esencial para navegar entre actividades y aplicaciones. De forma predeterminada, la barra de navegación muestra las posibilidades de Atrás y Inicio. Esto se incluye solo si la pantalla de destino admite decoraciones del sistema (consulte DisplayWindowSettings ).

La barra de estado es una ventana del sistema más complicada porque también contiene Pantalla de notificación, Configuración rápida y Pantalla de bloqueo. En Android 10, la barra de estado no es compatible con pantallas secundarias. Por lo tanto, las notificaciones, las configuraciones y un bloqueo de teclado completo están disponibles solo en la pantalla principal.

La ventana del sistema Descripción general/Recientes no se admite en pantallas secundarias. En Android 10, 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 pasa al frente en esa pantalla, de forma predeterminada. Este enfoque tiene algunos problemas conocidos, como no actualizarse inmediatamente cuando aparecen aplicaciones en otras pantallas.

Implementación

Para implementar funciones adicionales de la interfaz de usuario del sistema, los fabricantes de dispositivos deben utilizar un único componente de la interfaz de usuario del sistema que escuche la adición o eliminación de pantallas y presente el contenido adecuado.

Un componente de la interfaz de usuario del sistema que admita múltiples pantallas (MD) debe manejar los siguientes casos:

  • Inicialización de múltiples pantallas al inicio
  • Pantalla agregada en tiempo de ejecución
  • Pantalla eliminada en tiempo de ejecución

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

Además, Android 10 proporciona estas actualizaciones:

  • La clase NavigationBarController controla todas las funciones específicas de las barras de navegación.
  • Para ver una barra de navegación personalizada, consulte CarStatusBar .
  • TYPE_NAVIGATION_BAR ya no está restringido a una sola instancia y se puede usar por pantalla.
  • IWindowManager#hasNavigationBar() se actualiza para incluir el parámetro displayId solo para la interfaz de usuario del sistema.

Lanzacohetes

En Android 10, cada pantalla configurada para admitir decoraciones del sistema tiene una pila de inicio dedicada para las actividades del iniciador con el tipo WindowConfiguration#ACTIVITY_TYPE_HOME , de forma predeterminada. Cada pantalla utiliza una instancia separada de actividad del iniciador.

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

La mayoría de los lanzadores existentes no admiten múltiples instancias y no están optimizados para pantallas de gran tamaño. Además, a menudo se espera un tipo diferente de experiencia en pantallas secundarias/externas. Para proporcionar una actividad dedicada para pantallas secundarias, Android 10 introduce la categoría SECONDARY_HOME en los filtros de intención. Se utilizan instancias de esta actividad en todas las pantallas que admiten decoraciones del sistema, una por 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 se espera que se adapte a diferentes tamaños de pantalla. El modo de inicio no puede ser singleInstance o singleTask .

Implementación

En Android 10, RootActivityContainer#startHomeOnDisplay() selecciona automáticamente el componente y la intención deseados según la pantalla donde se inicia la pantalla de inicio. RootActivityContainer#resolveSecondaryHomeActivity() contiene la lógica para buscar el componente de actividad del iniciador según el iniciador seleccionado actualmente y puede usar el valor predeterminado del sistema, si es necesario (consulte 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 aplicación maliciosa cree una pantalla virtual con decoraciones del sistema habilitadas y lea información confidencial del usuario desde la superficie, el iniciador aparece solo en pantallas virtuales propiedad del sistema. El iniciador no muestra contenido en pantallas virtuales que no pertenecen al sistema.

Fondos de pantalla

En Android 10 (y versiones posteriores), los fondos de pantalla se admiten en pantallas secundarias:

Figura 2. Fondo de pantalla en vivo en pantallas internas (arriba) y externas (abajo)

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

El marco crea una instancia 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, a diferentes velocidades de fotogramas, respetando VSYNC.

Seleccionar fondos de pantalla para pantallas individuales

Android 10 no proporciona soporte directo de 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 del reinicio.

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

  1. Utilice la API WallpaperManager para configurar los fondos de pantalla.
  2. WallpaperManager se obtiene de un objeto Context , y cada objeto Context tiene información sobre la visualización correspondiente ( Context#getDisplay()/getDisplayId() ). Por lo tanto, puede obtener displayId desde una instancia WallpaperManager sin agregar nuevos métodos.
  3. En el lado del marco, use displayId obtenido de un objeto Context y asígnelo a un identificador estático (como un puerto de una pantalla física). Utilice el identificador estático para conservar el fondo de pantalla elegido.

Esta solución utiliza implementaciones existentes para recolectores de papel tapiz. Si se abrió en una pantalla específica y usa el contexto correcto, cuando solicite configurar un fondo de pantalla, el sistema puede identificar automáticamente la pantalla.

Si es necesario configurar un fondo de pantalla para una pantalla distinta a la pantalla actual, cree un nuevo objeto Context para la pantalla de destino ( Context#createDisplayContext ) y obtenga 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 de que una aplicación maliciosa podría crear una pantalla virtual con soporte de decoración del sistema habilitado y leer información confidencial del usuario desde la superficie (como una foto personal).

Implementación

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

Algunas de las implementaciones del método público WallpaperManager (como WallpaperManager#getDesiredMinimumWidth() ) se actualizaron 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 aplicaciones puedan informar qué fondos de pantalla están listos para múltiples pantallas.

Si el servicio de fondo de pantalla que se muestra en la pantalla predeterminada no admite varias pantallas, entonces el sistema muestra el fondo de pantalla predeterminado en las pantallas secundarias.

Figura 3. Lógica de respaldo del fondo de pantalla para pantallas secundarias