Apps for foldable and multi-screen devices
Generally, apps should not rely on static identifiers or logic that depends on some display IDs. In most cases, apps should resize and work on different displays and the system should control where to locate apps. For example, to build a new and unique experience for foldable devices and launch a special app on the external screen when the device is folded.
In this case, SystemUI (or another system component) should detect the fold, determine if it's appropriate to perform an action, and then launch the target activity and specify an external display ID as the launch target. Apps shouldn't detect this action or perform any action in response and then perform the launch on a specific display. In other words, do not assume that what works on one device will work on other devices. In short, device-specific code increases fragmentation.
Restrict access to displays
If the device configuration requires the restriction of access to one or more
displays, the recommendation is to use the Display#FLAG_PRIVATE flag
to designate such displays as private. Doing so restricts all but the
owner from adding content to the display. Any attempt to launch an activity or to
add a window by anyone but the owner results in a SecurityException.
If the system owns the display, the system can add windows and launch activities.
In addition, entities placed on a display can always access that display. If the owner launches an activity on a display, then the activity can launch other activities on this display. As a result, the owner is responsible for restricting access and allowing trusted apps only.
In addition, more restrictions are added to virtual displays because any app can
create one without making it visible to the user. If the virtual display isn't
owned by the system, then only activities with
allowEmbedded
are permitted and the caller should have the ACTIVITY_EMBEDDING
permission.
For more information, see:
ActivityStackSupervisor#isCallerAllowedToLaunchOnDisplay()ActivityDisplay#isUidPresent()DisplayManagerService#isUidPresentOnDisplay()
To conditionally control activity launches, use LaunchParamsController,
which intercepts all activity launches and allows a system component to modify the
parameters used for launch. This is available in system_server.
Configure display windowing settings and system decorations
System decorations can
be configured per display in DisplayWindowSettings. A device
implementation can provide a default configuration in
/data/system/display_settings.xml.
This value determines whether system decorations (launcher, wallpaper,
navigation bar, and other decor windows) and the IME appear on a display.
For details, see DisplayWindowSettings#shouldShowSystemDecorsLocked()
and DisplayWindowSettings#shouldShowImeLocked().
To identify the display, use either a unique ID (this default uses
DisplayInfo#uniqueId) or a physical port ID for hardware
displays (see DisplayInfo#address).
For example, the following display config example enables system decorations and the IME on a simulated display:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <display-settings> <config identifier="0" /> <display name="overlay:1" shouldShowSystemDecors="true" shouldShowIme="true" /> </display-settings>
In the example above, uniqueId is used for display identification
in the name attribute, which for a simulated display is overlay:1.
For a built-in display, a sample value may be "local:45354385242535243453".
Another option is to use hardware port information and set identifier="1"
to correspond to DisplayWindowSettings#IDENTIFIER_PORT and then update the
name to use the "port:<port_id>" format:
<?xmlversion='1.0' encoding='utf-8' standalone='yes' ?> <display-settings> <config identifier="1" /> <display name="port:12345" shouldShowSystemDecors="true" shouldShowIme="true" /> </display-settings>
For details, see Static display identifiers.
For more information, see:
Switch displays between mirroring and hosting tasks
In Android 17 and higher, DisplayManager uses the
FLAG_ALLOWS_CONTENT_MODE_SWITCH flag to control whether a display switches
between mirroring and hosting tasks at run time. By default, this flag is
enabled for external displays and disabled for all other displays.
When FLAG_ALLOWS_CONTENT_MODE_SWITCH is present, DisplayManager monitors
the android.provider.Settings.Secure.MIRROR_BUILT_IN_DISPLAY secure setting
to determine whether to mirror or host tasks. While this is the default logic,
OEMs can customize this behavior.
Display topology and pointer movement
In Android 17 and higher, display topology defines the relative positions of displays and restricts mouse pointer movement to the specific set of displays in the topology.
WindowManager decides to include a display in the topology and calls
DisplayManagerInternal.onDisplayBelongToTopologyChanged. DisplayManager
checks DisplayTopologyCoordinator.isDisplayAllowedInTopology before adding the
display. By default, if local displays can host tasks, the system adds them.
If there are multiple public displays that can host tasks, the decision to
include the default display is handled by the
shouldIncludeDefaultDisplayInTopology boolean provider that is passed to
DisplayTopologyCoordinator. If the default display is the only public display
that can host tasks, it's always in the topology. In AOSP, the boolean
provider returns true only if the default display supports desktop windowing
or if the secure setting Settings.Secure.INCLUDE_DEFAULT_DISPLAY_IN_TOPOLOGY
is true.
Apps query the current topology using DisplayManager.getDisplayTopology and
react to changes to the topology by registering a listener with
DisplayManager.registerTopologyListener.