Nota: Esta página hace referencia al paquete Camera2. A menos que tu app requiera funciones específicas de bajo nivel de Camera2, te recomendamos que uses CameraX. CameraX y Camera2 admiten Android 5.0 (nivel de API 21) y versiones posteriores.
Muchos dispositivos Android modernos tienen dos o más cámaras en la parte frontal, posterior o en ambos lados del dispositivo. Cada lente puede tener capacidades únicas, como captura en ráfaga, control manual o seguimiento de movimiento. Una app para depositar cheques podría usar solo la primera cámara posterior, mientras que una app de redes sociales podría usar de forma predeterminada una cámara frontal, pero darles a los usuarios la opción de cambiar entre todas las lentes disponibles. También puede recordar sus elecciones.
En esta página, se explica cómo enumerar las lentes de la cámara y sus capacidades para que puedas tomar decisiones en tu app sobre qué lente usar en una situación determinada. En el siguiente fragmento de código, se recupera una lista de todas las cámaras y se itera sobre ellas:
try { val cameraIdList = cameraManager.cameraIdList // may be empty // iterate over available camera devices. for (cameraId in cameraIdList) { val characteristics = cameraManager.getCameraCharacteristics(cameraId) val cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING) val cameraCapabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES) // check if the selected camera device supports basic features // ensures backward compatibility with the original Camera API. val isBackwardCompatible = cameraCapabilities?.contains( CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE ) ?: false // ... } } catch (e: CameraAccessException) { e.message?.let { Log.e(TAG, it) } // ... }
La variable cameraLensFacing describe la dirección hacia la que apunta la cámara en relación con la pantalla del dispositivo y tiene uno de los siguientes valores:
CameraMetadata.LENS_FACING_FRONTCameraMetadata.LENS_FACING_BACKCameraMetadata.LENS_FACING_EXTERNAL
Para obtener más información sobre la configuración de la orientación de la lente, consulta CameraCharacteristics.LENS_FACING.
La variable cameraCapabilities de la muestra de código anterior contiene información sobre capacidades varias, incluido si la cámara puede producir fotogramas estándar como resultado (en lugar de, por ejemplo, solo datos de sensores de profundidad). Puedes buscar si CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE es una de las capacidades de la cámara, que se almacena como una marca en isBackwardCompatible.
Elige valores predeterminados razonables
En tu app, es probable que quieras abrir una cámara específica de forma predeterminada (si está disponible). Por ejemplo, es probable que una app de selfies abra la cámara frontal, mientras que una app de realidad aumentada podría comenzar con la cámara posterior. La siguiente función devuelve la primera cámara que apunta en una dirección determinada:
fun getFirstCameraIdFacing( cameraManager: CameraManager, facing: Int = CameraMetadata.LENS_FACING_BACK ): String? { try { // Get list of all compatible cameras. val cameraIds = cameraManager.cameraIdList.filter { val characteristics = cameraManager.getCameraCharacteristics(it) val capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES) capabilities?.contains( CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE ) ?: false } // Iterate over the list of cameras and return the first one matching desired // lens-facing configuration. cameraIds.forEach { val characteristics = cameraManager.getCameraCharacteristics(it) if (characteristics.get(CameraCharacteristics.LENS_FACING) == facing) { return it } } // If no camera matched desired orientation, return the first one from the list. return cameraIds.firstOrNull() } catch (e: CameraAccessException) { e.message?.let { Log.e(TAG, it) } return null } }
Habilitar el cambio de cámara
Muchas apps de cámara les brindan a los usuarios la opción de alternar entre cámaras:
Muchos dispositivos tienen varias cámaras que apuntan en la misma dirección. Algunas incluso tienen cámaras USB externas. Para proporcionarles a los usuarios una IU que les permita cambiar entre diferentes cámaras, elige la primera cámara disponible para cada configuración posible de orientación de la lente.
Si bien no existe una lógica universal para seleccionar la siguiente cámara, el siguiente código funciona para la mayoría de los casos de uso:
fun filterCompatibleCameras( cameraIds: Array<String>, cameraManager: CameraManager ): List<String> { return cameraIds.filter { val characteristics = cameraManager.getCameraCharacteristics(it) characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)?.contains( CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE ) ?: false } } fun filterCameraIdsFacing( cameraIds: List<String>, cameraManager: CameraManager, facing: Int ): List<String> { return cameraIds.filter { val characteristics = cameraManager.getCameraCharacteristics(it) characteristics.get(CameraCharacteristics.LENS_FACING) == facing } } fun getNextCameraId(cameraManager: CameraManager, currCameraId: String? = null): String? { // Get all front, back and external cameras in 3 separate lists. val cameraIds = filterCompatibleCameras(cameraManager.cameraIdList, cameraManager) val backCameras = filterCameraIdsFacing( cameraIds, cameraManager, CameraMetadata.LENS_FACING_BACK ) val frontCameras = filterCameraIdsFacing( cameraIds, cameraManager, CameraMetadata.LENS_FACING_FRONT ) val externalCameras = filterCameraIdsFacing( cameraIds, cameraManager, CameraMetadata.LENS_FACING_EXTERNAL ) // The recommended order of iteration is: all external, first back, first front. val allCameras = ( externalCameras + listOf( backCameras.firstOrNull(), frontCameras.firstOrNull() ) ).filterNotNull() // Get the index of the currently selected camera in the list. val cameraIndex = allCameras.indexOf(currCameraId) // The selected camera may not be in the list, for example it could be an // external camera that has been removed by the user. return if (cameraIndex == -1) { // Return the first camera from the list. allCameras.getOrNull(0) } else { // Return the next camera from the list, wrap around if necessary. allCameras.getOrNull((cameraIndex + 1) % allCameras.size) } }
Este código funciona para un gran conjunto de dispositivos con muchas configuraciones diferentes. Para obtener más información sobre cómo tener en cuenta los casos extremos, consulta CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA.
Crea apps compatibles
En el caso de las apps que aún usan la API de Camera obsoleta, la cantidad de cámaras que muestra Camera.getNumberOfCameras() depende de la implementación del OEM. Si hay varias cámaras lógicas en el sistema, para mantener la retrocompatibilidad de la app, este método solo expondrá una cámara para cada cámara lógica y el grupo de cámaras físicas subyacente. Usa la API de Camera2 para ver todas las cámaras.
Para obtener más información sobre las orientaciones de la cámara, consulta Camera.CameraInfo.orientation.
En general, usa la API de Camera.getCameraInfo() para consultar todos los orientations de la cámara y exponer solo una cámara para cada orientación disponible a los usuarios que cambian de cámara.
Se adapta a todos los tipos de dispositivos
No des por sentado que tu app siempre se ejecuta en un dispositivo de mano con una o dos cámaras. En su lugar, elige las cámaras más adecuadas para la app. Si no necesitas una cámara específica, selecciona la primera cámara que apunte en la dirección elegida. Si la cámara que apunta en una dirección determinada no está disponible, considera si el usuario puede completar su recorrido con otra cámara. No restrinjas la disponibilidad de tu app en ciertos dispositivos según el hardware de la cámara. Si hay una cámara externa conectada, es probable que el usuario la prefiera como predeterminada.