Prácticas recomendadas

Apps para dispositivos plegables y de varias pantallas

Por lo general, las apps no deben depender de identificadores estáticos ni de lógica que dependa de algunos IDs de pantalla. En la mayoría de los casos, las apps deben cambiar de tamaño y funcionar en diferentes pantallas, y el sistema debe controlar dónde ubicarlas. Por ejemplo, para crear una experiencia nueva y única para dispositivos plegables y lanzar una app especial en la pantalla externa cuando el dispositivo está plegado.

En este caso, SystemUI (o algún otro componente del sistema) debe detectar el pliegue, determinar si es adecuado realizar una acción y, luego, iniciar la actividad de destino y especificar un ID de pantalla externa como destino de inicio. Las apps no deben detectar esta acción ni realizar ninguna acción en respuesta y, luego, realizar el lanzamiento en una pantalla específica. En otras palabras, no supongas que lo que funciona en un dispositivo funcionará en otros. En resumen, el código específico del dispositivo aumenta la fragmentación.

Restringe el acceso a las pantallas

Si la configuración del dispositivo requiere la restricción del acceso a una o más pantallas, se recomienda usar la marca Display#FLAG_PRIVATE para designar esas pantallas como privadas. Si lo haces, se restringe a todos, excepto al propietario, la posibilidad de agregar contenido a la pantalla. Cualquier intento de iniciar una actividad o agregar una ventana por parte de alguien que no sea el propietario genera una SecurityException. Si el sistema es propietario de la pantalla, puede agregar ventanas y lanzar actividades.

Además, las entidades que se colocan en una pantalla siempre pueden acceder a ella. Si el propietario inicia una actividad en una pantalla, la actividad puede iniciar otras actividades en esta pantalla. Como resultado, el propietario es responsable de restringir el acceso y permitir solo apps de confianza.

Además, se agregan más restricciones a las pantallas virtuales porque cualquier app puede crear una sin que sea visible para el usuario. Si el sistema no es propietario de la pantalla virtual, solo se permiten las actividades con allowEmbedded, y el llamador debe tener el permiso ACTIVITY_EMBEDDING.

Para obtener más información, consulte:

  • ActivityStackSupervisor#isCallerAllowedToLaunchOnDisplay()
  • ActivityDisplay#isUidPresent()
  • DisplayManagerService#isUidPresentOnDisplay()

Para controlar de forma condicional los inicios de actividades, usa LaunchParamsController, que intercepta todos los inicios de actividades y permite que un componente del sistema modifique los parámetros que se usan para el inicio. Esto está disponible en system_server.

Configura los parámetros de ventanas de la pantalla y las decoraciones del sistema

Las decoraciones del sistema se pueden configurar por pantalla en DisplayWindowSettings. Una implementación del dispositivo puede proporcionar una configuración predeterminada en /data/system/display_settings.xml.

Este valor determina si las decoraciones del sistema (launcher, fondo de pantalla, barra de navegación y otras ventanas de decoración) y el IME aparecen en una pantalla. Para obtener más detalles, consulta DisplayWindowSettings#shouldShowSystemDecorsLocked() y DisplayWindowSettings#shouldShowImeLocked().

Para identificar la pantalla, usa un ID único (este valor predeterminado usa DisplayInfo#uniqueId) o un ID de puerto físico para pantallas de hardware (consulta DisplayInfo#address).

Por ejemplo, el siguiente ejemplo de configuración de pantalla habilita las decoraciones del sistema y el IME en una pantalla simulada:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<display-settings>
<config identifier="0" />
<display
  name="overlay:1"
  shouldShowSystemDecors="true"
  shouldShowIme="true" />
</display-settings>

En el ejemplo anterior, se usa uniqueId para la identificación de la pantalla en el atributo name, que para una pantalla simulada es overlay:1. Para una pantalla integrada, un valor de muestra puede ser "local:45354385242535243453". Otra opción es usar la información del puerto de hardware y configurar identifier="1" para que corresponda a DisplayWindowSettings#IDENTIFIER_PORT y, luego, actualizar el nombre para usar el "port:<port_id>" formato:

<?xmlversion='1.0' encoding='utf-8' standalone='yes' ?>
<display-settings>
<config identifier="1" />
<display
  name="port:12345"
  shouldShowSystemDecors="true"
  shouldShowIme="true" />
</display-settings>

Para obtener más detalles, consulta Identificadores de pantalla estáticos.

Para obtener más información, consulte:

Alterna las pantallas entre las tareas de duplicación y hosting

En Android 17 y versiones posteriores, DisplayManager usa la FLAG_ALLOWS_CONTENT_MODE_SWITCH marca para controlar si una pantalla alterna entre las tareas de duplicación y hosting tareas en el tiempo de ejecución. De forma predeterminada, esta marca está habilitada para pantallas externas y está inhabilitada para todas las demás pantallas.

Cuando FLAG_ALLOWS_CONTENT_MODE_SWITCH está presente, DisplayManager supervisa el parámetro seguro android.provider.Settings.Secure.MIRROR_BUILT_IN_DISPLAY para determinar si se deben duplicar o alojar tareas. Si bien esta es la lógica predeterminada, los OEMs pueden personalizar este comportamiento.

Topología de la pantalla y movimiento del puntero

En Android 17 y versiones posteriores, la topología de la pantalla define las posiciones relativas de las pantallas y restringe el movimiento del puntero del mouse al conjunto específico de pantallas de la topología.

WindowManager decide incluir una pantalla en la topología y llama a DisplayManagerInternal.onDisplayBelongToTopologyChanged. DisplayManager verifica DisplayTopologyCoordinator.isDisplayAllowedInTopology antes de agregar la pantalla. De forma predeterminada, si las pantallas locales pueden alojar tareas, el sistema las agrega.

Si hay varias pantallas públicas que pueden alojar tareas, la decisión de incluir la pantalla predeterminada la controla el proveedor booleano shouldIncludeDefaultDisplayInTopology que se pasa a DisplayTopologyCoordinator. Si la pantalla predeterminada es la única pantalla pública que puede alojar tareas, siempre está en la topología. En AOSP, el proveedor booleano muestra true solo si la pantalla predeterminada admite el modo de ventanas de escritorio o si el parámetro seguro Settings.Secure.INCLUDE_DEFAULT_DISPLAY_IN_TOPOLOGY es true.

Las apps consultan la topología actual con DisplayManager.getDisplayTopology y reaccionan a los cambios en la topología registrando un objeto de escucha con DisplayManager.registerTopologyListener.