Поддержка многооконного режима

Многооконный режим позволяет нескольким приложениям одновременно использовать один и тот же экран. Приложения могут располагаться рядом или одно над другим (режим разделенного экрана), одно приложение в небольшом окне, накладывающее другие приложения (режим «картинка в картинке»), или отдельные приложения в отдельных подвижных окнах с изменяемым размером (оконный режим рабочего стола). .

Рисунок 1. Отображение двух приложений рядом в режиме разделенного экрана.

Инструкции для пользователей о том, как получить доступ к режиму разделенного экрана на телефонах, см. в разделе «Просмотр двух приложений одновременно на телефоне Pixel» .

Многооконные функции, зависящие от версии

Работа пользователя с несколькими окнами зависит от версии Android и типа устройства:

  • В Android 7.0 (уровень API 24) появился режим разделения экрана на устройствах с маленьким экраном и режим «картинка в картинке» на некоторых устройствах.

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

    • Режим «картинка в картинке» позволяет пользователям продолжать воспроизведение видео во время взаимодействия с другим приложением (см. Поддержка «картинка в картинке» ).

    • Оконный режим рабочего стола , в котором пользователи могут свободно изменять размер каждого действия, может быть включен производителями устройств с большим экраном.

      Вы можете настроить, как ваше приложение будет обрабатывать многооконный режим, указав минимально допустимые размеры вашего действия. Вы также можете отключить многооконный режим для своего приложения, установив resizeableActivity="false" чтобы система всегда отображала ваше приложение в полноэкранном режиме.

  • Android 8.0 (уровень API 26) расширяет режим «картинка в картинке» на устройства с небольшим экраном.

  • Android 12 (уровень API 31) обеспечивает стандартное поведение многооконного режима.

    • На больших экранах (класс среднего или расширенного размера окна) платформа поддерживает все приложения в многооконном режиме независимо от конфигурации приложения. Если resizeableActivity="false" приложение переводится в режим совместимости, когда это необходимо для соответствия размерам дисплея.

    • На маленьких экранах (класс компактного размера окна) система проверяет minWidth и minHeight действия, чтобы определить, может ли действие выполняться в многооконном режиме. Если resizeableActivity="false" , приложение не сможет работать в многооконном режиме независимо от минимальной ширины и высоты.

Режим разделенного экрана

Пользователи активируют режим разделенного экрана, выполнив следующие действия:

  1. Откройте экран «Недавние»
  2. Проведите приложение в поле зрения
  3. Нажмите значок приложения в строке заголовка приложения.
  4. Выберите опцию меню разделенного экрана.
  5. Выберите другое приложение на экране «Последние» или закройте экран «Последние» и запустите другое приложение.

Пользователи выходят из режима разделения экрана, перетаскивая разделитель окна к краю экрана — вверх или вниз, влево или вправо.

Запустить соседний

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

FLAG_ACTIVITY_LAUNCH_ADJACENT был представлен в Android 7.0 (уровень API 24), чтобы позволить приложениям, работающим в режиме разделенного экрана, запускать действия в соседнем окне.

В Android 12L (уровень API 32) и более поздних версиях определение флага расширено, чтобы приложения, работающие в полноэкранном режиме, могли активировать режим разделенного экрана, а затем запускать действия в соседнем окне.

Чтобы запустить смежное действие, используйте FLAG_ACTIVITY_LAUNCH_ADJACENT в сочетании с FLAG_ACTIVITY_NEW_TASK , например:

Котлин

fun openUrlInAdjacentWindow(url:
String) { Intent(Intent.ACTION_VIEW).apply { data = Uri.parse(url)
addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT or Intent.FLAG_ACTIVITY_NEW_TASK)
 }.also { intent -> startActivity(intent) } }

Ява

public void openUrlInAdjacentWindow(String url) {
  Intent intent = new Intent(Intent.ACTION_VIEW);
  intent.setData(Uri.parse(url));
  intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
  startActivity(intent);
}

Жизненный цикл активности в многооконном режиме

Многооконный режим не меняет жизненный цикл активности . Однако возобновленное состояние приложений в нескольких окнах различается в разных версиях Android.

Мультирезюме

Android 10 (уровень API 29) и более поздние версии поддерживают несколько возобновлений — все действия остаются в состоянии RESUMED , когда устройство находится в многооконном режиме. Действие можно приостановить, если прозрачное действие находится поверх действия или действие не фокусируется, например, действие находится в режиме «картинка в картинке» . Также возможно, что в данный момент ни одно действие не имеет фокуса, например, если панель уведомлений открыта. Метод onStop() работает как обычно: метод вызывается каждый раз, когда действие удаляется с экрана.

Мультирезюме также доступно на некоторых устройствах под управлением Android 9 (уровень API 28). Чтобы включить множественное резюме на устройствах Android 9, добавьте следующие метаданные манифеста:

<meta-data android:name="android.allow_multiple_resumed_activities" android:value="true" />

Чтобы убедиться, что данное устройство поддерживает эти метаданные манифеста, обратитесь к спецификациям устройства.

Андроид 9

В многооконном режиме на Android 9 (уровень API 28) и более ранних версиях в данный момент времени активно только то действие, с которым пользователь взаимодействовал последним. Это действие считается самым верхним и единственным действием в состоянии RESUMED . Все остальные видимые действия STARTED , но НЕ RESUMED . Однако система придает этим видимым, но не возобновленным действиям более высокий приоритет, чем невидимым действиям. Если пользователь взаимодействует с одним из видимых действий, это действие возобновляется, а предыдущее самое верхнее действие переходит в состояние STARTED .

Если в одном активном процессе приложения выполняется несколько действий, действие с наивысшим z-порядком возобновляется, а остальные приостанавливаются.

Изменения конфигурации

Когда пользователь переводит приложение в многооконный режим, система уведомляет об изменении конфигурации, как указано в разделе «Обработка изменений конфигурации» . Это также происходит, когда пользователь изменяет размер приложения или переводит его обратно в полноэкранный режим.

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

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

Эксклюзивный доступ к ресурсам

Для поддержки функции множественного возобновления используйте обратный вызов жизненного цикла onTopResumedActivityChanged() .

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

Котлин

override fun
onTopResumedActivityChanged(topResumed: Boolean) { if (topResumed) { // Top
resumed activity. // Can be a signal to re-acquire exclusive resources. } else {
// No longer the top resumed activity. } }

Ява

@Override
public void onTopResumedActivityChanged(boolean topResumed) {
  if (topResumed) {
      // Top resumed activity.
      // Can be a signal to re-acquire exclusive resources.
  } else {
      // No longer the top resumed activity.
  }
}

Обратите внимание, что приложение может потерять ресурсы по другим причинам, например из-за удаления общего оборудования.

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

Для приложений, использующих камеру, CameraManager.AvailabilityCallback#onCameraAccessPrioritiesChanged() подсказывает, что, возможно, сейчас самое время попытаться получить доступ к камере. Этот метод доступен начиная с Android 10 (уровень API 29).

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

Рисунок 2. Камера в многооконном режиме.

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

После того как приложение получит обратный вызов CameraDevice.StateCallback#onDisconnected() , последующие вызовы на устройстве камеры вызовут исключение CameraAccessException .

Мультидисплей

Android 10 (уровень API 29) поддерживает действия на дополнительных дисплеях. Если действие выполняется на устройстве с несколькими дисплеями, пользователи могут перемещать действие с одного дисплея на другой. Мультирезюме применимо и к сценариям с несколькими экранами; несколько действий могут одновременно получать данные от пользователя.

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

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

Действие должно проверять текущее отображение в onCreate() и onConfigurationChanged() при обработке изменения конфигурации. Обязательно обновляйте ресурсы и макеты при изменении отображения.

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

Рисунок 3. Несколько экземпляров действия на нескольких дисплеях.

Вы также можете прочитать об API нескольких дисплеев , которые были представлены в Android 8.0.

Контекст активности и приложения

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

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

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

Котлин

val activityDisplay = activity.getDisplay()

Ява

Display activityDisplay = activity.getDisplay();

Получите текущие показатели окна активности:

Котлин

val windowMetrics = activity.getWindowManager().getCurrentWindowMetrics()

Ява

WindowMetrics windowMetrics = activity.getWindowManager().getCurrentWindowMetrics();

Получите максимальные показатели окна для текущей конфигурации системы:

Котлин

val maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics()

Ява

WindowMetrics maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics();

Максимальные метрики окна предназначены для проведения расчетов, выбора макета или определения размера ресурсов, которые необходимо получить заранее. Доступность этого в onCreate() позволяет вам принимать эти решения до первого прохода макета. Эти метрики не следует использовать для размещения определенных элементов представления; вместо этого используйте информацию из объекта Configuration .

Вырезы для дисплея

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

Вторичные дисплеи

Доступные дисплеи можно получить из системного сервиса DisplayManager :

Котлин

val displayManager =
getSystemService(Context.DISPLAY_SERVICE) as DisplayManager val displays =
displayManager.getDisplays()

Ява

DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
Display[] displays = displayManager.getDisplays();

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

Определите, может ли действие запускаться на дисплее:

Котлин

val activityManager =
getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val
activityAllowed = activityManager.isActivityStartAllowedOnDisplay(context,
displayId, intent)

Ява

ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
boolean activityAllowed = activityManager.isActivityStartAllowedOnDisplay(context, displayId, intent);

Затем запустите активность на дисплее:

Котлин

val options = ActivityOptions.makeBasic()
options.setLaunchDisplayId(targetDisplay.displayId) startActivity(intent,
options.toBundle())

Ява

ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(targetDisplay.displayId);
startActivity(intent, options.toBundle());

Поддержка нескольких дисплеев

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

Программная клавиатура

Клавиатура может отображаться на дополнительном экране, если дисплей настроен на поддержку системных украшений. Редактор метода ввода появляется автоматически, если текстовое поле требует ввода на этом дисплее.

Рисунок 4. Клавиатура на дополнительном дисплее.

Обои

В Android 10 (уровень API 29) на дополнительных экранах могут быть обои. Платформа создает отдельный экземпляр WallpaperService.Engine для каждого дисплея. Убедитесь, что поверхность каждого двигателя нарисована независимо. Разработчики могут загружать ресурсы, используя контекст отображения в WallpaperService.Engine#getDisplayContext() . Кроме того, убедитесь, что в вашем файле WallpaperInfo.xml установлен android:supportsMultipleDisplays="true" .

Рис. 5. Обои на телефоне и дополнительном дисплее.

пусковые установки

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

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

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

Например, реализация Launcher3 AOSP поддерживает действие SECONDARY_HOME .

Рисунок 6. Панель запуска Material Design на телефоне.
Рисунок 7. Панель запуска Material Design на дополнительном дисплее.

Метрики окна

В Android 11 (уровень API 30) представлены следующие методы WindowManager для определения границ приложений, работающих в многооконном режиме:

  • getCurrentWindowMetrics() : Возвращает объект WindowMetrics для текущего состояния окна системы.
  • getMaximumWindowMetrics() : возвращает WindowMetrics для самого большого потенциального состояния окна системы.

Методы библиотеки Jetpack WindowManager computeCurrentWindowMetrics() и computeMaximumWindowMetrics() предлагают аналогичную функциональность соответственно, но с обратной совместимостью с уровнем API 14.

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

  • Создайте контекст отображения
  • Создайте контекст окна для отображения
  • Получите WindowManager контекста окна.
  • Получите WindowMetrics максимальной области отображения, доступной приложению.

Котлин

val windowMetrics =
context.createDisplayContext(display)
.createWindowContext(WindowManager.LayoutParams.TYPE_APPLICATION, null)
.getSystemService(WindowManager::class.java) .maximumWindowMetrics

Ява

WindowMetrics windowMetrics = context.createDisplayContext(display)
                            .createWindowContext(WindowManager.LayoutParams.TYPE_APPLICATION, null)
                            .getSystemService(WindowManager.class)
                            .getMaximumWindowMetrics();

Устаревшие методы

Методы Display getSize() и getMetrics() устарели на уровне API 30 в пользу новых методов WindowManager .

В Android 12 (уровень API 31) устаревшие методы Display getRealSize() и getRealMetrics() и обновляются их поведение, чтобы более точно соответствовать поведению getMaximumWindowMetrics() .

Конфигурация многооконного режима

Если ваше приложение предназначено для Android 7.0 (уровень API 24) или выше, вы можете настроить, как и будут ли действия вашего приложения поддерживать многооконный режим. Вы можете установить атрибуты в своем манифесте, чтобы контролировать размер и макет. Настройки атрибутов корневого действия применяются ко всем действиям в его стеке задач. Например, если корневое действие имеет android:resizeableActivity="true" , ​​то все действия в стеке задач можно изменить. На некоторых более крупных устройствах, таких как Chromebook, ваше приложение может работать в окне изменяемого размера, даже если вы укажете android:resizeableActivity="false" . Если это повредит вашему приложению, вы можете использовать фильтры в Google Play, чтобы ограничить доступность вашего приложения на таких устройствах.

Android 12 (уровень API 31) по умолчанию использует многооконный режим. На больших экранах (класс среднего или расширенного размера окна) все приложения работают в многооконном режиме независимо от конфигурации приложения. На маленьких экранах система проверяет параметры действия minWidth , minHeight и resizeableActivity , чтобы определить, может ли действие выполняться в многооконном режиме.

resizeableActivity

Установите этот атрибут в элементе <activity> или <application> вашего манифеста, чтобы включить или отключить многооконный режим для уровня API 30 и ниже:

<application
  android:name=".MyActivity"
  android:resizeableActivity=["true" | "false"] />;

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

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

Если ваше приложение ориентировано на уровень API 31 или выше, этот атрибут работает по-разному на маленьких и больших экранах:

  • Большие экраны ( средний или расширенный класс размера окна): все приложения поддерживают многооконный режим. Атрибут указывает, можно ли изменить размер действия. Если resizeableActivity="false" , приложение переводится в режим совместимости, когда необходимо соответствовать размерам дисплея.
  • Маленькие экраны (класс компактного размера окна): если resizeableActivity="true" и минимальная ширина и минимальная высота действия находятся в пределах требований к многооконному режиму, действие поддерживает многооконный режим. Если resizeableActivity="false" , действие не поддерживает многооконный режим независимо от минимальной ширины и высоты действия.

supportsPictureInPicture

Установите этот атрибут в узле <activity> манифеста, чтобы указать, поддерживает ли действие режим «картинка в картинке».

<activity
  android:name=".MyActivity"
  android:supportsPictureInPicture=["true" | "false"] />

configChanges

Чтобы самостоятельно обрабатывать изменения многооконной конфигурации, например, когда пользователь изменяет размер окна, добавьте атрибут android:configChanges в узел <activity> манифеста вашего приложения как минимум со следующими значениями:

<activity
  android:name=".MyActivity"
  android:configChanges="screenSize | smallestScreenSize
      | screenLayout | orientation" />

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

<layout>

В Android 7.0 (уровень API 24) и более поздних версиях элемент манифеста <layout> поддерживает несколько атрибутов, влияющих на поведение действия в многооконном режиме:

  • android:defaultHeight , android:defaultWidth : высота и ширина активности по умолчанию при запуске в оконном режиме рабочего стола.

  • android:gravity : начальное размещение активности при запуске в оконном режиме рабочего стола. Подходящие значения см. в классе Gravity .

  • android:minHeight , android:minWidth : минимальная высота и минимальная ширина для действия как в оконном режиме разделенного экрана, так и на рабочем столе. Если пользователь перемещает разделитель в режиме разделенного экрана, чтобы сделать действие меньше указанного минимума, система обрезает действие до размера, запрошенного пользователем.

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

<activity android:name=".MyActivity">
    <layout android:defaultHeight="500dp"
          android:defaultWidth="600dp"
          android:gravity="top|end|..."
          android:minHeight="450dp"
          android:minWidth="300dp" />
</activity>

Многооконный режим во время выполнения

Начиная с Android 7.0, система предлагает функции поддержки приложений, которые могут работать в многооконном режиме.

Отключенные функции в многооконном режиме

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

Кроме того, некоторые параметры настройки пользовательского интерфейса системы отключены. Например, приложения не могут скрыть строку состояния, если они работают в многооконном режиме (см. Управление видимостью системного пользовательского интерфейса ).

Система игнорирует изменения атрибута android:screenOrientation .

Запросы и обратные вызовы в многооконном режиме

Класс Activity предлагает следующие методы для поддержки многооконного режима:

  • isInMultiWindowMode() : указывает, находится ли действие в многооконном режиме.

  • isInPictureInPictureMode() : указывает, находится ли действие в режиме «картинка в картинке».

  • onMultiWindowModeChanged() : система вызывает этот метод всякий раз, когда действие переходит в многооконный режим или выходит из него. Система передает методу значение true, если действие переходит в многооконный режим, или значение false, если действие выходит из многооконного режима.

  • onPictureInPictureModeChanged() : система вызывает этот метод всякий раз, когда действие переходит в режим «картинка в картинке» или выходит из него. Система передает методу значение true, если действие переходит в режим «картинка в картинке», или значение false, если действие выходит из режима «картинка в картинке».

Класс Fragment предоставляет версии многих из этих методов; например, Fragment.onMultiWindowModeChanged() .

Режим «картинка в картинке»

Чтобы перевести действие в режим «картинка в картинке», вызовите enterPictureInPictureMode() Этот метод не оказывает никакого эффекта, если устройство не поддерживает режим «картинка в картинке». Дополнительную информацию см. в разделе Добавление видео с помощью функции «картинка в картинке» (PiP) .

Новые действия в многооконном режиме

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

Если устройство находится в оконном режиме рабочего стола и вы запускаете новое действие, вы можете указать размеры нового действия и расположение экрана, вызвав ActivityOptions.setLaunchBounds() . Метод не имеет эффекта, если устройство не находится в многооконном режиме.

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

Android 12 (уровень API 31) позволяет приложениям разделять окно задач приложения на несколько действий. Вы определяете, как ваше приложение отображает свои действия — в полноэкранном режиме, рядом или в стопке — путем создания файла конфигурации XML или выполнения вызовов API Jetpack WindowManager.

Перетащите

Пользователи могут перетаскивать данные из одного действия в другое, пока эти два действия совместно используют экран. (До Android 7.0 пользователи могли перетаскивать данные только в пределах одного действия.) Чтобы быстро добавить поддержку приема удаленного контента, воспользуйтесь API DropHelper . Подробные инструкции по перетаскиванию см. в разделе Включение перетаскивания .

Мультиэкземплярность

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

Android 12 (уровень API 31) и выше позволяют запускать два экземпляра действия одновременно в одном окне задачи при внедрении действия .

Если вы хотите разрешить пользователям запускать другой экземпляр вашего приложения из средства запуска приложения или панели задач, установите android:resizeableActivity="true" в манифесте действия средства запуска и не используйте режим запуска , который предотвращает создание нескольких экземпляров. Например, действие singleInstancePerTask может быть создано несколько раз в разных задачах, если установлен FLAG_ACTIVITY_MULTIPLE_TASK или FLAG_ACTIVITY_NEW_DOCUMENT .

В Android 15 (уровень API 35) и более поздних версиях PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI позволяет объявить поддержку нескольких экземпляров. Это свойство является явным сигналом для системного пользовательского интерфейса о предоставлении пользователю элементов управления для создания нескольких экземпляров приложения. Свойство не зависит от режима запуска, но его следует использовать только в том случае, если режим запуска действия или приложения совместим со свойством, например, когда режим запуска не является singleInstance .

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

Проверка многооконного режима

Независимо от того, предназначено ли ваше приложение для уровня API 24 или выше, вам следует проверить, как оно ведет себя в многооконном режиме, если пользователь попытается запустить его в многооконном режиме на устройстве под управлением Android 7.0 или более поздней версии.

Тестовые устройства

Устройства под управлением Android 7.0 (уровень API 24) или более поздней версии поддерживают многооконный режим.

Уровень API 23 или ниже

Когда пользователи пытаются использовать приложение в многооконном режиме, система принудительно изменяет размер приложения, если приложение не декларирует фиксированную ориентацию.

Если ваше приложение не декларирует фиксированную ориентацию, вам следует запустить его на устройстве под управлением Android 7.0 или более поздней версии и попытаться перевести приложение в режим разделенного экрана. Убедитесь, что взаимодействие с пользователем приемлемо при принудительном изменении размера приложения.

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

Уровни API с 24 по 30

Если ваше приложение предназначено для уровней API с 24 по 30 и не отключает поддержку многооконности, проверьте следующее поведение как в оконном режиме разделенного экрана, так и в режиме рабочего стола:

  • Запустите приложение в полноэкранном режиме, затем переключитесь в многооконный режим, нажав и удерживая кнопку «Последние» . Убедитесь, что приложение переключается правильно.

  • Запустите приложение непосредственно в многооконном режиме и убедитесь, что приложение запускается правильно. Вы можете запустить приложение в многооконном режиме, нажав кнопку «Недавние» , затем нажав и удерживая строку заголовка приложения и перетащив ее в одну из выделенных областей на экране.

  • Измените размер приложения в режиме разделенного экрана, перетащив разделитель экрана. Убедитесь, что размер приложения изменяется без сбоев и что необходимые элементы пользовательского интерфейса видны.

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

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

Уровень API 31 или выше

Если ваше приложение ориентировано на уровень API 31 или выше, а минимальная ширина и минимальная высота основного действия меньше или равны соответствующим размерам доступной области отображения, проверьте все варианты поведения, перечисленные для уровней API с 24 по 30 .

Контрольный список испытаний

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

  • Вход и выход из многооконного режима.

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

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

  • Выполните несколько операций изменения размера в быстрой последовательности. Убедитесь, что ваше приложение не аварийно завершает работу и не вызывает утечки памяти. Профилировщик памяти Android Studio предоставляет информацию об использовании памяти вашим приложением (см. раздел Проверка использования памяти вашим приложением с помощью Memory Profiler ).

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

Поддержка нескольких окон отключена

На уровнях API с 24 по 30, если вы отключили поддержку нескольких окон, установив android:resizeableActivity="false" , вам следует запустить приложение на устройстве под управлением Android 7.0–11 и попытаться перевести приложение в режим разделения экрана и рабочего стола. режимы. Убедитесь, что при этом приложение остается в полноэкранном режиме.

Дополнительные ресурсы

Дополнительную информацию о поддержке многооконного режима в Android см.:

{% дословно %} {% дословно %}

Рекомендуется для вас * Примечание: текст ссылки отображается, когда JavaScript отключен * Режим совместимости устройств * Поддержка изменения размера большого экрана * Обработка изменений конфигурации

{% дословно %}
{% дословно %}