Поддержка системных украшений

Обновления, внесенные в эти области дисплея, представлены ниже:

Системные украшения

В Android 10 добавлена ​​поддержка настройки дополнительных дисплеев для отображения определенных системных украшений, таких как обои, панель навигации и панель запуска. По умолчанию на основном дисплее отображаются все системные украшения, а на дополнительных дисплеях — те, которые включены опционально. Поддержку редактора метода ввода (IME) можно настроить отдельно от других украшательств системы.

Используйте DisplayWindowSettings#setShouldShowSystemDecorsLocked() чтобы добавить поддержку системных украшений на определенном дисплее или указать значение по умолчанию в /data/system/display_settings.xml . Примеры см. в разделе Настройки окна отображения .

Выполнение

DisplayWindowSettings#setShouldShowSystemDecorsLocked() также доступен в WindowManager#setShouldShowSystemDecors() для тестирования. Запуск этого метода с целью включения системных декоров не добавляет отсутствующие ранее окна декора и не удаляет их, если они ранее присутствовали. В большинстве случаев поддержка смены системных украшений вступает в полную силу только после перезагрузки устройства.

Проверки поддержки системных украшений в базе кода WindowManager обычно выполняются через DisplayContent#supportsSystemDecorations() тогда как проверки внешних служб (например, системного пользовательского интерфейса для проверки необходимости отображения панели навигации) используют WindowManager#shouldShowSystemDecors() . Чтобы понять, чем управляет этот параметр, изучите точки вызова этих методов.

Окна оформления системного пользовательского интерфейса

В Android 10 добавлена ​​поддержка окон оформления системы только для панели навигации, поскольку панель навигации необходима для навигации между действиями и приложениями. По умолчанию на панели навигации отображаются возможности «Назад» и «Домой». Это включается только в том случае, если целевой дисплей поддерживает системные украшения (см. DisplayWindowSettings ).

Строка состояния — более сложное системное окно, поскольку она также содержит панель уведомлений, быстрые настройки и экран блокировки. В Android 10 строка состояния не поддерживается на дополнительных дисплеях. Поэтому уведомления, настройки и полноценная клавиатура доступны только на основном дисплее.

Системное окно «Обзор/Последние» не поддерживается на дополнительных экранах. В Android 10 AOSP отображает только «Недавние» на дисплее по умолчанию и содержит действия со всех дисплеев. При запуске из «Недавних» действие, которое было на дополнительном дисплее, по умолчанию выводится на передний план этого дисплея. У этого подхода есть некоторые известные проблемы, например отсутствие немедленного обновления при появлении приложений на других экранах.

Выполнение

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

Компонент системного пользовательского интерфейса, поддерживающий многоэкранный режим (MD), должен обрабатывать следующие случаи:

  • Инициализация нескольких дисплеев при запуске
  • Отображение добавлено во время выполнения
  • Дисплей удален во время выполнения

Когда системный пользовательский интерфейс обнаруживает добавление дисплея перед WindowManager, это создает состояние гонки. Этого можно избежать, реализовав собственный обратный вызов из WindowManager в системный пользовательский интерфейс при добавлении дисплея вместо подписки на события DisplayManager .DisplayListener . Образец реализации см. в разделе CommandQueue.Callbacks#onDisplayReady для поддержки панели навигации и WallpaperManagerInternal#onDisplayReady для обоев.

Кроме того, Android 10 предоставляет следующие обновления:

  • Класс NavigationBarController управляет всеми функциями, специфичными для панелей навигации.
  • Чтобы просмотреть настроенную панель навигации, см. CarStatusBar .
  • TYPE_NAVIGATION_BAR больше не ограничивается одним экземпляром и может использоваться для каждого дисплея.
  • IWindowManager#hasNavigationBar() обновлен и теперь включает параметр displayId только для системного пользовательского интерфейса.

пусковая установка

В Android 10 каждый дисплей, настроенный для поддержки системных украшений, по умолчанию имеет выделенный домашний стек для действий средства запуска с типом WindowConfiguration#ACTIVITY_TYPE_HOME . Каждый дисплей использует отдельный экземпляр активности средства запуска.

Рис. 1. Пример запуска нескольких дисплеев для platform/development/samples/MultiDisplay

Большинство существующих программ запуска не поддерживают несколько экземпляров и не оптимизированы для экранов больших размеров. Кроме того, на дополнительных/внешних дисплеях часто ожидаются другие впечатления. Чтобы обеспечить выделенное действие для дополнительных экранов, Android 10 вводит категорию SECONDARY_HOME в фильтрах намерений. Экземпляры этого действия используются на всех дисплеях, поддерживающих системные украшения, по одному на каждый дисплей.

<activity>
    ...
    <intent-filter>
        <category android:name="android.intent.category.SECONDARY_HOME" />
        ...
    </intent-filter>
</activity>

У действия должен быть режим запуска, который не препятствует созданию нескольких экземпляров и должен адаптироваться к различным размерам экрана. Режим запуска не может быть singleInstance или singleTask .

Выполнение

В Android 10 RootActivityContainer#startHomeOnDisplay() автоматически выбирает нужный компонент и намерение в зависимости от дисплея, на котором запускается главный экран. RootActivityContainer#resolveSecondaryHomeActivity() содержит логику для поиска компонента активности средства запуска в зависимости от выбранного в данный момент средства запуска и при необходимости может использовать системное значение по умолчанию (см. ActivityTaskManagerService#getSecondaryHomeIntent() ).

Ограничения безопасности

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

Обои

В Android 10 (и более поздних версиях) обои поддерживаются на дополнительных дисплеях:

Рисунок 2. Живые обои на внутреннем (вверху) и внешнем дисплеях (внизу)

Разработчики могут объявить о поддержке функции обоев, указав android:supportsMultipleDisplays="true" в XML-определении WallpaperInfo . Разработчики обоев также должны загружать ресурсы, используя контекст отображения в WallpaperService.Engine#getDisplayContext() .

Платформа создает один экземпляр WallpaperService.Engine для каждого дисплея, поэтому каждый механизм имеет свою собственную поверхность и контекст отображения. Разработчику необходимо убедиться, что каждый движок может рисовать независимо, с разной частотой кадров, соблюдая VSYNC.

Выбор обоев для отдельных экранов

Android 10 не обеспечивает прямой поддержки платформы для выбора обоев для отдельных экранов. Для этого необходим стабильный идентификатор дисплея, чтобы сохранить настройки обоев для каждого дисплея. Display#getDisplayId() является динамическим, поэтому нет гарантии, что физический дисплей будет иметь тот же идентификатор после перезагрузки.

Однако в Android 10 добавлен DisplayInfo.mAddress , который содержит стабильные идентификаторы для физических дисплеев и может использоваться для полной реализации в будущем. К сожалению, реализовывать логику для Android 10 уже поздно. Предлагаемое решение:

  1. Используйте API WallpaperManager для установки обоев.
  2. WallpaperManager получается из объекта Context , и каждый объект Context содержит информацию о соответствующем дисплее ( Context#getDisplay()/getDisplayId() ). Таким образом, вы можете получить displayId из экземпляра WallpaperManager без добавления новых методов.
  3. На стороне платформы используйте displayId , полученный из объекта Context , и сопоставьте его со статическим идентификатором (например, портом физического дисплея). Используйте статический идентификатор, чтобы сохранить выбранные обои.

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

Если необходимо установить обои для дисплея, отличного от текущего дисплея, создайте новый объект Context для целевого дисплея ( Context#createDisplayContext ) и получите экземпляр WallpaperManager из этого дисплея.

Ограничения безопасности

Система не будет отображать обои на виртуальных дисплеях, которые ей не принадлежат. Это связано с соображениями безопасности, поскольку вредоносное приложение может создать виртуальный дисплей с включенной поддержкой системных украшений и считывать с поверхности конфиденциальную информацию пользователя (например, личную фотографию).

Выполнение

В Android 10 интерфейсы IWallpaperConnection#attachEngine() и IWallpaperService#attach() принимают параметр displayId для создания подключений для каждого дисплея. WallpaperManagerService.DisplayConnector инкапсулирует механизм обоев и соединение для каждого дисплея. В WindowManager контроллеры обоев создаются для каждого объекта DisplayContent при создании вместо одного WallpaperController для всех дисплеев.

Некоторые реализации общедоступных методов WallpaperManager (например, WallpaperManager#getDesiredMinimumWidth() ) были обновлены для вычисления и предоставления информации для соответствующих дисплеев. Были добавлены WallpaperInfo#supportsMultipleDisplays() и соответствующий атрибут ресурса, чтобы разработчики приложений могли сообщать, какие обои готовы для нескольких экранов.

Если служба обоев, отображаемая на дисплее по умолчанию, не поддерживает несколько дисплеев, система отображает обои по умолчанию на дополнительных дисплеях.

Рисунок 3. Логика возврата обоев для дополнительных дисплеев

,

Обновления, внесенные в эти области дисплея, представлены ниже:

Системные украшения

В Android 10 добавлена ​​поддержка настройки дополнительных дисплеев для отображения определенных системных украшений, таких как обои, панель навигации и панель запуска. По умолчанию на основном дисплее отображаются все системные украшения, а на дополнительных дисплеях — те, которые включены опционально. Поддержку редактора метода ввода (IME) можно настроить отдельно от других украшательств системы.

Используйте DisplayWindowSettings#setShouldShowSystemDecorsLocked() чтобы добавить поддержку системных украшений на определенном дисплее или указать значение по умолчанию в /data/system/display_settings.xml . Примеры см. в разделе Настройки окна отображения .

Выполнение

DisplayWindowSettings#setShouldShowSystemDecorsLocked() также доступен в WindowManager#setShouldShowSystemDecors() для тестирования. Запуск этого метода с целью включения системных декоров не добавляет отсутствующие ранее окна декора и не удаляет их, если они ранее присутствовали. В большинстве случаев поддержка смены системных украшений вступает в полную силу только после перезагрузки устройства.

Проверки поддержки системных украшений в базе кода WindowManager обычно выполняются через DisplayContent#supportsSystemDecorations() тогда как проверки внешних служб (например, системного пользовательского интерфейса для проверки необходимости отображения панели навигации) используют WindowManager#shouldShowSystemDecors() . Чтобы понять, чем управляет этот параметр, изучите точки вызова этих методов.

Окна оформления системного пользовательского интерфейса

В Android 10 добавлена ​​поддержка окон оформления системы только для панели навигации, поскольку панель навигации необходима для навигации между действиями и приложениями. По умолчанию на панели навигации отображаются возможности «Назад» и «Домой». Это включается только в том случае, если целевой дисплей поддерживает системные украшения (см. DisplayWindowSettings ).

Строка состояния — более сложное системное окно, поскольку она также содержит панель уведомлений, быстрые настройки и экран блокировки. В Android 10 строка состояния не поддерживается на дополнительных дисплеях. Поэтому уведомления, настройки и полноценная клавиатура доступны только на основном дисплее.

Системное окно «Обзор/Последние» не поддерживается на дополнительных экранах. В Android 10 AOSP отображает только «Недавние» на дисплее по умолчанию и содержит действия со всех дисплеев. При запуске из «Недавних» действие, которое было на дополнительном дисплее, по умолчанию выводится на передний план этого дисплея. У этого подхода есть некоторые известные проблемы, например отсутствие немедленного обновления при появлении приложений на других экранах.

Выполнение

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

Компонент системного пользовательского интерфейса, поддерживающий многоэкранный режим (MD), должен обрабатывать следующие случаи:

  • Инициализация нескольких дисплеев при запуске
  • Отображение добавлено во время выполнения
  • Дисплей удален во время выполнения

Когда системный пользовательский интерфейс обнаруживает добавление дисплея перед WindowManager, это создает состояние гонки. Этого можно избежать, реализовав собственный обратный вызов из WindowManager в системный пользовательский интерфейс при добавлении дисплея вместо подписки на события DisplayManager .DisplayListener . Образец реализации см. в разделе CommandQueue.Callbacks#onDisplayReady для поддержки панели навигации и WallpaperManagerInternal#onDisplayReady для обоев.

Кроме того, Android 10 предоставляет следующие обновления:

  • Класс NavigationBarController управляет всеми функциями, специфичными для панелей навигации.
  • Чтобы просмотреть настроенную панель навигации, см. CarStatusBar .
  • TYPE_NAVIGATION_BAR больше не ограничивается одним экземпляром и может использоваться для каждого дисплея.
  • IWindowManager#hasNavigationBar() обновлен и теперь включает параметр displayId только для системного пользовательского интерфейса.

пусковая установка

В Android 10 каждый дисплей, настроенный для поддержки системных украшений, по умолчанию имеет выделенный домашний стек для действий средства запуска с типом WindowConfiguration#ACTIVITY_TYPE_HOME . Каждый дисплей использует отдельный экземпляр активности средства запуска.

Рис. 1. Пример запуска нескольких дисплеев для platform/development/samples/MultiDisplay

Большинство существующих программ запуска не поддерживают несколько экземпляров и не оптимизированы для экранов больших размеров. Кроме того, на дополнительных/внешних дисплеях часто ожидаются другие впечатления. Чтобы обеспечить выделенное действие для дополнительных экранов, Android 10 вводит категорию SECONDARY_HOME в фильтрах намерений. Экземпляры этого действия используются на всех дисплеях, поддерживающих системные украшения, по одному на каждый дисплей.

<activity>
    ...
    <intent-filter>
        <category android:name="android.intent.category.SECONDARY_HOME" />
        ...
    </intent-filter>
</activity>

У действия должен быть режим запуска, который не препятствует созданию нескольких экземпляров и должен адаптироваться к различным размерам экрана. Режим запуска не может быть singleInstance или singleTask .

Выполнение

В Android 10 RootActivityContainer#startHomeOnDisplay() автоматически выбирает нужный компонент и намерение в зависимости от дисплея, на котором запускается главный экран. RootActivityContainer#resolveSecondaryHomeActivity() содержит логику для поиска компонента активности средства запуска в зависимости от выбранного в данный момент средства запуска и при необходимости может использовать системное значение по умолчанию (см. ActivityTaskManagerService#getSecondaryHomeIntent() ).

Ограничения безопасности

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

Обои

В Android 10 (и более поздних версиях) обои поддерживаются на дополнительных дисплеях:

Рисунок 2. Живые обои на внутреннем (вверху) и внешнем дисплеях (внизу)

Разработчики могут объявить о поддержке функции обоев, указав android:supportsMultipleDisplays="true" в XML-определении WallpaperInfo . Разработчики обоев также должны загружать ресурсы, используя контекст отображения в WallpaperService.Engine#getDisplayContext() .

Платформа создает один экземпляр WallpaperService.Engine для каждого дисплея, поэтому каждый механизм имеет свою собственную поверхность и контекст отображения. Разработчику необходимо убедиться, что каждый движок может рисовать независимо, с разной частотой кадров, соблюдая VSYNC.

Выбор обоев для отдельных экранов

Android 10 не обеспечивает прямой поддержки платформы для выбора обоев для отдельных экранов. Для этого необходим стабильный идентификатор дисплея, чтобы сохранить настройки обоев для каждого дисплея. Display#getDisplayId() является динамическим, поэтому нет гарантии, что физический дисплей будет иметь тот же идентификатор после перезагрузки.

Однако в Android 10 добавлен DisplayInfo.mAddress , который содержит стабильные идентификаторы для физических дисплеев и может использоваться для полной реализации в будущем. К сожалению, реализовывать логику для Android 10 уже поздно. Предлагаемое решение:

  1. Используйте API WallpaperManager для установки обоев.
  2. WallpaperManager получается из объекта Context , и каждый объект Context содержит информацию о соответствующем дисплее ( Context#getDisplay()/getDisplayId() ). Таким образом, вы можете получить displayId из экземпляра WallpaperManager без добавления новых методов.
  3. На стороне платформы используйте displayId , полученный из объекта Context , и сопоставьте его со статическим идентификатором (например, портом физического дисплея). Используйте статический идентификатор, чтобы сохранить выбранные обои.

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

Если необходимо установить обои для дисплея, отличного от текущего дисплея, создайте новый объект Context для целевого дисплея ( Context#createDisplayContext ) и получите экземпляр WallpaperManager из этого дисплея.

Ограничения безопасности

Система не будет отображать обои на виртуальных дисплеях, которые ей не принадлежат. Это связано с соображениями безопасности, поскольку вредоносное приложение может создать виртуальный дисплей с включенной поддержкой системных украшений и считывать с поверхности конфиденциальную информацию пользователя (например, личную фотографию).

Выполнение

В Android 10 интерфейсы IWallpaperConnection#attachEngine() и IWallpaperService#attach() принимают параметр displayId для создания подключений для каждого дисплея. WallpaperManagerService.DisplayConnector инкапсулирует механизм обоев и соединение для каждого дисплея. В WindowManager контроллеры обоев создаются для каждого объекта DisplayContent при создании вместо одного WallpaperController для всех дисплеев.

Некоторые реализации общедоступных методов WallpaperManager (например, WallpaperManager#getDesiredMinimumWidth() ) были обновлены для вычисления и предоставления информации для соответствующих дисплеев. Были добавлены WallpaperInfo#supportsMultipleDisplays() и соответствующий атрибут ресурса, чтобы разработчики приложений могли сообщать, какие обои готовы для нескольких экранов.

Если служба обоев, отображаемая на дисплее по умолчанию, не поддерживает несколько дисплеев, система отображает обои по умолчанию на дополнительных дисплеях.

Рисунок 3. Логика возврата обоев для дополнительных дисплеев

,

Обновления, внесенные в эти области дисплея, представлены ниже:

Системные украшения

В Android 10 добавлена ​​поддержка настройки дополнительных дисплеев для отображения определенных системных украшений, таких как обои, панель навигации и панель запуска. По умолчанию на основном дисплее отображаются все системные украшения, а на дополнительных дисплеях — те, которые включены опционально. Поддержку редактора метода ввода (IME) можно настроить отдельно от других украшательств системы.

Используйте DisplayWindowSettings#setShouldShowSystemDecorsLocked() чтобы добавить поддержку системных украшений на определенном дисплее или указать значение по умолчанию в /data/system/display_settings.xml . Примеры см. в разделе Настройки окна отображения .

Выполнение

DisplayWindowSettings#setShouldShowSystemDecorsLocked() также доступен в WindowManager#setShouldShowSystemDecors() для тестирования. Запуск этого метода с целью включения системных декоров не добавляет отсутствующие ранее окна декора и не удаляет их, если они ранее присутствовали. В большинстве случаев поддержка смены системных украшений вступает в полную силу только после перезагрузки устройства.

Проверки поддержки системных украшений в базе кода WindowManager обычно выполняются через DisplayContent#supportsSystemDecorations() тогда как проверки внешних служб (например, системного пользовательского интерфейса для проверки необходимости отображения панели навигации) используют WindowManager#shouldShowSystemDecors() . Чтобы понять, чем управляет этот параметр, изучите точки вызова этих методов.

Окна оформления системного пользовательского интерфейса

В Android 10 добавлена ​​поддержка окон оформления системы только для панели навигации, поскольку панель навигации необходима для навигации между действиями и приложениями. По умолчанию на панели навигации отображаются возможности «Назад» и «Домой». Это включается только в том случае, если целевой дисплей поддерживает системные украшения (см. DisplayWindowSettings ).

Строка состояния — более сложное системное окно, поскольку она также содержит панель уведомлений, быстрые настройки и экран блокировки. В Android 10 строка состояния не поддерживается на дополнительных дисплеях. Поэтому уведомления, настройки и полноценная клавиатура доступны только на основном дисплее.

Системное окно «Обзор/Последние» не поддерживается на дополнительных экранах. В Android 10 AOSP отображает только «Недавние» на дисплее по умолчанию и содержит действия со всех дисплеев. При запуске из «Недавних» действие, которое было на дополнительном дисплее, по умолчанию выводится на передний план этого дисплея. У этого подхода есть некоторые известные проблемы, например отсутствие немедленного обновления при появлении приложений на других экранах.

Выполнение

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

Компонент системного пользовательского интерфейса, поддерживающий многоэкранный режим (MD), должен обрабатывать следующие случаи:

  • Инициализация нескольких дисплеев при запуске
  • Отображение добавлено во время выполнения
  • Дисплей удален во время выполнения

Когда системный пользовательский интерфейс обнаруживает добавление дисплея перед WindowManager, это создает состояние гонки. Этого можно избежать, реализовав собственный обратный вызов из WindowManager в системный пользовательский интерфейс при добавлении дисплея вместо подписки на события DisplayManager .DisplayListener . Образец реализации см. в разделе CommandQueue.Callbacks#onDisplayReady для поддержки панели навигации и WallpaperManagerInternal#onDisplayReady для обоев.

Кроме того, Android 10 предоставляет следующие обновления:

  • Класс NavigationBarController управляет всеми функциями, специфичными для панелей навигации.
  • Чтобы просмотреть настроенную панель навигации, см. CarStatusBar .
  • TYPE_NAVIGATION_BAR больше не ограничивается одним экземпляром и может использоваться для каждого дисплея.
  • IWindowManager#hasNavigationBar() обновлен и теперь включает параметр displayId только для системного пользовательского интерфейса.

пусковая установка

В Android 10 каждый дисплей, настроенный для поддержки системных украшений, по умолчанию имеет выделенный домашний стек для действий средства запуска с типом WindowConfiguration#ACTIVITY_TYPE_HOME . Каждый дисплей использует отдельный экземпляр активности средства запуска.

Рис. 1. Пример запуска нескольких дисплеев для platform/development/samples/MultiDisplay

Большинство существующих программ запуска не поддерживают несколько экземпляров и не оптимизированы для экранов больших размеров. Кроме того, на дополнительных/внешних дисплеях часто ожидаются другие впечатления. Чтобы обеспечить выделенное действие для дополнительных экранов, Android 10 вводит категорию SECONDARY_HOME в фильтрах намерений. Экземпляры этого действия используются на всех дисплеях, поддерживающих системные украшения, по одному на каждый дисплей.

<activity>
    ...
    <intent-filter>
        <category android:name="android.intent.category.SECONDARY_HOME" />
        ...
    </intent-filter>
</activity>

У действия должен быть режим запуска, который не препятствует созданию нескольких экземпляров и должен адаптироваться к различным размерам экрана. Режим запуска не может быть singleInstance или singleTask .

Выполнение

В Android 10 RootActivityContainer#startHomeOnDisplay() автоматически выбирает нужный компонент и намерение в зависимости от дисплея, на котором запускается главный экран. RootActivityContainer#resolveSecondaryHomeActivity() содержит логику для поиска компонента активности средства запуска в зависимости от выбранного в данный момент средства запуска и при необходимости может использовать системное значение по умолчанию (см. ActivityTaskManagerService#getSecondaryHomeIntent() ).

Ограничения безопасности

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

Обои

В Android 10 (и более поздних версиях) обои поддерживаются на дополнительных дисплеях:

Рисунок 2. Живые обои на внутреннем (вверху) и внешнем дисплеях (внизу)

Разработчики могут объявить о поддержке функции обоев, указав android:supportsMultipleDisplays="true" в XML-определении WallpaperInfo . Разработчики обоев также должны загружать ресурсы, используя контекст отображения в WallpaperService.Engine#getDisplayContext() .

Платформа создает один экземпляр WallpaperService.Engine для каждого дисплея, поэтому каждый механизм имеет свою собственную поверхность и контекст отображения. Разработчику необходимо убедиться, что каждый движок может рисовать независимо, с разной частотой кадров, соблюдая VSYNC.

Выбор обоев для отдельных экранов

Android 10 не обеспечивает прямой поддержки платформы для выбора обоев для отдельных экранов. Для этого необходим стабильный идентификатор дисплея, чтобы сохранить настройки обоев для каждого дисплея. Display#getDisplayId() является динамическим, поэтому нет гарантии, что физический дисплей будет иметь тот же идентификатор после перезагрузки.

Однако в Android 10 добавлен DisplayInfo.mAddress , который содержит стабильные идентификаторы для физических дисплеев и может использоваться для полной реализации в будущем. К сожалению, реализовывать логику для Android 10 уже поздно. Предлагаемое решение:

  1. Используйте API WallpaperManager для установки обоев.
  2. WallpaperManager получается из объекта Context , и каждый объект Context содержит информацию о соответствующем дисплее ( Context#getDisplay()/getDisplayId() ). Таким образом, вы можете получить displayId из экземпляра WallpaperManager без добавления новых методов.
  3. На стороне платформы используйте displayId , полученный из объекта Context , и сопоставьте его со статическим идентификатором (например, портом физического дисплея). Используйте статический идентификатор, чтобы сохранить выбранные обои.

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

Если необходимо установить обои для дисплея, отличного от текущего дисплея, создайте новый объект Context для целевого дисплея ( Context#createDisplayContext ) и получите экземпляр WallpaperManager из этого дисплея.

Ограничения безопасности

Система не будет отображать обои на виртуальных дисплеях, которые ей не принадлежат. Это связано с соображениями безопасности, поскольку вредоносное приложение может создать виртуальный дисплей с включенной поддержкой системных украшений и считывать с поверхности конфиденциальную информацию пользователя (например, личную фотографию).

Выполнение

В Android 10 интерфейсы IWallpaperConnection#attachEngine() и IWallpaperService#attach() принимают параметр displayId для создания подключений для каждого дисплея. WallpaperManagerService.DisplayConnector инкапсулирует механизм обоев и соединение для каждого дисплея. В WindowManager контроллеры обоев создаются для каждого объекта DisplayContent при создании вместо одного WallpaperController для всех дисплеев.

Некоторые реализации общедоступных методов WallpaperManager (например, WallpaperManager#getDesiredMinimumWidth() ) были обновлены для вычисления и предоставления информации для соответствующих дисплеев. Были добавлены WallpaperInfo#supportsMultipleDisplays() и соответствующий атрибут ресурса, чтобы разработчики приложений могли сообщать, какие обои готовы для нескольких экранов.

Если служба обоев, отображаемая на дисплее по умолчанию, не поддерживает несколько дисплеев, система отображает обои по умолчанию на дополнительных дисплеях.

Рисунок 3. Логика возврата обоев для дополнительных дисплеев

,

Обновления, внесенные в эти области дисплея, представлены ниже:

Системные украшения

В Android 10 добавлена ​​поддержка настройки дополнительных дисплеев для отображения определенных системных украшений, таких как обои, панель навигации и панель запуска. По умолчанию на основном дисплее отображаются все системные украшения, а на дополнительных дисплеях — те, которые включены опционально. Поддержку редактора метода ввода (IME) можно настроить отдельно от других украшательств системы.

Используйте DisplayWindowSettings#setShouldShowSystemDecorsLocked() чтобы добавить поддержку системных украшений на определенном дисплее или указать значение по умолчанию в /data/system/display_settings.xml . Примеры см. в разделе Настройки окна отображения .

Выполнение

DisplayWindowSettings#setShouldShowSystemDecorsLocked() также доступен в WindowManager#setShouldShowSystemDecors() для тестирования. Запуск этого метода с целью включения системных декоров не добавляет отсутствующие ранее окна декора и не удаляет их, если они ранее присутствовали. В большинстве случаев поддержка смены системных украшений вступает в полную силу только после перезагрузки устройства.

Проверки поддержки системных украшений в базе кода WindowManager обычно выполняются через DisplayContent#supportsSystemDecorations() тогда как проверки внешних служб (например, системного пользовательского интерфейса для проверки необходимости отображения панели навигации) используют WindowManager#shouldShowSystemDecors() . Чтобы понять, чем управляет этот параметр, изучите точки вызова этих методов.

Окна оформления системного пользовательского интерфейса

В Android 10 добавлена ​​поддержка окон оформления системы только для панели навигации, поскольку панель навигации необходима для навигации между действиями и приложениями. По умолчанию на панели навигации отображаются возможности «Назад» и «Домой». Это включается только в том случае, если целевой дисплей поддерживает системные украшения (см. DisplayWindowSettings ).

Строка состояния — более сложное системное окно, поскольку она также содержит панель уведомлений, быстрые настройки и экран блокировки. В Android 10 строка состояния не поддерживается на дополнительных дисплеях. Поэтому уведомления, настройки и полноценная клавиатура доступны только на основном дисплее.

Системное окно «Обзор/Последние» не поддерживается на дополнительных экранах. В Android 10 AOSP отображает только «Недавние» на дисплее по умолчанию и содержит действия со всех дисплеев. При запуске из «Недавних» действие, которое было на дополнительном дисплее, по умолчанию выводится на передний план этого дисплея. У этого подхода есть некоторые известные проблемы, например отсутствие немедленного обновления при появлении приложений на других экранах.

Выполнение

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

Компонент системного пользовательского интерфейса, поддерживающий многоэкранный режим (MD), должен обрабатывать следующие случаи:

  • Инициализация нескольких дисплеев при запуске
  • Отображение добавлено во время выполнения
  • Дисплей удален во время выполнения

Когда системный пользовательский интерфейс обнаруживает добавление дисплея перед WindowManager, это создает состояние гонки. Этого можно избежать, реализовав собственный обратный вызов из WindowManager в системный пользовательский интерфейс при добавлении дисплея вместо подписки на события DisplayManager .DisplayListener . Для справочной реализации см. CommandQueue.Callbacks#onDisplayReady для поддержки навигационных баров и WallpaperManagerInternal#onDisplayReady для обоев.

Кроме того, Android 10 предоставляет эти обновления:

  • Класс NavigationBarController управляет всеми функциональными возможностями, специфичными для навигационных стержней.
  • Для просмотра индивидуальной навигационной панели см. CarStatusBar .
  • TYPE_NAVIGATION_BAR больше не ограничивается одним экземпляром и может использоваться для каждого дисплея.
  • IWindowManager#hasNavigationBar() обновляется, чтобы включить параметр displayId только для системного пользовательского интерфейса.

пусковая установка

В Android 10 каждый дисплей, настроенный для поддержки системных украшений, имеет выделенный домашний стек для действий запуска с типом WindowConfiguration#ACTIVITY_TYPE_HOME , по умолчанию. Каждый дисплей использует отдельный экземпляр активности пусковой установки.

Рисунок 1.. Пример запуска с несколькими динамиками для platform/development/samples/MultiDisplay

Большинство существующих пусковых установок не поддерживают несколько экземпляров и не оптимизированы для больших размеров экрана. Кроме того, на вторичных/внешних дисплеях часто ожидается другой вид опыта. Чтобы обеспечить выделенное занятие для вторичных экранов, Android 10 представляет категорию SECONDARY_HOME в фильтрах намерения. Экземпляры этой деятельности используются на всех дисплеях, которые поддерживают украшения системы, по одному на дисплей.

<activity>
    ...
    <intent-filter>
        <category android:name="android.intent.category.SECONDARY_HOME" />
        ...
    </intent-filter>
</activity>

Заявление должно иметь режим запуска, который не предотвращает несколько экземпляров и, как ожидается, будет адаптироваться к различным размерам экрана. Режим запуска не может быть singleInstance или singleTask .

Выполнение

В Android 10 RootActivityContainer#startHomeOnDisplay() автоматически выбирает желаемый компонент и намерения в зависимости от дисплея, где запускается домашний экран. RootActivityContainer#resolveSecondaryHomeActivity() содержит логику для поиска компонента активности запуска в зависимости от выбранной в настоящее время установки запуска и может использовать систему по умолчанию, если это необходимо (см. ActivityTaskManagerService#getSecondaryHomeIntent() ).

Ограничения безопасности

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

Обои

В Android 10 (и выше) обои поддерживаются на вторичных дисплеях:

Рисунок 2. Живые обои на внутренних (вверху) и внешних дисплеях (ниже)

Разработчики могут объявить поддержку функции обоев, предоставляя android:supportsMultipleDisplays="true" в определении xml WallpaperInfo . Ожидается, что разработчики обоев будут загружать активы, используя контекст дисплея в WallpaperService.Engine#getDisplayContext() .

Фреймворк создает один WallpaperService.Engine . Разработчик должен убедиться, что каждый двигатель может рисовать независимо, с разными частотами кадров, уважая VSYNC.

Выберите обои для отдельных экранов

Android 10 не предоставляет прямую поддержку платформы для выбора обоев для отдельных экранов. Для этого необходим стабильный идентификатор дисплея, чтобы сохранить настройки обоев на дисплей. Display#getDisplayId() является динамичным, поэтому нет никакой гарантии, что физический дисплей будет иметь такой же идентификатор после перезагрузки.

Тем не менее, Android 10 добавил DisplayInfo.mAddress , который содержит стабильные идентификаторы для физических дисплеев и может использоваться для полной реализации в будущем. К сожалению, уже слишком поздно реализовать логику для Android 10. Предлагаемое решение:

  1. Используйте API API WallpaperManager , чтобы установить обои.
  2. WallpaperManager получается из объекта Context , и у каждого объекта Context есть информация о соответствующем дисплее ( Context#getDisplay()/getDisplayId() ). Следовательно, вы можете получить displayId из экземпляра WallpaperManager , не добавляя новые методы.
  3. На стороне фреймворта используйте displayId , полученный из объекта Context , и сопоставьте его на статический идентификатор (например, порт физического дисплея). Используйте статический идентификатор, чтобы сохранить выбранные обои.

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

Если есть необходимость установить обои для дисплея, отличного от текущего дисплея, то создайте новый Context объект для Target Display ( Context#createDisplayContext ) и получите экземпляр WallpaperManager с этого дисплея.

Ограничения безопасности

Система не будет показывать обои на виртуальных дисплеях, которые она не владеет. Это связано с проблемой безопасности, что злонамеренное приложение может создать виртуальный дисплей с поддержкой поддержки системных украшений и прочитать пользовательную информацию с поверхности (например, личная фотография).

Выполнение

В Android 10 интерфейсы IWallpaperConnection#attachEngine() и IWallpaperService#attach() принимают параметр displayId для создания подключений для каждого диска. WallpaperManagerService.DisplayConnector инкапсулирует двигатель и соединение обоев для каждого диска. В Windowmanager контроллеры обоев создаются для каждого объекта DisplayContent на строительстве вместо одного WallpaperController для всех дисплеев.

Некоторые из публичных реализаций метода WallpaperManager (например, WallpaperManager#getDesiredMinimumWidth() ) были обновлены для вычисления и предоставления информации для соответствующих дисплеев. Были добавлены WallpaperInfo#supportsMultipleDisplays() и соответствующий атрибут ресурса, так что разработчики приложений могут сообщить, какие обои готовы к нескольким экранам.

Если услуга обоев, показанная на дисплее по умолчанию, не поддерживает несколько дисплеев, то система показывает обои по умолчанию на вторичных дисплеях.

Рисунок 3. Обои для вторичных дисплеев