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

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

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

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

Функции многооконного режима, зависящие от версии

Пользовательский интерфейс многооконного режима зависит от версии Android и типа устройства:

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

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

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

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

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

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

  • Android 12 (API уровня 31) делает многооконный режим стандартным поведением.

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

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

  • Android 16 (API уровня 36) переопределяет ограничения по ориентации экрана, соотношению сторон и изменению размера.

    • На больших экранах (минимальная ширина >= 600dp) система игнорирует атрибуты манифеста и API среды выполнения, используемые для ограничения ориентации, соотношения сторон и возможности изменения размера приложения, оптимизируя пользовательский интерфейс на всех форм-факторах устройств.

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

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

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

  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) }
}

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

Многооконный режим не изменяет жизненный цикл активности . Однако возобновленное состояние приложений в нескольких окнах отличается в разных версиях 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.
    }
}

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

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

Для приложений, использующих камеру, 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, которые используют информацию из контекста (например, см. Обзор тостов ).

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

val activityDisplay = activity.getDisplay()

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

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

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

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

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

Вырезы для отображения

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

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

Доступные дисплеи можно получить из системной службы DisplayManager :

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

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

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

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

Затем запустите действие на дисплее:

val 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 для задания границ приложений, работающих в многооконном режиме:

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

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

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

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

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

Методы 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" , приложение переводится в режим совместимости, когда это необходимо для соответствия размерам дисплея.
  • Маленькие экраны (класс размера окна compact ): Если resizeableActivity="true" и минимальная ширина и минимальная высота активности находятся в пределах требований к многоокну, активность поддерживает многооконный режим. Если resizeableActivity="false" , активность не поддерживает многооконный режим независимо от минимальной ширины и высоты активности.

Если ваше приложение нацелено на API уровня 36 или выше, этот атрибут игнорируется на дисплеях с наименьшей шириной >= 600dp. Однако приложение полностью уважает выбор соотношения сторон пользователем (см. Переопределения пользователя для каждого приложения ).

Если вы создаете игру, ознакомьтесь с разделом Ориентация приложения, соотношение сторон и возможность изменения размера, чтобы узнать, как исключить свою игру из изменений Android 16 (API уровня 36).

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 ваши activity и фрагменты получают обратный вызов 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 предоставляет информацию об использовании памяти вашим приложением (см. Проверка использования памяти вашим приложением с помощью Профилировщика памяти ).

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

Поддержка многооконного режима отключена

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

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

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

,

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

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

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

Функции с конкретными версиями многонароды

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

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

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

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

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

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

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

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

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

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

  • Android 16 (уровень API 36) переопределяет ориентацию экрана, соотношение сторон и ограничения рециртируемости.

    • На больших экранах (наименьшая ширина> = 600dp) система игнорирует манифестные атрибуты и API -интерфейсы времени выполнения, используемые для ограничения ориентации приложения, соотношения сторон и повторной оценки, оптимизируя пользовательский опыт на всех форм -факторах устройства.

      Чтобы узнать, как исключить игры из изменений Android 16, см. Ориентацию приложений, соотношение сторон и исключения измельчения .

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

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

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

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

Запуск рядом

Если вашему приложению необходимо получить доступ к контенту с помощью намерения, вы можете использовать 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) }
}

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

Режим мульти-окна не изменяет жизненный цикл активности . Тем не менее, возобновляемое состояние приложений в нескольких окнах отличается от разных версий Android.

Многолетуя

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

Multi-Resume также доступен на Select Devices, работающих на Android 9 (уровень API 28). Чтобы выбрать мульти-репутация на устройствах Android 9, добавьте следующие манифестные метаданные:

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

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

Android 9

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

Когда в рамках одного активного процесса приложения существует несколько действий, возобновляется активность с самым высоким Z-порядком, а другие приостановлены.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Многополучитель

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

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

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

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

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

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

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

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

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

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

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

val activityDisplay = activity.getDisplay()

Получите текущие метрики окна активности:

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

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

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

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

Отображение вырезов

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

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

Вы можете получить доступные дисплеи от службы системы DisplayManager :

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

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

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

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

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

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

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

Рисунок 6. Запуск материала на телефоне.
Рисунок 7. Запуск материала на вторичном дисплее.

Показатели окон

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

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

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

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

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

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

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

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

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

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

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

resizeableActivity

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

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

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

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

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

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

Если ваше приложение нацелено на уровень API 36 или выше, этот атрибут игнорируется на дисплеев с наименьшей шириной> = 600DP. Тем не менее, приложение полностью уважает выбор соотношения пользователя (см. Пользовательские переоценки для каждого приложения ).

Если вы создаете игру, см. Ориентацию приложений, соотношение сторон и повторную ошибку, чтобы узнать, как вы можете исключить свою игру из изменений Android 16 (уровень 36).

supportsPictureInPicture

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

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

configChanges

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

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

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

<layout>

На Android 7.0 (API-уровне 24) и выше, элемент MANIFEST <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, если деятельность вводит в режим мульти-Window или False, если действие покидает режим многоналиции.

  • onPictureInPictureModeChanged() : система вызывает этот метод всякий раз, когда деятельность входит в режим изображения в картине. Система передает метод значения True, если действие вводит в режим изображения в картинке или False, если деятельность оставляет режим изображения в картинке.

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

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

Чтобы поместить деятельность в режиме изображения в картинке, вызовите enterPictureInPictureMode() Этот метод не имеет никакого эффекта, если устройство не поддерживает режим изображения в картинке. Для получения дополнительной информации см. Добавить видео с помощью Picture-In-Picture (PIP) .

Новые виды деятельности в режиме с несколькими окнами

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

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

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

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

Перетащите и отпустите

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

Мульти-инстанция

Каждая корневая деятельность имеет свою собственную задачу, которая отображается в его собственном окне. Чтобы запустить новый экземпляр вашего приложения в отдельном окне, запустите новые действия с флагом 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 позволяет объявить поддержку многоконтрадации. Свойство является явным сигналом для пользовательского интерфейса System, чтобы предоставить пользователю элементы управления для создания нескольких экземпляров приложения. Свойство не зависит от режима запуска, но следует использовать только тогда, когда режим запуска для деятельности или приложения совместим со свойством, например, когда режим запуска не является singleInstance .

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

Проверка режима с несколькими окнами

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

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

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

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

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

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

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

Уровни API от 24 до 30

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

  • Запустите полный экран App, затем переключитесь на режим мульти-Window, продолжив кнопку Recents . Убедитесь, что приложение переключается должным образом.

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

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

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

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

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

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

Тестовый контрольный список

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

  • Введите и оставьте режим нескольких Window.

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

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

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

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

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

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

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

Для получения дополнительной информации о поддержке нескольких Window в Android см.