Предварительный просмотр камеры

Примечание. Эта страница относится к пакету Camera2 . Если вашему приложению не требуются специальные низкоуровневые функции Camera2, мы рекомендуем использовать CameraX . И CameraX, и Camera2 поддерживают Android 5.0 (уровень API 21) и выше.

Камеры и предварительный просмотр камер не всегда имеют одинаковую ориентацию на устройствах Android.

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

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

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

Ориентация камеры

В определении совместимости Android указано, что датчик изображения камеры «ДОЛЖЕН быть ориентирован таким образом, чтобы длинный размер камеры совпадал с длинным размером экрана. То есть, когда устройство удерживается в альбомной ориентации, камеры ДОЛЖНЫ захватывать изображения в альбомной ориентации. . Это применимо независимо от естественной ориентации устройства; то есть это относится как к устройствам с альбомной, так и с книжной ориентацией».

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

Датчик телефона и камеры в портретной ориентации.
Рисунок 1. Типичное соотношение ориентации сенсора телефона и камеры.

Естественная ориентация датчика камеры — альбомная. На рисунке 1 датчик фронтальной камеры (камера направлена ​​в том же направлении, что и дисплей) повернут на 270 градусов относительно телефона, чтобы соответствовать определению совместимости Android.

Чтобы показать приложениям вращение датчика, API camera2 включает константу SENSOR_ORIENTATION . Для большинства телефонов и планшетов устройство сообщает об ориентации датчика 270 градусов для фронтальных камер и 90 градусов (точка обзора с задней стороны устройства) для задних камер, что выравнивает длинный край датчика с длинный край устройства. Камеры ноутбуков обычно сообщают об ориентации датчика 0 или 180 градусов.

Поскольку датчики изображения камеры выводят свои данные (буфер изображения) в естественной ориентации датчика (альбомной ориентации), буфер изображения необходимо повернуть на количество градусов, указанное параметром SENSOR_ORIENTATION , чтобы предварительный просмотр камеры отображался вертикально в естественной ориентации устройства. Для фронтальных камер вращение происходит против часовой стрелки; для задних камер — по часовой стрелке.

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

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

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

Датчик камеры в портретной ориентации, изображение вертикально.

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

Поворот устройства

Поворот устройства — это количество градусов, на которое устройство повернуто от его естественной ориентации. Например, телефон в альбомной ориентации имеет поворот устройства на 90 или 270 градусов в зависимости от направления вращения.

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

Расчет ориентации

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

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

rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360

где sign равен 1 для фронтальных камер, -1 для задних камер.

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

Выражение deviceOrientationDegrees * sign + 360 преобразует поворот устройства с против часовой стрелки на поворот по часовой стрелке для камер, обращенных назад (например, преобразование 270 градусов против часовой стрелки в 90 градусов по часовой стрелке). Операция по модулю масштабирует результат до значения менее 360 градусов (например, масштабирование поворота с 540 градусов до 180).

Различные API сообщают о повороте устройства по-разному:

  • Display#getRotation() обеспечивает вращение устройства против часовой стрелки (с точки зрения пользователя). Это значение подставляется в приведенную выше формулу как есть.
  • OrientationEventListener#onOrientationChanged() возвращает вращение устройства по часовой стрелке (с точки зрения пользователя). Отмените значение для использования в формуле выше.

Фронтальные камеры

Предварительный просмотр камеры и сенсора в альбомной ориентации, сенсор расположен правой стороной вверх.
Рис. 2. Предварительный просмотр камеры и сенсора, когда телефон повернут на 90 градусов в альбомную ориентацию.

Вот буфер изображения, созданный датчиком камеры на рисунке 2:

Датчик камеры в альбомной ориентации, изображение вертикально.

Буфер необходимо повернуть на 270 градусов против часовой стрелки, чтобы отрегулировать ориентацию датчика (см. Ориентацию камеры выше):

Датчик камеры повёрнут в портретную ориентацию, изображение расположено сбоку, вверху справа.

Затем буфер поворачивается еще на 90 градусов против часовой стрелки, чтобы учесть вращение устройства, что приводит к правильной ориентации предварительного просмотра камеры на рисунке 2:

Датчик камеры повернут в альбомную ориентацию, а изображение вертикально.

Вот камера повернута вправо в альбомную ориентацию:

Предварительный просмотр камеры и сенсора в альбомной ориентации, но сенсор перевернут.
Рис. 3. Предварительный просмотр камеры и сенсора с телефоном, повернутым на 270 градусов (или -90 градусов) в альбомную ориентацию.

Вот буфер изображения:

Датчик камеры повернут в альбомную ориентацию, изображение перевернуто.

Буфер необходимо повернуть на 270 градусов против часовой стрелки, чтобы отрегулировать ориентацию датчика:

Датчик камеры рассчитан на портретную ориентацию, изображение расположено сбоку, вверху слева.

Затем буфер поворачивается еще на 270 градусов против часовой стрелки, чтобы учесть вращение устройства:

Датчик камеры повернут в альбомную ориентацию, а изображение вертикально.

Задние камеры

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

Предварительный просмотр камеры и сенсора в альбомной ориентации, но сенсор перевернут.
Рис. 4. Телефон с задней камерой в альбомной ориентации (повернут на 270 или -90 градусов).

Вот буфер изображения с сенсора камеры на рис. 4:

Датчик камеры повернут в альбомную ориентацию, изображение перевернуто.

Буфер необходимо повернуть на 90 градусов по часовой стрелке, чтобы отрегулировать ориентацию датчика:

Датчик камеры рассчитан на портретную ориентацию, изображение расположено сбоку, вверху слева.

Затем буфер поворачивается на 270 градусов против часовой стрелки, чтобы учесть вращение устройства:

Датчик камеры повернут в альбомную ориентацию, а изображение вертикально.

Соотношение сторон

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

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

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

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

На рисунке 5 приложение ошибочно предположило, что устройство повернуто на 90 градусов против часовой стрелки; и поэтому приложение повернуло предварительный просмотр на ту же величину.

Развернутое складное устройство с предварительным просмотром камеры в вертикальном положении, но сдавлено из-за неправильного масштабирования.
Рис. 6. Соотношение сторон складного устройства меняется с книжного на альбомное, но датчик камеры остается в портретной ориентации.

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

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

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

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

Встроенный портретный режим

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

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

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

Предварительный просмотр камеры и пользовательский интерфейс приложения в правильной портретной ориентации на ноутбуке.             Широкое изображение предварительного просмотра масштабируется и обрезается в соответствии с портретной ориентацией.
Рис. 8. Приложение портретной ориентации с фиксированной ориентацией в портретном режиме на ноутбуке.

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

Поворот, обрезка, масштабирование

Портретный режим «Вставка» вызывается для приложения камеры, предназначенного только для портретной ориентации, на дисплее с альбомным соотношением сторон:

Предварительный просмотр камеры на ноутбуке расположен вертикально, но пользовательский интерфейс приложения расположен сбоку.
Рис. 9. Приложение портретной ориентации с фиксированной ориентацией на ноутбуке.

Приложение расположено в почтовом ящике в книжной ориентации:

Приложение повернуто в портретную ориентацию и в почтовом ящике. Изображение сбоку, вверху справа.

Изображение с камеры поворачивается на 90 градусов для изменения ориентации приложения:

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

Изображение обрезается до соотношения сторон предварительного просмотра камеры, затем масштабируется до размера предварительного просмотра (поле обзора уменьшается):

Обрезанное изображение камеры масштабировано по размеру предварительного просмотра камеры.

На складных устройствах ориентация датчика камеры может быть книжной, а соотношение сторон дисплея — альбомной:

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

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

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

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

API

Начиная с Android 12 (уровень API 31), приложения также могут явно управлять вставленным портретным режимом с помощью свойства SCALER_ROTATE_AND_CROP класса CaptureRequest .

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

Не все устройства поддерживают все значения SCALER_ROTATE_AND_CROP . Чтобы получить список поддерживаемых значений, обратитесь к CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES .

КамераX

Библиотека Jetpack CameraX упрощает создание видоискателя камеры, который учитывает ориентацию датчика и вращение устройства.

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

Чтобы узнать основы создания предварительного просмотра камеры с помощью PreviewView , см. Реализация предварительного просмотра .

Полный пример реализации см. в репозитории CameraXBasic на GitHub.

КамераВидоискатель

Подобно варианту использования предварительного просмотра , библиотека CameraViewfinder предоставляет набор инструментов для упрощения создания предварительного просмотра камеры. Он не зависит от CameraX Core, поэтому вы можете легко интегрировать его в существующую кодовую базу Camera2.

Вместо непосредственного использования Surface вы можете использовать виджет CameraViewfinder для отображения изображения с камеры для Camera2.

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

Чтобы запросить поверхность у объекта CameraViewfinder , вам необходимо создать ViewfinderSurfaceRequest .

Этот запрос содержит требования к разрешению поверхности и информацию об устройстве камеры из CameraCharacteristics .

Вызов requestSurfaceAsync() отправляет запрос поставщику поверхности, который является либо TextureView , либо SurfaceView , и получает ListenableFuture Surface .

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

Котлин


fun startCamera(){
    val previewResolution = Size(width, height)
    val viewfinderSurfaceRequest =
        ViewfinderSurfaceRequest(previewResolution, characteristics)
    val surfaceListenableFuture =
        cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest)

    Futures.addCallback(surfaceListenableFuture, object : FutureCallback<Surface> {
        override fun onSuccess(surface: Surface) {
            /* create a CaptureSession using this surface as usual */
        }
        override fun onFailure(t: Throwable) { /* something went wrong */}
    }, ContextCompat.getMainExecutor(context))
}

Джава


    void startCamera(){
        Size previewResolution = new Size(width, height);
        ViewfinderSurfaceRequest viewfinderSurfaceRequest =
                new ViewfinderSurfaceRequest(previewResolution, characteristics);
        ListenableFuture<Surface> surfaceListenableFuture =
                cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest);

        Futures.addCallback(surfaceListenableFuture, new FutureCallback<Surface>() {
            @Override
            public void onSuccess(Surface result) {
                /* create a CaptureSession using this surface as usual */
            }
            @Override public void onFailure(Throwable t) { /* something went wrong */}
        },  ContextCompat.getMainExecutor(context));
    }

Поверхностное представление

SurfaceView — это простой подход к созданию предварительного просмотра с камеры, если предварительный просмотр не требует обработки и не анимирован.

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

Вы должны убедиться, что соотношение сторон буфера изображения соответствует соотношению сторон SurfaceView , чего можно добиться путем масштабирования содержимого SurfaceView в методе onMeasure() компонента:

(Исходный код computeRelativeRotation() приведен ниже в разделе «Относительное вращение» .)

Котлин

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    val width = MeasureSpec.getSize(widthMeasureSpec)
    val height = MeasureSpec.getSize(heightMeasureSpec)

    val relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees)

    if (previewWidth > 0f && previewHeight > 0f) {
        /* Scale factor required to scale the preview to its original size on the x-axis. */
        val scaleX =
            if (relativeRotation % 180 == 0) {
                width.toFloat() / previewWidth
            } else {
                width.toFloat() / previewHeight
            }
        /* Scale factor required to scale the preview to its original size on the y-axis. */
        val scaleY =
            if (relativeRotation % 180 == 0) {
                height.toFloat() / previewHeight
            } else {
                height.toFloat() / previewWidth
            }

        /* Scale factor required to fit the preview to the SurfaceView size. */
        val finalScale = min(scaleX, scaleY)

        setScaleX(1 / scaleX * finalScale)
        setScaleY(1 / scaleY * finalScale)
    }
    setMeasuredDimension(width, height)
}

Джава

@Override
void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);

    int relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees);

    if (previewWidth > 0f && previewHeight > 0f) {

        /* Scale factor required to scale the preview to its original size on the x-axis. */
        float scaleX = (relativeRotation % 180 == 0)
                       ? (float) width / previewWidth
                       : (float) width / previewHeight;

        /* Scale factor required to scale the preview to its original size on the y-axis. */
        float scaleY = (relativeRotation % 180 == 0)
                       ? (float) height / previewHeight
                       : (float) height / previewWidth;

        /* Scale factor required to fit the preview to the SurfaceView size. */
        float finalScale = Math.min(scaleX, scaleY);

        setScaleX(1 / scaleX * finalScale);
        setScaleY(1 / scaleY * finalScale);
    }
    setMeasuredDimension(width, height);
}

Дополнительные сведения о реализации SurfaceView в качестве предварительного просмотра камеры см. в разделе Ориентации камеры .

Просмотр текстуры

TextureView менее эффективен, чем SurfaceView , и требует больше работы, но TextureView дает вам максимальный контроль над предварительным просмотром с камеры.

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

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

Относительное вращение

Относительное вращение датчика камеры — это величина вращения, необходимая для выравнивания выходного сигнала датчика камеры с ориентацией устройства.

Относительное вращение используется такими компонентами, как SurfaceView и TextureView для определения коэффициентов масштабирования x и y для изображения предварительного просмотра. Он также используется для указания вращения буфера изображения датчика.

Классы CameraCharacteristics и Surface позволяют рассчитывать относительное вращение датчика камеры:

Котлин

/**
 * Computes rotation required to transform the camera sensor output orientation to the
 * device's current orientation in degrees.
 *
 * @param characteristics The CameraCharacteristics to query for the sensor orientation.
 * @param surfaceRotationDegrees The current device orientation as a Surface constant.
 * @return Relative rotation of the camera sensor output.
 */
public fun computeRelativeRotation(
    characteristics: CameraCharacteristics,
    surfaceRotationDegrees: Int
): Int {
    val sensorOrientationDegrees =
        characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)!!

    // Reverse device orientation for back-facing cameras.
    val sign = if (characteristics.get(CameraCharacteristics.LENS_FACING) ==
        CameraCharacteristics.LENS_FACING_FRONT
    ) 1 else -1

    // Calculate desired orientation relative to camera orientation to make
    // the image upright relative to the device orientation.
    return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360
}

Джава

/**
 * Computes rotation required to transform the camera sensor output orientation to the
 * device's current orientation in degrees.
 *
 * @param characteristics The CameraCharacteristics to query for the sensor orientation.
 * @param surfaceRotationDegrees The current device orientation as a Surface constant.
 * @return Relative rotation of the camera sensor output.
 */
public int computeRelativeRotation(
    CameraCharacteristics characteristics,
    int surfaceRotationDegrees
){
    Integer sensorOrientationDegrees =
        characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);

    // Reverse device orientation for back-facing cameras.
    int sign = characteristics.get(CameraCharacteristics.LENS_FACING) ==
        CameraCharacteristics.LENS_FACING_FRONT ? 1 : -1;

    // Calculate desired orientation relative to camera orientation to make
    // the image upright relative to the device orientation.
    return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360;
}

Метрики окна

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

WindowManager#getCurrentWindowMetrics() (добавлен на уровне API 30) возвращает размер окна приложения, а не размер экрана. Методы библиотеки Jetpack WindowManager WindowMetricsCalculator#computeCurrentWindowMetrics() и WindowInfoTracker#currentWindowMetrics() обеспечивают аналогичную поддержку с обратной совместимостью с уровнем API 14.

Вращение на 180 градусов

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

Чтобы обнаружить поворот на 180 градусов, реализуйте DisplayListener и проверьте поворот устройства с помощью вызова Display#getRotation() в обратном вызове onDisplayChanged() .

Эксклюзивные ресурсы

До Android 10 только самое верхнее видимое действие в многооконной среде находилось в состоянии RESUMED . Это сбивало пользователей с толку, поскольку система не указывала, какая деятельность была возобновлена.

В Android 10 (уровень API 29) появилось множественное возобновление, при котором все видимые действия находятся в состоянии RESUMED . Видимые действия по-прежнему могут переходить в состояние PAUSED , если, например, прозрачное действие находится поверх действия или действие не фокусируется, например, в режиме «картинка в картинке» (см. Поддержка «картинка в картинке» ).

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

Дополнительную информацию см. в разделе Мультирезюме .

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