Soporte de pantalla

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

Cambiar el tamaño de actividades y visualizaciones

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 desde el contexto de la aplicación. Los valores devueltos no se ajustarán a las métricas del área visible en la que se muestra una actividad.
  • Es posible que una actividad no admita el cambio de tamaño y se bloquee, muestre una interfaz de usuario distorsionada o pierda el estado debido al reinicio sin guardar el estado de la instancia.
  • Una aplicación puede intentar utilizar coordenadas de entrada absolutas (en lugar de aquellas relativas a la posición de la ventana), lo que puede interrumpir la entrada en ventanas múltiples.

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 cuyo tamaño no se puede cambiar entren en pantalla dividida. Si el usuario intenta invocar una actividad no redimensionable desde el iniciador mientras ya está en modo de pantalla dividida, la plataforma sale del modo de pantalla dividida e inicia la actividad no redimensionable en modo de pantalla completa.

Las aplicaciones que establecen 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 no relacionados con la actividad.
  • 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 cuyo tamaño no se puede cambiar entren en modo de pantalla dividida, pero se pueden escalar temporalmente si la actividad ha declarado una orientación o relación de aspecto fija. 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 ventanas múltiples mediante el uso del atributo android:resizeableActivity y cuando esa actividad cumple con una de las condiciones que se describen a continuación, cuando la configuración de pantalla aplicada debe cambiar, la actividad y el proceso se guardan con la configuración original. y el usuario tiene la posibilidad de reiniciar el proceso de la aplicación para utilizar 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 según el nivel de API o declara la relación de aspecto explícitamente

Esta figura muestra una actividad no redimensionable con una relación de aspecto declarada. Al plegar el dispositivo, la ventana se reduce para adaptarse al área mientras se mantiene la relación de aspecto utilizando el formato letterboxing adecuado. Además, se proporciona al usuario una opción de reinicio de la actividad 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 de reiniciar la actividad.

Cuando no se establece resizeableActivity (o se establece en true ), la aplicación admite totalmente el cambio de tamaño.

Implementación

Una actividad no redimensionable con orientación o relación de aspecto fija 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 pantalla actual.

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

Cuando una actividad de SCM utiliza 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 relaciones altas de pantallas largas y delgadas hasta relaciones 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. Ejemplos de proporciones de aplicaciones compatibles con 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 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 menor o igual al tamaño de visualización objetivo. Utilice los atributos de diseño de actividad 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 WindowManagerPolicy en PhoneWindowManager a clases por pantalla, como:

  • Estado de visualización y rotación
  • Algunas claves y seguimiento de eventos de movimiento.
  • Interfaz de usuario del sistema y ventanas decorativas.

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

Configuración de la ventana de visualización

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

  • Modo de ventana de visualización predeterminado
  • Valores de sobreexploración
  • Rotación de usuario y modo de rotación.
  • Tamaño, densidad y modo de escala forzados
  • Modo de eliminación de contenido (cuando se elimina la visualización)
  • 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 sus dispositivos. Sin embargo, debido a que el archivo está almacenado en /data , es posible que se necesite lógica adicional para restaurar el archivo si se borra mediante un borrado.

De forma predeterminada, Android 10 usa DisplayInfo#uniqueId como identificador de una pantalla cuando persiste 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 utilizar el puerto de una pantalla física como identificador, que se puede configurar en DisplayWindowSettings#mIdentifier . Tras cada escritura, se escriben todas las configuraciones, por lo que es seguro actualizar la clave que se utiliza para una entrada de pantalla almacenada. Para obtener más información, consulte Identificadores de visualización estáticos .

La configuración se conserva en el directorio /data por motivos históricos. Originalmente, se usaban para conservar las configuraciones establecidas por el usuario, como la rotación de la pantalla.

Identificadores de visualización estática

Android 9 (y versiones anteriores) no proporcionaba identificadores estables para las 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 tenía varias pantallas disponibles desde el inicio, a las pantallas se les podrían asignar diferentes identificadores, según el momento. Si bien Android 9 (y versiones anteriores) incluía DisplayInfo#uniqueId , no contenía suficiente información para diferenciar entre pantallas porque las pantallas físicas se identificaban como local:0 o local:1 , para representar la pantalla incorporada 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>
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 tras los reinicios. En Android 10, DisplayAddress admite pantallas físicas y de red. DisplayAddress.Physical contiene una 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 pantallas estáticamente. 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 características del sistema utilizando identificadores de pantalla estática, como puertos para pantallas físicas. Estos métodos están ocultos y están destinados a usarse únicamente 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 información del fabricante o modelo del EDID para generar ID de pantalla estables de 64 bits expuestas al marco. Si este método no es compatible o se produce un error, SurfaceFlinger recurre al modo MD heredado, donde DisplayInfo#address es nulo y DisplayInfo#uniqueId está codificado, como se describe anteriormente.

Para verificar que esta característica sea 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"

Utilice más de dos pantallas

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

A partir de Android 10, SurfaceFlinger podría aprovechar una API 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 IBinder para una pantalla física a través de SurfaceControl#getPhysicalDisplayToken después de obtener el identificador 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 versiones posteriores).

  • 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 que no es HWC. visualización virtual.

A partir de Android 10, las pantallas reciben ID estables y persistentes, lo que permite a SurfaceFlinger y DisplayManagerService rastrear más de dos pantallas y reconocer pantallas vistas anteriormente. Si HWC admite 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 físicas y virtuales HWC. 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 soporte HWC, SurfaceFlinger recurre al comportamiento heredado con como máximo dos pantallas físicas.

Enfoque por pantalla

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

Se recomienda encarecidamente que esta función no esté habilitada para dispositivos normales, incluidos los dispositivos multipantalla o los que se utilizan 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 visualización virtual fuera de 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 activa (cursor parpadeante).

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

Utilice 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 del sistema tiene el foco a la vez.

Solución: En el raro caso de que se enfoquen dos ventanas del mismo proceso, el sistema enfoca solo la ventana que está más arriba en el orden Z. Esta restricción se elimina para las aplicaciones orientadas a 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 , ActivityDisplay#getFocusedStack() ahora se usa en lugar del seguimiento global en una variable. ActivityDisplay#getFocusedStack() determina el enfoque según el orden Z en lugar de almacenar en caché el valor. Esto es para que sólo una fuente, WindowManager, necesite realizar un seguimiento del 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 del sistema. Las pilas se recorren de arriba a 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 la 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 y 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 sus usos respectivos. Los métodos de actualización y seguimiento de enfoque relacionados se han movido de WindowManagerService a DisplayContent .