Vista previa de cámara

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

Las cámaras y las vistas previas no siempre están en la misma orientación en dispositivos Android.

La cámara se encuentra en una posición fija en un dispositivo, independientemente de si el dispositivo es un teléfono, una tablet o una computadora. Cuando cambia la orientación del dispositivo, también cambia la orientación de la cámara.

Como resultado, las apps de cámara generalmente suponen 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 se encuentra 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 al modo horizontal, se espera que la vista previa de la cámara sea más ancha que alta.

Sin embargo, estas suposiciones se enfrentan a nuevos factores de forma, como los dispositivos plegables y los 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 la orientación. El modo multiventana restringe las apps de cámara a una parte de la pantalla y ajusta la vista previa de la cámara independientemente de la orientación del dispositivo. El modo de pantallas múltiples permite el uso de pantallas secundarias que podrían no 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 mantiene 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, se aplica tanto a dispositivos principales en modo horizontal como a dispositivos principales verticales".

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

Sensor de la cámara y el teléfono en orientación vertical.
Figura 1: Relación típica de la orientación del teléfono y del sensor de 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 que apunta en la misma dirección que la pantalla) se rota 270 grados con respecto al teléfono para cumplir con la Definición de compatibilidad de Android.

Para exponer la rotación del sensor a las apps, la API de camera2 incluye una constante SENSOR_ORIENTATION. En la mayoría de los teléfonos y tablets, el dispositivo informa una orientación del 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 posteriores, lo que alinea el borde largo del sensor 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 sus datos (un búfer de imagen) en la orientación natural del sensor (horizontal), el búfer de imagen se debe rotar la cantidad de grados especificada por SENSOR_ORIENTATION para que la vista previa de la cámara aparezca en posición vertical en la orientación natural del dispositivo. Para las cámaras frontales, la rotación es en sentido antihorario; para las 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 el lado superior izquierdo.

La imagen debe rotarse 270 grados en sentido antihorario para que la orientación de la vista previa coincida con la del dispositivo:

Sensor de la cámara en orientación vertical con la imagen en posición 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 desde su orientación natural. Por ejemplo, un teléfono en orientación horizontal tiene una rotación del dispositivo de 90 o 270 grados, según la dirección de rotación.

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

Cálculo de orientación

La orientación correcta 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 imagen del sensor se puede calcular mediante la siguiente fórmula:

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

En el ejemplo anterior, sign es 1 para las cámaras frontales y -1 para las posteriores.

En el caso de las cámaras frontales, el búfer de imagen se rota en sentido antihorario (desde la orientación natural del sensor). Para las cámaras traseras, el búfer de imagen 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 al sentido de las manecillas del reloj para las cámaras traseras (por ejemplo, si se convierte 270 grados en sentido antihorario a 90 grados en el sentido de las manecillas del reloj). La operación de módulo ajusta el resultado a menos de 360 grados (por ejemplo, escalando 540 grados de rotación a 180).

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

  • Display#getRotation() proporciona la rotación en sentido antihorario del dispositivo (desde el punto de vista del usuario). Este valor se relaciona con 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 para usar en la fórmula anterior

Cámaras frontales

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

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

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

El búfer se debe rotar 270 grados en sentido contrario a las manecillas del reloj para ajustar la orientación del sensor (consulta Orientación de la cámara más arriba):

Sensor de la cámara girado a la orientación vertical con la imagen hacia el lado superior derecho.

Luego, el búfer se rota 90 grados adicionales en sentido contrario a las manecillas del reloj para tener en cuenta la rotación del dispositivo, lo que genera 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.

Esta es la cámara girada a la derecha a orientación horizontal:

Vista previa y sensor de la cámara 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:

El sensor de la cámara se giró a la orientación horizontal con la imagen al revés.

El búfer se debe rotar 270 grados en sentido antihorario para ajustar la orientación del sensor:

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

Luego, el búfer se rota 270 grados en sentido antihorario para tener en cuenta la rotación del dispositivo:

Se rotó el sensor de la cámara a la orientación horizontal con la imagen
 en posición 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 según la rotación del sensor (en lugar de en sentido antihorario, como las cámaras frontales), y, luego, el búfer de imágenes se rota en sentido contrario a las manecillas del reloj según la rotación del dispositivo.

Vista previa y sensor de la cámara en orientación horizontal, pero el sensor está al revés.
Figura 4: Teléfono con cámara posterior en orientación horizontal (girada a 270 o -90 grados)

En la figura 4, se muestra el búfer de imagen del sensor de la cámara:

El sensor de la cámara se giró a la orientación horizontal con la imagen al revés.

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

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

Luego, el búfer se rota 270 grados en sentido antihorario para tener en cuenta la rotación del dispositivo:

Se rotó el sensor de la cámara a la orientación horizontal con la imagen
 en posición 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 las apps se abren en pantallas secundarias.

El búfer de imagen del sensor de la cámara debe orientarse y ajustarse 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 forma dinámica, con o sin que el dispositivo cambie de orientación.

En nuevos factores de forma o en entornos multiventana o de pantallas múltiples, 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 no esté orientada o se ajuste de forma incorrecta, o ambas.

Dispositivo plegable desplegado con vista previa de la cámara vertical girada.
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 consideró erróneamente que el dispositivo se giró 90 grados en sentido contrario a las manecillas del reloj y, de este modo, giró la vista previa la misma cantidad.

Dispositivo plegable desplegado con vista previa de la cámara en posición vertical, pero aplastado debido al escalamiento incorrecto.
Figura 6: 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 6, la app no ajustó la relación de aspecto del búfer de imagen para permitir que se ajuste correctamente a las nuevas dimensiones del elemento de la IU de la vista previa de la cámara.

Las apps de cámara con orientación fija suelen experimentar problemas en dispositivos plegables y otros dispositivos con pantalla grande, como laptops:

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

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

Modo de retrato de inserción

Las apps de cámara que no admiten el modo multiventana (resizeableActivity="false") y restringen su orientación (screenOrientation="portrait" o screenOrientation="landscape") pueden colocarse en el modo vertical de inserción en dispositivos con pantalla grande para orientar correctamente la vista previa de la cámara.

Inserción de apps con formato letterbox (inserciones) solo en modo vertical en orientación vertical, aunque la relación de aspecto de la pantalla sea horizontal. Las apps solo con modo horizontal tienen formato letterbox en orientación horizontal, aunque la relación de aspecto de la pantalla sea vertical. La imagen de la cámara se rota para alinearla con la IU de la app, se recorta para que coincida con la relación de aspecto de la vista previa de la cámara y, luego, se ajusta para llenar la vista previa.

El modo vertical de inserción se activa cuando la relación de aspecto del sensor de 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 y la IU de la app en orientación vertical correcta en una laptop.
            La imagen de vista previa ancha se ajusta y se recorta para adaptarse a la orientación vertical.
Figura 8: App vertical con orientación fija en modo vertical insertado en una laptop

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

Rotar, recortar, ajustar

El modo vertical de inserción se invoca para una app de cámara que solo usa el modo vertical en una pantalla con una relación de aspecto horizontal:

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

La app tiene formato letterbox en orientación vertical:

La app se giró a la orientación vertical y en formato letterbox. La imagen está inclinada hacia un lado y arriba a la derecha.

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

Se rotó la imagen del sensor a 90 grados para que se mantenga en posición vertical.

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

Se recortó la imagen de la cámara a escala para llenar la vista previa de la cámara.

En 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:

Vista previa de la cámara y la IU de la app giradas en una pantalla ancha y desplegada
Figura 10: Dispositivo desplegado con app de cámara solo con orientación 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 se orienta de manera correcta en el visor, pero la app solo con orientación vertical está de lado.

El modo vertical de 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 en 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 explícitamente el modo vertical de inserción mediante 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 de inserción. SCALER_ROTATE_AND_CROP_90 es el comportamiento del modo vertical de inserción, 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 que crear un visor de la cámara se adapte a la orientación del sensor y a la rotación del dispositivo en una tarea simple.

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

Para conocer los conceptos básicos de la creación de una vista previa de la cámara con PreviewView, consulta Cómo implementar una vista previa.

Para obtener una implementación de muestra completa, consulta el repositorio CameraXBasic en GitHub.

Visor de la cámara

Al igual que el caso de uso de Preview, la biblioteca de 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 a 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 objeto TextureView o SurfaceView para mostrar el feed de la cámara y les aplica las transformaciones necesarias para mostrar correctamente el visor. Esto implica corregir su relación de aspecto, escala y rotación.

Para solicitar la plataforma desde el objeto CameraViewfinder, debes crear un ViewfinderSurfaceRequest.

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

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

Llamar a markSurfaceSafeToRelease() le notifica al proveedor de superficie que esta no es necesaria y que se pueden liberar los recursos relacionados.

Kotlin


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

Java


    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 sencillo para crear una vista previa de la cámara si esta no requiere procesamiento ni está animada.

SurfaceView rota automáticamente el búfer de imagen del sensor de la cámara para que coincida con la orientación de la pantalla, lo que tiene en cuenta tanto la orientación del sensor como la rotación del dispositivo. Sin embargo, el búfer de imagen se escala para adaptarse a las dimensiones de SurfaceView sin tener en cuenta la relación de aspecto.

Debes asegurarte de que la relación de aspecto del búfer de imagen coincida con la del SurfaceView. Para ello, escala el contenido de SurfaceView en el método onMeasure() del componente:

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

Kotlin

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

Java

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

Vista de textura

TextureView tiene menos rendimiento que SurfaceView y genera más trabajo, pero TextureView te brinda el control máximo de la vista previa de la cámara.

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

El escalamiento y la rotación se pueden codificar en una transformación Matrix Para obtener información sobre cómo ajustar y rotar correctamente un objeto 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 el resultado del sensor de la cámara con la orientación del dispositivo.

Los 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 especificar la rotación del búfer de imagen del sensor.

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

Kotlin

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

Java

/**
 * 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. La app de la cámara puede estar ejecutándose en una parte de la pantalla, ya sea en el modo multiventana en dispositivos móviles o en el modo libre en ChromeOS.

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

Rotación de 180 grados

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

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

Recursos exclusivos

Antes de Android 10, solo la actividad superior visible en un entorno multiventana tenía el estado RESUMED. Esto era confuso para los usuarios, porque el sistema no proporcionaba una 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, una actividad transparente se encuentra sobre la actividad o esta no se puede enfocar, como en el modo de pantalla en pantalla (consulta Compatibilidad con pantalla en pantalla).

Una aplicación que usa la cámara, el micrófono o cualquier recurso exclusivo o singleton 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 mayor prioridad.

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

Recursos adicionales