Soporte de pantalla

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

Cambiar el tamaño de actividades y pantallas

Para indicar que es posible que una aplicación no admita el modo de ventanas múltiples o el cambio de tamaño, las actividades usan el atributo resizeableActivity=false . Los problemas comunes que encuentran las aplicaciones cuando se cambia el tamaño de las actividades incluyen:

  • Una actividad puede tener una configuración diferente a la de la aplicación u otro componente no visual. Un error común es leer las métricas de visualización del contexto de la aplicación. Los valores devueltos no se ajustarán a las métricas del área visible en las que se muestra una actividad.
  • Es posible que una actividad no maneje el cambio de tamaño y se bloquee, muestre una interfaz de usuario distorsionada o pierda el estado debido a un reinicio sin guardar el estado de la instancia.
  • Una aplicación puede intentar usar coordenadas de entrada absolutas (en lugar de las relativas a la posición de la ventana), lo que puede interrumpir la entrada en varias ventanas.

En Android 7 (y versiones posteriores), se puede configurar una aplicación resizeableActivity=false para que siempre se ejecute en modo de pantalla completa. En este caso, la plataforma evita que las actividades que no se pueden cambiar de tamaño pasen a pantalla dividida. Si el usuario intenta invocar una actividad de tamaño no variable desde el lanzador mientras ya está en modo de pantalla dividida, la plataforma sale del modo de pantalla dividida y lanza la actividad de tamaño no variable en modo de pantalla completa.

Las aplicaciones que establezcan explícitamente este atributo en false en el manifiesto no deben iniciarse en modo de ventanas múltiples, a menos que se aplique el modo de compatibilidad:

  • Se aplica la misma configuración al proceso, que contiene todas las actividades y los componentes que no son actividades.
  • La configuración aplicada cumple con los requisitos de CDD para pantallas compatibles con aplicaciones.

En Android 10, la plataforma aún evita que las actividades que no se pueden cambiar de tamaño pasen al modo de pantalla dividida, pero se pueden escalar temporalmente si la actividad ha declarado una orientación fija o una relación de aspecto. De lo contrario, la actividad cambia de tamaño para llenar toda la pantalla como en Android 9 y versiones anteriores.

La implementación predeterminada aplica la siguiente política:

Cuando una actividad se declara incompatible con las ventanas múltiples mediante el uso del atributo android:resizeableActivity y cuando esa actividad cumple una de las condiciones que se describen a continuación, cuando la configuración de la pantalla aplicada debe cambiar, la actividad y el proceso se guardan con la configuración original y el usuario tiene la posibilidad de relanzar el proceso de la aplicación para usar la configuración de pantalla actualizada.

  • Se fija la orientación a través de la aplicación de android:screenOrientation
  • La aplicación tiene una relación de aspecto máxima o mínima predeterminada al apuntar al nivel de API o declara la relación de aspecto explícitamente

Esta figura muestra una actividad de tamaño no variable con una relación de aspecto declarada. Al plegar el dispositivo, la ventana se reduce para adaptarse al área manteniendo la relación de aspecto utilizando el formato de pantalla ancha adecuado. Además, se proporciona al usuario una opción de actividad de reinicio cada vez que se cambia el área de visualización de la actividad.

Al desplegar el dispositivo, la configuración, el tamaño y la relación de aspecto de la actividad no cambian, pero se muestra la opción para reiniciar la actividad.

Cuando resizeableActivity no está configurado (o está configurado en true ), la aplicación es totalmente compatible con el cambio de tamaño.

Implementación

Una actividad de tamaño no variable con orientación fija o relación de aspecto se denomina modo de compatibilidad de tamaño (SCM) en el código. La condición se define en ActivityRecord#shouldUseSizeCompatMode() . Cuando se inicia una actividad de SCM, la configuración relacionada con la pantalla (como el tamaño o la densidad) se fija en la configuración de anulación solicitada, por lo que la actividad ya no depende de la configuración de visualización actual.

Si la actividad de SCM no puede ocupar toda la pantalla, se alinea en la parte superior y se centra horizontalmente. Los límites de la actividad los calcula AppWindowToken#calculateCompatBoundsTransformation() .

Cuando una actividad de SCM usa una configuración de pantalla diferente a la de su contenedor (por ejemplo, se cambia el tamaño de la pantalla o se mueve la actividad a otra pantalla), ActivityRecord#inSizeCompatMode() es verdadero y SizeCompatModeActivityController (en la interfaz de usuario del sistema) recibe la devolución de llamada para mostrar el proceso botón de reinicio

Tamaños de pantalla y relaciones de aspecto

Android 10 brinda soporte para nuevas relaciones de aspecto, desde altas proporciones de pantallas largas y delgadas hasta proporciones 1:1. Las aplicaciones pueden definir ApplicationInfo#maxAspectRatio y ApplicationInfo#minAspectRatio de la pantalla que pueden manejar.

proporciones de aplicaciones en Android 10

Figura 1. Proporciones de aplicaciones de ejemplo admitidas en Android 10

Las implementaciones de dispositivos pueden tener pantallas secundarias con tamaños y resoluciones más pequeños que los requeridos por Android 9 e inferiores (mínimo de 2,5 pulgadas de ancho o alto, mínimo de 320 DP para el ancho de pantalla smallestScreenWidth ), pero solo se pueden realizar actividades que opten por admitir estas pantallas pequeñas. colocado allí.

Las aplicaciones pueden optar por declarar un tamaño mínimo admitido que sea más pequeño que oe igual al tamaño de visualización de destino. Use los atributos de diseño de actividad android: android:minHeight y android:minWidth en AndroidManifest para hacerlo.

Políticas de visualización

Android 10 separa y mueve ciertas políticas de visualización de la implementación predeterminada de WindowManagerPolicy en PhoneWindowManager a clases por pantalla, como:

  • Mostrar estado y rotación
  • Algunas teclas y seguimiento de eventos de movimiento
  • Interfaz de usuario del sistema y ventanas decorativas

En Android 9 (y versiones anteriores), la clase PhoneWindowManager manejaba las políticas de visualización, el estado y la configuración, la rotación, el seguimiento del marco de la ventana decorativa y más. Android 10 traslada la mayor parte de esto a la clase DisplayPolicy , excepto el seguimiento de rotación, que se ha trasladado a DisplayRotation .

Configuración de la ventana de visualización

En Android 10, la configuración de ventana configurable por pantalla se ha ampliado para incluir:

  • Modo de ventana de visualización predeterminado
  • Valores de sobreexploración
  • Rotación de usuarios y modo de rotación
  • Tamaño forzado, densidad y modo de escala
  • Modo de eliminación de contenido (cuando se elimina la pantalla)
  • Soporte para decoraciones del sistema e IME

La clase DisplayWindowSettings contiene configuraciones para estas opciones. Se conservan en el disco en la partición /data en display_settings.xml cada vez que se cambia una configuración. Para obtener más información, consulte DisplayWindowSettings.AtomicFileStorage y DisplayWindowSettings#writeSettings() . Los fabricantes de dispositivos pueden proporcionar valores predeterminados en display_settings.xml para la configuración de su dispositivo. Sin embargo, debido a que el archivo se almacena en /data , es posible que se necesite lógica adicional para restaurar el archivo si se borra con un borrado.

De manera predeterminada, Android 10 usa DisplayInfo#uniqueId como identificador de una pantalla cuando se conserva la configuración. uniqueId debe completarse para todas las pantallas. Además, es estable para pantallas físicas y de red. También es posible usar el puerto de una pantalla física como identificador, que se puede configurar en DisplayWindowSettings#mIdentifier . En cada escritura, se escriben todas las configuraciones, por lo que es seguro actualizar la clave que se usa para una entrada de visualización en el almacenamiento. Para obtener más información, consulte Identificadores de visualización estáticos .

La configuración se conserva en el directorio /data por razones históricas. Originalmente, se usaban para conservar la configuración establecida por el usuario, como la rotación de la pantalla.

Identificadores de pantalla estática

Android 9 (y versiones anteriores) no proporcionó identificadores estables para pantallas en el marco. Cuando se agregó una pantalla al sistema, se generó Display#mDisplayId o DisplayInfo#displayId para esa pantalla incrementando un contador estático. Si el sistema agregó y eliminó la misma pantalla, resultó una ID diferente.

Si un dispositivo tuviera varias pantallas disponibles desde el arranque, se podrían asignar identificadores diferentes a las pantallas, según el tiempo. Si bien Android 9 (y versiones anteriores) incluían DisplayInfo#uniqueId , no contenía suficiente información para diferenciar entre pantallas porque las pantallas físicas se identificaron como local:0 o local:1 , para representar la pantalla integrada y la externa.

Android 10 cambia DisplayInfo#uniqueId para agregar un identificador estable y diferenciar entre pantallas locales, de red y virtuales.

Tipo de visualización Formato
Local
local:<stable-id>
La red
network:<mac-address>
Virtual
virtual:<package-name-and-name>

Además de las actualizaciones de uniqueId , DisplayInfo.address contiene DisplayAddress , un identificador de pantalla que es estable entre reinicios. En Android 10, DisplayAddress admite pantallas físicas y de red. DisplayAddress.Physical contiene un ID de visualización estable (igual que en uniqueId ) y se puede crear con DisplayAddress#fromPhysicalDisplayId() .

Android 10 también proporciona un método conveniente para obtener información del puerto ( Physical#getPort() ). Este método se puede utilizar en el marco para identificar estáticamente las pantallas. Por ejemplo, se usa en DisplayWindowSettings ). DisplayAddress.Network contiene la dirección MAC y se puede crear con DisplayAddress#fromMacAddress() .

Estas adiciones permiten a los fabricantes de dispositivos identificar pantallas en configuraciones estáticas de múltiples pantallas y configurar diferentes configuraciones y funciones del sistema utilizando identificadores de pantallas estáticas, como puertos para pantallas físicas. Estos métodos están ocultos y están destinados solo para ser utilizados dentro de system_server .

Dada una ID de pantalla HWC (que puede ser opaca y no siempre estable), este método devuelve el número de puerto de 8 bits (específico de la plataforma) que identifica un conector físico para la salida de la pantalla, así como el blob EDID de la pantalla. SurfaceFlinger extrae la información del fabricante o del modelo del EDID para generar los ID de pantalla estables de 64 bits expuestos al marco. Si este método no es compatible o falla, SurfaceFlinger recurre al modo MD heredado, donde DisplayInfo#address es nulo y DisplayInfo#uniqueId está codificado, como se describe anteriormente.

Para verificar que esta función es compatible, ejecute:

$ dumpsys SurfaceFlinger --display-id
# Example output.
Display 21691504607621632 (HWC display 0): port=0 pnpId=SHP displayName="LQ123P1JX32"
Display 9834494747159041 (HWC display 2): port=1 pnpId=HWP displayName="HP Z24i"
Display 1886279400700944 (HWC display 1): port=2 pnpId=AUS displayName="ASUS MB16AP"

Uso de más de dos pantallas

En Android 9 (y versiones anteriores), SurfaceFlinger y DisplayManagerService asumieron la existencia de dos pantallas físicas como máximo con los ID codificados 0 y 1.

A partir de Android 10, SurfaceFlinger podría aprovechar una API de Hardware Composer (HWC) para generar ID de pantalla estables, lo que le permite administrar una cantidad arbitraria de pantallas físicas. Para obtener más información, consulte Identificadores de visualización estáticos .

El marco puede buscar el token de IBinder para una pantalla física a través SurfaceControl#getPhysicalDisplayToken después de obtener el ID de pantalla de 64 bits de SurfaceControl#getPhysicalDisplayIds o de un evento de conexión en caliente DisplayEventReceiver .

En Android 10 (y versiones anteriores), la pantalla interna principal es TYPE_INTERNAL y todas las pantallas secundarias están marcadas como TYPE_EXTERNAL , independientemente del tipo de conexión. Por lo tanto, las pantallas internas adicionales se tratan como externas. Como solución alternativa, el código específico del dispositivo puede hacer suposiciones sobre DisplayAddress.Physical#getPort si se conoce el HWC y la lógica de asignación de puertos es predecible.

Esta limitación se elimina en Android 11 (y superior).

  • En Android 11, la primera pantalla que se informa durante el arranque es la pantalla principal. El tipo de conexión (interna versus externa) es irrelevante. Sin embargo, sigue siendo cierto que la pantalla principal no se puede desconectar y, en la práctica, debe ser una pantalla interna. Tenga en cuenta que algunos teléfonos plegables tienen varias pantallas internas.
  • Las pantallas secundarias se clasifican correctamente como Display.TYPE_INTERNAL o Display.TYPE_EXTERNAL (anteriormente conocidas como Display.TYPE_BUILT_IN y Display.TYPE_HDMI , respectivamente) según su tipo de conexión.

Implementación

En Android 9 y versiones anteriores, las pantallas se identifican mediante ID de 32 bits, donde 0 es la pantalla interna, 1 es la pantalla externa, [2, INT32_MAX] son ​​pantallas virtuales HWC y -1 representa una pantalla no válida o no HWC visualización virtual.

A partir de Android 10, las pantallas reciben ID estables y persistentes, lo que permite que SurfaceFlinger y DisplayManagerService rastreen más de dos pantallas y reconozcan pantallas vistas anteriormente. Si HWC es compatible con IComposerClient.getDisplayIdentificationData y proporciona datos de identificación de pantalla, SurfaceFlinger analiza la estructura EDID y asigna ID de pantalla estables de 64 bits para pantallas virtuales HWC y físicas. Los ID se expresan mediante un tipo de opción, donde el valor nulo representa una pantalla no válida o una pantalla virtual que no es HWC. Sin compatibilidad con HWC, SurfaceFlinger vuelve al comportamiento heredado con dos pantallas físicas como máximo.

Enfoque por pantalla

Para admitir varias fuentes de entrada que apuntan a pantallas individuales al mismo tiempo, Android 10 se puede configurar para admitir varias ventanas enfocadas, como máximo una por pantalla. Esto está destinado solo a tipos especiales de dispositivos cuando varios usuarios interactúan con el mismo dispositivo al mismo tiempo y usan diferentes métodos o dispositivos de entrada, como Android Automotive.

Se recomienda enfáticamente que esta función no esté habilitada para dispositivos normales, incluidos los dispositivos de pantallas múltiples o los que se usan para experiencias similares a las de un escritorio. Esto se debe principalmente a un problema de seguridad que puede hacer que los usuarios se pregunten qué ventana tiene el foco de entrada.

Imagine al usuario que ingresa información segura en un campo de entrada de texto, tal vez iniciando sesión en una aplicación bancaria o ingresando texto que contiene información confidencial. Una aplicación maliciosa podría crear una pantalla virtual fuera de la pantalla con la que ejecutar una actividad, también con un campo de entrada de texto. Las actividades legítimas y maliciosas tienen foco y ambas muestran un indicador de entrada activo (cursor parpadeante).

Sin embargo, dado que la entrada de un teclado (hardware o software) se ingresa solo en la actividad más alta (la aplicación que se lanzó más recientemente), al crear una pantalla virtual oculta, una aplicación maliciosa podría captar la entrada del usuario, incluso cuando se usa un teclado de software. en la pantalla del dispositivo principal.

Use com.android.internal.R.bool.config_perDisplayFocusEnabled para establecer el enfoque por pantalla.

Compatibilidad

Problema: en Android 9 y versiones anteriores, como máximo una ventana en el sistema tiene foco a la vez.

Solución: En el raro caso de que dos ventanas del mismo proceso estén enfocadas, el sistema solo enfoca la ventana que está más arriba en el orden Z. Esta restricción se elimina para las aplicaciones que tienen como objetivo Android 10, momento en el que se espera que puedan admitir el enfoque en varias ventanas simultáneamente.

Implementación

WindowManagerService#mPerDisplayFocusEnabled controla la disponibilidad de esta función. En ActivityManager , ahora se usa ActivityDisplay#getFocusedStack() en lugar del seguimiento global en una variable. ActivityDisplay#getFocusedStack() determina el enfoque en función del orden Z en lugar de almacenar en caché el valor. Esto es para que solo una fuente, WindowManager, necesite rastrear el orden Z de las actividades.

ActivityStackSupervisor#getTopDisplayFocusedStack() adopta un enfoque similar para aquellos casos en los que se debe identificar la pila enfocada más alta en el sistema. Las pilas se recorren de arriba abajo, buscando la primera pila elegible.

InputDispatcher ahora puede tener múltiples ventanas enfocadas (una por pantalla). Si un evento de entrada es específico de una pantalla, se envía a la ventana enfocada en la pantalla correspondiente. De lo contrario, se envía a la ventana enfocada en la pantalla enfocada, que es la pantalla con la que el usuario interactuó más recientemente.

Consulte InputDispatcher::mFocusedWindowHandlesByDisplay e InputDispatcher::setFocusedDisplay() . Las aplicaciones enfocadas también se actualizan por separado en InputManagerService a través de NativeInputManager::setFocusedApplication() .

En WindowManager , las ventanas enfocadas también se rastrean por separado. Consulte DisplayContent#mCurrentFocus y DisplayContent#mFocusedApp y los usos respectivos. Los métodos de seguimiento y actualización de enfoque relacionados se han movido de WindowManagerService a DisplayContent .