Current Android devices can have two or more cameras in the front, in the back, or both. That can be a lot of lenses to choose from.
To accommodate all device configurations, check the camera list and camera characteristics:
val cameraIdList = cameraManager.cameraIdList // may be empty
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING)
val cameraCapabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)
val cameraCompatible = cameraCapabilities?.contains(
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ?: false
The variable cameraLensFacing
will be one of:
CameraMetadata.LENS_FACING_FRONT
CameraMetadata.LENS_FACING_BACK
CameraMetadata.LENS_FACING_EXTERNAL
For more information about the lens-facing configuration, see
CameraCharacteristics.LENS_FACING
.
The variable cameraCapabilities
from the preceding code sample contains
information about miscellaneous capabilities, including whether the camera is
able to produce standard frames as an output (as opposed to, for example, only
depth sensor data). You can look for whether
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
is one of the camera’s listed capabilities, which is stored as a flag in
cameraCompatible
.
Choose sensible defaults
Depending on the use case of your app, you may want to open a specific camera lens configuration by default, if it’s available. For example, a selfie app likely opens the front-facing camera, while an augmented reality app might start with the back camera. You can wrap this logic into a function that properly handles the cases mentioned above:
fun getFirstCameraIdFacing(cameraManager: CameraManager,
facing: Int = CameraMetadata.LENS_FACING_BACK): String? {
// 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()
}
Enable switching cameras
Many camera apps give users the option to switch between cameras:

There are many devices with multiple cameras facing the same way, or that have external cameras connected via USB. To provide the user with a UI that lets them switch between different facing cameras, choose the first available camera for each possible lens-facing configuration.
For information on how to do this, see
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
.
Although there is no universal logic for selecting the next camera, the following code works for most use cases:
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 on 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)
}
}
This code accounts for a large set of devices with many different configurations.
Create compatible apps
For apps still using the deprecated Camera API, the number of cameras
that
Camera.getNumberOfCameras()
returns depends on OEM implementation. If there is a logical multi-camera in the
system, to maintain app backward compatibility, this method will only expose one
camera for every logical camera and underlying physical cameras group. Use
camera2 API to see all cameras.
For more background information on camera orientations, see
Camera.CameraInfo.orientation
.
In general, use the
Camera.getCameraInfo()
API to query all camera
orientation
s,
and expose only one camera for each available orientation to users that are
switching between cameras.
Accommodate all device types
Android runs on many different devices. You should not assume that your app will always run on a traditional handheld device with one or two cameras. Pick the most appropriate cameras for the app. If you don't need a specific camera, select the first camera with the desired lens-facing configuration. If there are external cameras connected, it may be reasonable to assume that the user would prefer to see those first.