• Camera Enumeration on Android
  • Written by Oscar Wahltinez
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: luoqiuyu
  • Proofread by hanliuxin5

Starting with Android P, support for logical multiple cameras and USB cameras has been added. What does this mean for Android developers?

Multiple cameras

Multiple cameras on one device is nothing new, but until now, Android devices have had at most two front and rear cameras. If you want to open the first camera, do the following:

val cameraDevice = Camera.open(0)
Copy the code

But these are relatively simple operations. These days, multi-camera means two or more cameras in the front or back. There are so many shots to choose from!

Camera2 API

Due to compatibility issues, the above code still works, even though the old Camera API has been deprecated for a long time. But as ecosystems evolve, more advanced camera capabilities are needed. Therefore, Android 5.0 (Lollipop) introduced Camera2 for API 21 and above. Use the Camera2 API to open the first existing camera as follows:

val cameraManager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
val cameraId = cameraManager.cameraIdList[0]
cameraManager.openCamera(cameraId, object : CameraDevice.StateCallback() {
    override fun onOpened(device: CameraDevice) {
        // Do something with `device`
    }
    override fun onDisconnected(device: CameraDevice) {
        device.close()
    }
    override fun onError(device: CameraDevice, error: Int) {
        onDisconnected(device)
    }
}, null)
Copy the code

The first one is not the best choice

The above code looks fine so far. If all we need is an app that opens the first camera that exists, it will work on most Android phones. But consider the following scenario:

  • If the device doesn’t have a camera, the application crashes. It may seem unlikely, but remember that Android runs on a variety of devices, including Android Things, Android Wear, and Android TV, with millions of users.
  • If the device has at least one rear camera, it will map to the first camera in the list. But when the app runs on a device without a rear-facing camera, such as PixelBooks or some other ChromeOS laptops, a single front-facing camera will open.

So what should we do? Check the camera list and camera features:


val cameraIdList = cameraManager.cameraIdList // may be empty
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING)
Copy the code

The variable cameraLensFacing has the following values:

  • CameraMetadata.LENS_FACING_FRONT
  • CameraMetadata.LENS_FACING_BACK
  • CameraMetadata.LENS_FACING_EXTERNAL

For more information on camera configuration, see the documentation.

Reasonable defaults

Depending on the use of the application, we want specific camera lens configurations turned on by default (if such a capability is available). For example, a selfie app will likely want to turn on the front-facing camera, while an augmented reality app will want to turn on the rear-facing camera. We can wrap such a logic into a function that correctly handles the above case:

fun getFirstCameraIdFacing(cameraManager: CameraManager,
                           facing: Int = CameraMetadata.LENS_FACING_BACK): String? {
    val cameraIds = cameraManager.cameraIdList
    // 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()
}
Copy the code

Switching cameras

So far, we’ve discussed how to choose the default camera based on the purpose of your application. Many camera apps also offer users the ability to switch between cameras:

Switch the camera button in the Google Camera app

In order to achieve this function, try from the CameraManager. GetCameraIdList () provides the list of a camera, but it is not a good way. Because starting with Android P, we’ll see more devices with multiple cameras in the same situation, and even external cameras connected via USB. If we want to provide the user with the UI to switch between different cameras, the recommendation (as documented) is to select the first available camera for each possible lens configuration.

Although there is no general logic for choosing the next camera, the following code works for most cases:

fun filterCameraIdsFacing(cameraIds: Array<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 = cameraManager.cameraIdList
    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)
    }
}
Copy the code

This may seem complicated, but we need to take into account a large number of devices with different configurations.

Compatibility behavior

For those who are still in the abandoned Camera apis used by the application, through the Camera. The getNumberOfCameras () to get the number of cameras depends on the realization of the OEM. Here’s what the document says:

If there are logical multiple cameras on the system, this method exposes only one camera for each logical camera and the underlying physical camera group in order to maintain backward compatibility of the application. Use the camera2 API to view all the cameras.

Please read the rest of the documentation carefully for more information. In general, similar advice applies: use the Camera.getCamerainfo () API to query all Camera directions, and only provide one Camera for each available direction when the user switches cameras.

Best practices

Android runs on many different devices. Instead of assuming that your app will always run on a traditional handheld device with one or two cameras, you should choose the camera that works best for your app. If you don’t need a specific camera, select the first camera that needs the default configuration. If the device is connected to an external camera, it is reasonable to assume that the user wants to see the first of these external cameras first.

If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.