На этой странице публикуются обновления, связанные с показом рекламы.
Системные украшения
В Android 10 добавлена поддержка настройки дополнительных дисплеев для показа определенных системных элементов, таких как обои, панель навигации и панель запуска. По умолчанию на основном экране показываются все элементы интерфейса, а на дополнительных – только те, которые включены. Вы можете настроить поддержку редактора метода ввода (IME) отдельно от других элементов оформления системы.
Используйте DisplayWindowSettings#setShouldShowSystemDecorsLocked, чтобы добавить поддержку системных элементов оформления на определенном экране, или укажите значение по умолчанию в /data/system/display_settings.xml. Примеры можно найти в разделе Настройки окна.
В Android 17 и более поздних версиях поддержка системных элементов оформления может меняться динамически. Если у дисплея есть флаг FLAG_ALLOWS_CONTENT_MODE_SWITCH, система позволяет пользователю выбрать, будет ли на нем показываться контент из приложений или он будет дублировать другой дисплей. Система использует системные декорации, только если пользователь решает использовать дисплей для размещения приложений. Системные компоненты, такие как системный интерфейс и программы запуска OEM, отвечают за создание и показ системных декораций. Чтобы динамически добавлять или удалять системные декорации, а также инициализировать или освобождать структуры для каждого дисплея, эти компоненты должны зарегистрировать экземпляр IDisplayWindowListener и реализовать методы IDisplayWindowListener.onDisplayAddSystemDecorations и IDisplayWindowListener.onDisplayRemoveSystemDecorations.
IDisplayWindowListener – это скрытый API, доступный только системным компонентам.
Реализация
DisplayWindowSettings#setShouldShowSystemDecorsLocked также доступен в WindowManager#setShouldShowSystemDecors для тестирования. Вызов этого метода с целью включить системные элементы оформления не добавляет отсутствующие окна оформления и не удаляет существующие. В большинстве случаев изменение поддержки системных декораций вступает в силу только после перезагрузки устройства.
Проверки поддержки системных декораций в базе кода WindowManager обычно выполняются через DisplayContent#supportsSystemDecorations, а проверки внешних сервисов (например, интерфейса системы для определения того, нужно ли показывать панель навигации) – через WindowManager#shouldShowSystemDecors.
Чтобы понять, что контролируется этой настройкой, изучите точки вызова этих методов.
Декоративные окна системного интерфейса
В Android 10 добавлена поддержка системного окна декора для панели навигации, поскольку она необходима для перехода между объектами activity и приложениями. По умолчанию на панели навигации есть кнопки "Назад" и "Главный экран". Панель навигации включается, только если целевой дисплей поддерживает системные декорации (см. DisplayWindowSettings).
Строка состояния – более сложная системная область, поскольку она также содержит панель уведомлений, быстрые настройки и заблокированный экран. В Android 10 строка состояния не поддерживается на дополнительных экранах. Поэтому уведомления, настройки и полная блокировка клавиатуры доступны только на основном экране.
Системное окно Обзоры или Недавние не поддерживается на дополнительных экранах. В Android 10 AOSP показывает список недавно использованных приложений только на экране по умолчанию. В него входят действия со всех экранов. Если запустить из раздела "Недавние" действие, которое выполнялось на дополнительном экране, оно по умолчанию будет показано на этом экране. У этого подхода есть известные проблемы, например он не позволяет сразу обновлять информацию, когда приложения появляются на других экранах.
Реализация
Чтобы реализовать дополнительные функции системного интерфейса, производители устройств должны использовать один компонент системного интерфейса, который отслеживает добавление или удаление дисплеев и показывает подходящий контент.
Компонент системного интерфейса, поддерживающий многоэкранный режим, должен обрабатывать следующие случаи:
- Инициализация нескольких дисплеев при запуске
- Дисплей добавлен во время выполнения
- Дисплей удален во время выполнения
Если интерфейс системы обнаруживает добавление дисплея раньше, чем WindowManager, возникает состояние гонки. Чтобы избежать этого, реализуйте пользовательский обратный вызов из WindowManager в интерфейс системы при добавлении дисплея вместо подписки на события DisplayManager.DisplayListener. Примеры реализации можно найти в CommandQueue.Callbacks#onDisplayAddSystemDecorations (поддержка панели навигации) и WallpaperManagerInternal#onDisplayAddSystemDecorations (обои).
Кроме того, в Android 10 есть следующие изменения:
- Класс
NavigationBarControllerуправляет всеми функциями, связанными с панелями навигации. - Чтобы посмотреть, как выглядит настраиваемая панель навигации, перейдите к разделу
CarStatusBar. TYPE_NAVIGATION_BARбольше не ограничивается одним экземпляром и может использоваться для каждого дисплея.- Атрибут
IWindowManager#hasNavigationBarобновлен и теперь включает параметрdisplayIdтолько для системного интерфейса.
Панель запуска
В Android 10 у каждого экрана, настроенного на поддержку системных декораций, есть собственный стек главного экрана для действий запуска с типом WindowConfiguration#ACTIVITY_TYPE_HOME по умолчанию. Для каждого экрана используется отдельный экземпляр действия запуска:


Рисунок 1. Пример запуска приложения для нескольких экранов для платформы/разработки/примеров/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 для каждого экрана, поэтому у каждого движка есть собственная поверхность и контекст экрана. Разработчику необходимо убедиться, что каждый движок может отрисовывать изображение независимо, с разной частотой кадров, соблюдая вертикальную синхронизацию.
Как выбрать обои для отдельных экранов
В Android 10 нет встроенной поддержки выбора обоев для отдельных экранов. Для этого нужен постоянный идентификатор экрана, чтобы сохранять настройки обоев для каждого экрана.
Display#getDisplayId – динамический идентификатор, поэтому нет гарантии, что после перезагрузки физический дисплей будет иметь тот же идентификатор.
Однако в Android 10 был добавлен DisplayInfo.mAddress, который содержит стабильные идентификаторы для физических дисплеев и может быть использован для полной реализации в будущем. К сожалению, реализовать логику для Android 10 уже нельзя. Рекомендуемое решение:
- Используйте класс
WallpaperManager, чтобы задать обои.WallpaperManagerполучается из объектаContext, а каждый объектContextсодержит информацию о соответствующем дисплее (Context#getDisplay/getDisplayId). Таким образом, вы можете получитьdisplayIdиз экземпляраWallpaperManager, не добавляя новые методы. - На стороне фреймворка используйте
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 и более поздних версиях (API 29) разработчики могут использовать атрибут android:supportsMultipleDisplays, чтобы указать, можно ли использовать обои на нескольких экранах. В многооконном режиме, когда пользователь выполняет множество задач одновременно, отрисовка живых обоев на внешних дисплеях может значительно увеличить нагрузку на графический процессор и память.
Чтобы экономить ресурсы системы, живые обои на подключенных дисплеях по умолчанию не показываются. Если живые обои ограничены конфигурацией системы или манифестом приложения, система отображает резервные статические обои.
Производители оригинального оборудования могут настроить эту функцию, включив поддержку живых обоев для высокопроизводительного оборудования или настроив статическое резервное изображение для фирменного оформления.
Если ваше оборудование может отображать несколько экземпляров живых обоев, переопределите следующую конфигурацию:
| Путь к ресурсу | frameworks/base/core/res/res/values/config.xml |
|---|---|
| Название конфигурации | config_isLiveWallpaperSupportedInDesktopExperience |
Как настроить резервные обои
Если живые обои отключены или не поддерживаются поставщиком, система использует компонент по умолчанию. Вы можете указать собственный поставщик статических обоев:
| Путь к ресурсу | frameworks/base/core/res/res/values/config.xml |
|---|---|
| Название конфигурации | fallback_wallpaper_component |
Как реализовать поддержку обоев
Чтобы применить эти изменения, используйте наложение ресурсов во время сборки в папке, относящейся к определенному устройству (обычно device/<vendor>/<product>/overlay/frameworks/base/core/res/res/values/).