Recommended Practices

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.

Restricting 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.

Configuring 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: