Vista previa de cámara

Nota: Esta página hace referencia al paquete Camera2. A menos que la app requiera funciones específicas y de bajo nivel de Camera2, te recomendamos que uses CameraX. CameraX y Camera2 admiten Android 5.0 (nivel de API 21) y versiones posteriores.

Las cámaras y las vistas previas de la cámara no siempre tienen la misma orientación en los dispositivos Android.

Una cámara está en una posición fija en un dispositivo, independientemente de si se trata de un teléfono, una tablet o una computadora. Cuando cambia la orientación del dispositivo, el que cambie la orientación de la cámara.

Como resultado, las apps de cámara suelen suponer una relación fija entre la orientación del dispositivo y la relación de aspecto de la vista previa de la cámara. Cuando un teléfono está en orientación vertical, se supone que la vista previa de la cámara es más alta que ancha. Cuando el teléfono (y la cámara) se rotan a la posición horizontal, el Se espera que la vista previa de la cámara sea más ancha que alta.

Sin embargo, estas suposiciones se ven desafiadas por nuevos factores de forma, como los dispositivos plegables, y modos de visualización, como multiventana y multipantalla. Los dispositivos plegables cambian el tamaño de la pantalla y la relación de aspecto sin cambiar orientación. El modo multiventana restringe las apps de cámara a una parte de la y ajustar la vista previa de la cámara, independientemente de la orientación del dispositivo. El modo de varias pantallas permite el uso de pantallas secundarias que podrían no tener estar en la misma orientación que la pantalla principal.

Orientación de la cámara

La definición de compatibilidad de Android especifica que un sensor de imagen de la cámara "SE DEBE orientar para que la dimensión larga de la cámara se alinee con la dimensión larga de la pantalla". Es decir, cuando el dispositivo se sostiene en orientación horizontal, las cámaras DEBEN capturar imágenes en orientación horizontal. Esto se aplica independientemente de la orientación natural del dispositivo, es decir, a los dispositivos con orientación horizontal principal y a los dispositivos con orientación vertical principal".

La disposición de cámara a pantalla maximiza el área de visualización de la cámara visor en una app de cámara. Además, los sensores de imagen suelen generar sus datos relaciones de aspecto horizontales, 4:3 es la más común.

El teléfono y el sensor de la cámara están en orientación vertical.
Figura 1: Relación típica de la orientación del sensor del teléfono y la cámara.

La orientación natural del sensor de la cámara es horizontal. En la figura 1, el sensor de la cámara frontal (la cámara apunta en la misma dirección que el pantalla) se rote 270 grados con relación al teléfono para cumplir con la Definición de compatibilidad de Android.

Para exponer la rotación del sensor a las apps, el La API de camera2 incluye una SENSOR_ORIENTATION constante. En la mayoría de los teléfonos y tablets, el dispositivo informa la orientación de un sensor. de 270 grados para las cámaras frontales y de 90 grados (punto de vista desde la parte posterior del dispositivo) para las cámaras traseras, que alinea el borde largo de la con el borde largo del dispositivo. Por lo general, las cámaras de las laptops informan una orientación del sensor de 0 o 180 grados.

Debido a que los sensores de imagen de la cámara generan datos (un búfer de imagen) en la en la orientación natural del sensor (horizontal), el búfer de imagen se debe rotar la cantidad de grados especificados por SENSOR_ORIENTATION para la vista previa de la cámara en aparezcan en posición vertical en la orientación natural del dispositivo. En el caso de las cámaras frontales, la rotación es en el sentido contrario a las manecillas del reloj; para las cámaras posteriores, en el sentido de las manecillas del reloj.

Por ejemplo, en el caso de la cámara frontal de la Figura 1, el búfer de imagen que produce el sensor de la cámara se ve de la siguiente manera:

Se rotó el sensor de la cámara a la orientación horizontal con la imagen
            hacia un lado, en la parte superior izquierda.

La imagen se debe girar 270 grados a la izquierda para que la vista previa la orientación coincide con la del dispositivo:

Sensor de cámara en orientación vertical con imagen vertical.

Una cámara posterior produciría un búfer de imagen con la misma orientación. que el búfer anterior, pero SENSOR_ORIENTATION es de 90 grados. Como resultado, el búfer se rota 90 grados en el sentido de las manecillas del reloj.

Rotación del dispositivo

La rotación del dispositivo es la cantidad de grados en los que se rota un dispositivo respecto de su rotación natural orientación. Por ejemplo, un teléfono en orientación horizontal tiene un dispositivo de 90 o 270 grados, según la dirección de rotación.

Un búfer de imagen del sensor de la cámara se debe rotar la misma cantidad de grados que el de rotación del dispositivo (además de los grados de orientación del sensor) para la que la vista previa de la cámara se vea en posición vertical.

Cálculo de la orientación

La orientación adecuada de la vista previa de la cámara tiene en cuenta la orientación del sensor y la rotación del dispositivo.

La rotación general del búfer de imágenes del sensor se puede calcular con la siguiente fórmula:

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

donde sign es 1 para las cámaras frontales y -1 para las cámaras posteriores.

Para las cámaras frontales, el búfer de imagen se rota en sentido contrario a las manecillas del reloj (desde la orientación natural del sensor). En el caso de las cámaras posteriores, el búfer de imágenes del sensor se rota en el sentido de las manecillas del reloj.

La expresión deviceOrientationDegrees * sign + 360 convierte la rotación del dispositivo. de las manecillas del reloj a las manecillas del reloj para las cámaras traseras (por ejemplo, convirtiendo 270 grados en sentido antihorario a 90 grados en el sentido de las manecillas del reloj). La operación modulo ajusta el resultado a menos de 360 grados (por ejemplo, ajusta 540 grados de rotación a 180).

Las diferentes APIs informan la rotación del dispositivo de manera diferente:

  • Display#getRotation() Proporciona la rotación del dispositivo en el sentido contrario a las manecillas del reloj (desde el punto del usuario visual). Este valor se inserta en la fórmula anterior tal como está.
  • OrientationEventListener#onOrientationChanged() muestra la rotación en el sentido de las manecillas del reloj del dispositivo (desde el punto de vista del usuario). Negar el valor que se usará en la fórmula anterior

Cámaras frontales

Vista previa de la cámara y sensor en orientación horizontal, el sensor está hacia arriba.
Figura 2: Vista previa y sensor de la cámara con el teléfono girado 90 grados en orientación horizontal.

En la figura 2, se muestra el búfer de imagen producido por el sensor de la cámara:

Sensor de la cámara en orientación horizontal con imagen en posición vertical.

El búfer se debe girar 270 grados en sentido antihorario para ajustarse al sensor. orientación (consulta Orientación de la cámara más arriba):

Sensor de la cámara girado a la orientación vertical con la imagen lateral, en la parte superior derecha.

Luego, el búfer se rota 90 grados adicionales en sentido antihorario para tienen en cuenta la rotación del dispositivo, lo que da como resultado la orientación correcta de la vista previa de la cámara en la figura 2:

Se rotó el sensor de la cámara a la orientación horizontal con la imagen
            en posición vertical.

Aquí está la cámara girada hacia la derecha a la orientación horizontal:

La vista previa y el sensor de la cámara están en orientación horizontal, pero el sensor está al revés.
Figura 3: Vista previa de la cámara y sensor con el teléfono girado a 270 grados (o -90 grados) a la orientación horizontal.

Este es el búfer de imagen:

Se rotó el sensor de la cámara a la orientación horizontal con la imagen invertida
            fuera de servicio.

El búfer debe girarse 270 grados en sentido contrario a las manecillas del reloj para ajustarse a la orientación del sensor:

Sensor de cámara con clasificación para orientación vertical con imagen lateral, esquina superior izquierda.

Luego, el búfer se rota otros 270 grados en sentido contrario a las manecillas del reloj para tener en cuenta la rotación del dispositivo:

Sensor de la cámara girado a la orientación horizontal con la imagen vertical

Cámaras posteriores

Por lo general, las cámaras posteriores tienen una orientación del sensor de 90 grados (como se ve desde la parte posterior del dispositivo). Cuando se orienta la vista previa de la cámara, el búfer de imagen del sensor se rota en el sentido de las manecillas del reloj por la cantidad de rotación del sensor (en lugar de hacerlo en sentido contrario a las manecillas del reloj como las cámaras frontales) y, luego, el búfer de imagen se rota en sentido contrario a las manecillas del reloj por la cantidad de rotación del dispositivo.

La vista previa de la cámara y el sensor están en orientación horizontal, pero
            que el sensor esté invertido.
Figura 4: Teléfono con cámara posterior en orientación horizontal (girado a 270 o -90 grados).

Este es el búfer de imagen del sensor de la cámara en la Figura 4:

Se rotó el sensor de la cámara a la orientación horizontal con la imagen invertida
            fuera de servicio.

El búfer se debe rotar 90 grados en el sentido de las manecillas del reloj para ajustarse al sensor orientación:

Sensor de cámara clasificado para orientación vertical con imagen girada,
            en la parte superior izquierda.

Luego, el búfer se rota 270 grados en sentido contrario a las manecillas del reloj para tener en cuenta el dispositivo. rotación:

Sensor de la cámara girado a la orientación horizontal con la imagen vertical

Relación de aspecto

La relación de aspecto de la pantalla cambia cuando cambia la orientación del dispositivo, pero también cuando se pliegan y despliegan los dispositivos plegables, cuando se cambia el tamaño de las ventanas en entornos multiventana y cuando se abren apps en pantallas secundarias.

El búfer de imágenes del sensor de la cámara debe estar orientado y ajustado para que coincida con la orientación y la relación de aspecto del elemento de la IU del visor a medida que la IU cambia de orientación de forma dinámica, con o sin que el dispositivo cambie de orientación.

En factores de forma nuevos o en entornos de varias ventanas o varias pantallas, si tu app supone que la vista previa de la cámara tiene la misma orientación que el dispositivo (vertical u horizontal), es posible que la vista previa esté orientada o ajustada de forma incorrecta, o ambas.

Dispositivo plegable desplegado con vista previa de la cámara vertical girada hacia un lado.
Figura 5: El dispositivo plegable pasa de la relación de aspecto vertical a la horizontal, pero el sensor de la cámara permanece en orientación vertical.

En la figura 5, la aplicación supone erróneamente que el dispositivo se rotó 90 grados en el sentido contrario a las manecillas del reloj; Por lo tanto, la app giró la vista previa del mismo modo.

Dispositivo plegable desplegado con la vista previa de la cámara en posición vertical, pero aplastado
            debido al escalamiento incorrecto.
Figura 6: Transiciones de dispositivos plegables de vertical a horizontal relación de aspecto, pero el sensor de la cámara permanece en orientación vertical.

En la figura 6, la app no ajustó la relación de aspecto del búfer de imagen a permitir que se ajuste de forma adecuada para que se adapte a las nuevas dimensiones de la IU de vista previa de la cámara .

Las apps de cámara con orientación fija suelen tener problemas en dispositivos plegables y otros dispositivos con pantallas grandes, como laptops:

La vista previa de la cámara en la laptop está vertical, pero la IU de la app está lateral.
Figura 7: App vertical con orientación fija en una laptop

En la figura 7, la IU de la app de cámara es lateral porque la orientación de la app está restringido al modo vertical. La imagen del visor está orientada correctamente en relación con el sensor de la cámara.

Modo Retrato con enmarcado

Apps de cámara que no admiten el modo multiventana (resizeableActivity="false") y restringir su orientación (screenOrientation="portrait") o screenOrientation="landscape") se puede colocar en modo vertical insertado en dispositivos con pantalla grande para orientar correctamente la vista previa de la cámara.

El modo vertical con formato letterbox (insertos) muestra apps solo en orientación vertical, aunque la relación de aspecto de la pantalla sea horizontal. Las apps que solo funcionan con formato horizontal tienen formato letterbox en orientación horizontal aunque la relación de aspecto de la pantalla sea vertical. Se rota la imagen de la cámara para alinearla con la IU de la app, recortada para que coincida con la relación de aspecto de la vista previa de la cámara y, luego, ajustarlo para llenar la vista previa.

El modo Retrato insertado se activa cuando la relación de aspecto de la imagen de la cámara y la relación de aspecto de la actividad principal de la aplicación no coinciden.

Vista previa de la cámara e IU de la app en orientación vertical adecuada en una laptop.
            La imagen de vista previa ancha se ajusta y se recorta para ajustarse al modo vertical
            orientación.
Figura 8: App vertical con orientación fija en modo vertical con inserción activado en una laptop.

En la figura 8, se rotó la app de cámara solo con orientación vertical para mostrar la IU. en posición vertical en la pantalla de la laptop. La app tiene formato letterbox debido a la diferencia en la relación de aspecto entre la app vertical y la pantalla horizontal. La cámara se rotó la imagen de vista previa para compensar la rotación de la IU de la app (debido a modo vertical de inserción), y la imagen se recortó y ajustó para adaptarla al con orientación vertical, lo que reduce el campo visual.

Rotar, recortar y escalar

Se invoca el modo vertical de inserción para una app de cámara solo con modo vertical en una pantalla. que tiene una relación de aspecto horizontal:

La vista previa de la cámara de la laptop es vertical, pero la IU de la app está girada.
Figura 9: App con orientación vertical fija en una laptop.

La app tiene formato letterbox en orientación vertical:

Se rotó la app a la orientación vertical y al formato letterbox. La imagen está de lado, de arriba a la derecha.

La imagen de la cámara se rota 90 grados para ajustarse a la reorientación de la app:

Imagen del sensor girada 90 grados para que quede en posición vertical

La imagen se recorta según la relación de aspecto de la vista previa de la cámara y, luego, se ajusta a rellenar la vista previa (se reduce el campo visual):

Imagen recortada de la cámara ajustada para llenar la vista previa de la cámara.

En los dispositivos plegables, la orientación del sensor de la cámara puede ser vertical mientras que la relación de aspecto de la pantalla es horizontal:

La vista previa de la cámara y la IU de la app están giradas hacia un lado de la pantalla ancha y desplegada.
Figura 10: Dispositivo desplegado con la app de cámara solo vertical y diferentes relaciones de aspecto del sensor de la cámara y la pantalla.

Debido a que la vista previa de la cámara se rota para ajustarse a la orientación del sensor, la imagen está orientada correctamente en el visor, pero la app solo vertical está de lado.

El modo vertical para inserción solo necesita aplicar formato letterbox a la app en orientación vertical. para orientar correctamente la app y la vista previa de la cámara:

App con formato letterbox en orientación vertical con vista previa de la cámara en posición vertical en un dispositivo plegable

API

A partir de Android 12 (nivel de API 31), las apps también pueden controlar de forma explícita el modo vertical intercalado a través de la propiedad SCALER_ROTATE_AND_CROP de la clase CaptureRequest.

El valor predeterminado es SCALER_ROTATE_AND_CROP_AUTO, que permite que el sistema invoque el modo vertical intercalado. SCALER_ROTATE_AND_CROP_90 es el comportamiento del modo vertical intercalado, como se describió anteriormente.

No todos los dispositivos admiten todos los valores de SCALER_ROTATE_AND_CROP. Para obtener una lista de los valores admitidos, consulta CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES.

CameraX

La biblioteca de Jetpack CameraX permite crear un visor de cámara que se adapta a la orientación de los sensores y rotación del dispositivo es una tarea sencilla.

El elemento de diseño PreviewView crea una vista previa de la cámara y se ajusta automáticamente según la orientación del sensor. la rotación y el escalamiento del dispositivo. PreviewView mantiene la relación de aspecto de la imagen de la cámara aplicando el FILL_CENTER tipo de escala, que centra la imagen, pero podría recortarla para que coincida con las dimensiones de la PreviewView. Para aplicar el formato letterbox a la imagen de la cámara, establece el tipo de escala en FIT_CENTER.

Para aprender los conceptos básicos de la creación de una vista previa de la cámara con PreviewView, consulta Implementa una vista previa.

Para ver una implementación de muestra completa, consulta la CameraXBasic en un repositorio de GitHub.

CameraViewfinder

Al igual que en el caso de uso de Preview, el CameraViewfinder proporciona un conjunto de herramientas para simplificar la creación de una vista previa de la cámara. No depende de CameraX Core, por lo que puedes integrarlo sin problemas en tu base de código de Camera2 existente.

En lugar de usar Surface directamente, puedes usar el widget CameraViewfinder para mostrar el feed de la cámara de Camera2.

CameraViewfinder usa internamente un TextureView o un SurfaceView para mostrar el feed de la cámara y aplica las transformaciones requeridas en ellos para mostrar correctamente el visor. Esto implica corregir su relación de aspecto, escala y rotación.

Para solicitar la superficie del objeto CameraViewfinder, debes hacer lo siguiente: crea un ViewfinderSurfaceRequest.

Esta solicitud contiene requisitos para la resolución de la superficie y la información del dispositivo de la cámara de CameraCharacteristics.

Llamando a requestSurfaceAsync() envía la solicitud al proveedor de superficie, que es un TextureView o SurfaceView y obtiene un ListenableFuture de Surface.

Llamando a markSurfaceSafeToRelease() notifica al proveedor de superficies que la superficie no es necesaria y está relacionada se pueden liberar recursos.

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 es un enfoque directo para crear una vista previa de la cámara si esta no requieren procesamiento y no están animadas.

SurfaceView rota automáticamente el búfer de imágenes del sensor de la cámara para que coincida con la orientación de la pantalla, teniendo en cuenta la orientación del sensor y la rotación del dispositivo. Sin embargo, el búfer de imagen se ajusta para adaptarse a SurfaceView dimensiones sin considerar la relación de aspecto.

Debes asegurarte de que la relación de aspecto del búfer de imagen coincida con la relación de aspecto de SurfaceView, lo que puedes lograr ajustando el contenido de SurfaceView en el método onMeasure() del componente:

(El código fuente de computeRelativeRotation() se encuentra en Rotación relativa a continuación).

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

Para obtener más detalles sobre la implementación de SurfaceView como vista previa de la cámara, consulta Orientaciones de la cámara.

TextureView

TextureView tiene un rendimiento inferior al de SurfaceView y requiere más trabajo, pero TextureView te brinda el máximo control de la vista previa de la cámara.

TextureView rota el búfer de imágenes del sensor según la orientación del sensor, pero no controla la rotación del dispositivo ni la escala de vista previa.

El escalamiento y la rotación se pueden codificar en una transformación Matrix. Para aprender a hacer lo siguiente: escalar y rotar correctamente un TextureView, consulta Cómo brindar compatibilidad con superficies redimensionables en tu app de cámara

Rotación relativa

La rotación relativa del sensor de la cámara es la cantidad de rotación necesaria para alinear la salida del sensor de la cámara con la orientación del dispositivo.

Componentes como SurfaceView y TextureView usan la rotación relativa para determinar los factores de escala x e y para la imagen de vista previa. También se usa para especifica la rotación del búfer de imagen del sensor.

Las clases CameraCharacteristics y Surface permiten calcular la rotación relativa del sensor de la cámara:

/**
 * 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;
}

Métricas de la ventana

No se debe usar el tamaño de la pantalla para determinar las dimensiones del visor de la cámara. Es posible que la app de la cámara se ejecute en una parte de la pantalla, ya sea en el modo multiventana en dispositivos móviles o en el modo sin restricciones en ChromeOS.

WindowManager#getCurrentWindowMetrics() (agregado en el nivel de API 30) muestra el tamaño de la ventana de la aplicación en lugar de el tamaño de la pantalla. Los métodos WindowMetricsCalculator#computeCurrentWindowMetrics() y WindowInfoTracker#currentWindowMetrics() de la biblioteca de WindowManager de Jetpack brindan una compatibilidad similar con retrocompatibilidad hasta el nivel de API 14.

Rotación de 180 grados

Una rotación de 180 grados de un dispositivo (por ejemplo, de la orientación natural a la orientación natural al revés) no activa la devolución de llamada de onConfigurationChanged(). Como resultado, la vista previa de la cámara puede estar al revés.

Para detectar una rotación de 180 grados, implementa una DisplayListener y comprueba la rotación del dispositivo con una llamada a Display#getRotation() en la onDisplayChanged() devolución de llamada.

Recursos exclusivos

Antes de Android 10, solo la actividad visible superior en un modo multiventana estaba en el estado RESUMED. Esto era confuso para los usuarios porque el sistema no proporcionó ninguna indicación de qué actividad se reanudó.

Android 10 (nivel de API 29) introdujo la reanudación múltiple, en la que todas las actividades visibles están en el estado RESUMED. Las actividades visibles aún pueden ingresar al estado PAUSED si, por ejemplo, hay una actividad transparente sobre la actividad o si la actividad no se puede enfocar, como en el modo de pantalla en pantalla (consulta Compatibilidad con el modo de pantalla en pantalla).

Una aplicación que use la cámara, el micrófono o cualquier recurso exclusivo o único en el nivel de API 29 o superior debe admitir la reanudación múltiple. Por ejemplo, si tres actividades reanudadas quieren usar la cámara, solo una puede acceder a este recurso exclusivo. Cada actividad debe implementar una devolución de llamada onDisconnected() para estar al tanto del acceso preventivo a la cámara por parte de una actividad de prioridad más alta.

Para obtener más información, consulta Reanudación múltiple:

Recursos adicionales