Рекомендации

На этой странице представлены рекомендации по работе с несколькими дисплеями.

Приложения для складных и многоэкранных устройств

В целом, приложениям не следует полагаться на статические идентификаторы или логику, зависящую от идентификаторов дисплея. В большинстве случаев приложения должны изменять размер и работать на разных дисплеях, а система должна контролировать, где размещать приложения. Например, для создания нового и уникального пользовательского опыта для складных устройств и запуска специального приложения на внешнем экране, когда устройство сложено.

В этом случае системный пользовательский интерфейс или другой системный компонент должен обнаружить складку экрана, определить, целесообразно ли выполнять какое-либо действие, а затем запустить целевое действие, указав в качестве целевого объекта запуска внешний идентификатор дисплея. Приложения не должны обнаруживать это действие или выполнять какие-либо действия в ответ, а затем запускать его на конкретном дисплее. Поэтому не следует предполагать, что то, что работает на одном устройстве, будет работать и на других. Короче говоря, код, специфичный для конкретного устройства, увеличивает фрагментацию.

Ограничить доступ к дисплеям

Если конфигурация устройства требует ограничения доступа к одному или нескольким дисплеям, мы рекомендуем использовать флаг Display#FLAG_PRIVATE чтобы обозначить дисплей как частный. Это обозначение запрещает всем, кроме владельца, добавлять контент на дисплей. Если кто-либо, кроме владельца, попытается запустить действие или добавить окно, это вызовет исключение SecurityException . Если дисплей принадлежит системе, она может добавлять окна и запускать действия.

Кроме того, объекты, размещенные на экране, всегда могут получить к нему доступ. Если владелец запускает действие на экране, то это действие может запустить другие действия на этом экране. Следовательно, владелец несет ответственность за ограничение доступа и разрешение доступа только доверенным приложениям.

Кроме того, к виртуальным дисплеям добавляются дополнительные ограничения, поскольку любое приложение может создать его, не делая его видимым для пользователя. Если виртуальный дисплей не принадлежит системе, разрешены только действия с allowEmbedded , а вызывающая сторона должна иметь разрешение ACTIVITY_EMBEDDING .

Для получения более подробной информации см.:

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

Для условного управления запуском действий используйте LaunchParamsController , который перехватывает все запуски действий и позволяет системному компоненту изменять параметры, используемые для запуска. Эта функция доступна в system_server .

Настройка параметров отображения и оформления системы.

Системные настройки оформления можно задать для каждого дисплея в DisplayWindowSettings . Для конкретного устройства можно задать конфигурацию по умолчанию в /data/system/display_settings.xml .

Это значение определяет, будут ли системные элементы оформления (панель запуска, обои, панель навигации и другие окна оформления) и IME отображаться на экране. Для получения подробной информации см. DisplayWindowSettings#shouldShowSystemDecorsLocked и DisplayWindowSettings#shouldShowImeLocked .

Для идентификации дисплея используйте либо уникальный идентификатор (по умолчанию используется DisplayInfo#uniqueId ), либо идентификатор физического порта для аппаратных дисплеев (см. DisplayInfo#address ).

Например, следующий пример конфигурации дисплея включает системные элементы оформления и IME на имитированном дисплее:

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

В приведенном выше примере uniqueId используется для идентификации дисплея в атрибуте name, который для имитируемого дисплея имеет overlay:1 . Для встроенного дисплея примерным значением может быть "local:45354385242535243453" . Другой вариант — использовать информацию о порте оборудования и установить identifier="1" в соответствии с DisplayWindowSettings#IDENTIFIER_PORT , а затем обновить имя, используя формат "port:<port_id>" :

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

Подробности см. в разделе «Статические идентификаторы отображения» .

Для получения более подробной информации см.:

Переключение отображения между задачами зеркалирования и хостинга.

В Android 17 и более поздних версиях DisplayManager использует флаг FLAG_ALLOWS_CONTENT_MODE_SWITCH для управления переключением дисплея между задачами зеркалирования и размещения во время выполнения. По умолчанию этот флаг включен для внешних дисплеев и отключен для всех остальных.

Если присутствует FLAG_ALLOWS_CONTENT_MODE_SWITCH , DisplayManager отслеживает параметр безопасности android.provider.Settings.Secure.MIRROR_BUILT_IN_DISPLAY , чтобы определить, следует ли дублировать или размещать задачи. Хотя это логика по умолчанию, производители оборудования могут настроить это поведение.

Отображение топологии и перемещения указателя.

В Android 17 и более поздних версиях топология дисплея определяет относительное положение дисплеев и ограничивает перемещение указателя мыши определенным набором дисплеев в этой топологии.

WindowManager принимает решение о включении дисплея в топологию и вызывает DisplayManagerInternal.onDisplayBelongToTopologyChanged . Перед добавлением дисплея DisplayManager проверяет DisplayTopologyCoordinator.isDisplayAllowedInTopology . По умолчанию, если локальные дисплеи могут размещать задачи, система добавляет их.

Если существует несколько общедоступных дисплеев, которые могут размещать задачи, решение о включении дисплея по умолчанию принимается логическим параметром shouldIncludeDefaultDisplayInTopology , который передается в DisplayTopologyCoordinator . Если дисплей по умолчанию является единственным общедоступным дисплеем, который может размещать задачи, он всегда присутствует в топологии. В AOSP логический параметр возвращает true только в том случае, если дисплей по умолчанию поддерживает оконный режим рабочего стола или если параметр безопасности Settings.Secure.INCLUDE_DEFAULT_DISPLAY_IN_TOPOLOGY имеет значение true .

Приложения запрашивают текущую топологию с помощью DisplayManager.getDisplayTopology и реагируют на изменения топологии, регистрируя слушатель с помощью DisplayManager.registerTopologyListener .