Search code examples
androidkotlinandroid-camerax

Android-CameraX: Switch between multiple front cameras


I´m trying to write my first Android Camera App, but it always selects the zoom camera instead of the main camera. (I tested it on a Huawei P30 Pro)

And the code is based on the offical camerax sample application (https://github.com/android/camera-samples/tree/master/CameraXBasic)

The relevant code:

/** Declare and bind preview, capture and analysis use cases */
private fun bindCameraUseCases() {

    // Get screen metrics used to setup camera for full screen resolution
    val metrics = DisplayMetrics().also { viewFinder.display.getRealMetrics(it) }
    Log.d(TAG, "Screen metrics: ${metrics.widthPixels} x ${metrics.heightPixels}")

    val screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels)
    Log.d(TAG, "Preview aspect ratio: $screenAspectRatio")

    val rotation = viewFinder.display.rotation

    // Bind the CameraProvider to the LifeCycleOwner

    val cameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()

    val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
    cameraProviderFuture.addListener(Runnable {

        // CameraProvider
        val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

        // Preview
        preview = Preview.Builder()
            // We request aspect ratio but no resolution
            .setTargetAspectRatio(screenAspectRatio)
            // Set initial target rotation
            .setTargetRotation(rotation)
            .build()

        // ImageCapture
        imageCapture = ImageCapture.Builder()
            .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
            // We request aspect ratio but no resolution to match preview config, but letting
            // CameraX optimize for whatever specific resolution best fits our use cases
            .setTargetAspectRatio(screenAspectRatio)
            // Set initial target rotation, we will have to call this again if rotation changes
            // during the lifecycle of this use case
            .setTargetRotation(rotation)
            .build()

        // Must unbind the use-cases before rebinding them
        cameraProvider.unbindAll()

        try {
            // A variable number of use-cases can be passed here -
            // camera provides access to CameraControl & CameraInfo
            camera = cameraProvider.bindToLifecycle(
                    this, cameraSelector, preview, imageCapture /**, imageAnalyzer*/)

            // Attach the viewfinder's surface provider to preview use case
            preview?.setSurfaceProvider(viewFinder.createSurfaceProvider(camera?.cameraInfo))
        } catch(exc: Exception) {
            Log.e(TAG, "Use case binding failed", exc)
        }

    }, ContextCompat.getMainExecutor(requireContext()))
}

Solution

  • With the current CameraX APIs, I don't think you can choose which specific camera to use, you can only select the lens facing (CameraSelector.Builder().requireLensFacing(int)), which can either be front or back. When you bind use cases, CameraX chooses the first camera that meets the use cases requirements. For example, 2 different back cameras may be used when binding the preview use case with extensions enabled vs disabled.

    The CameraSelector API seems to still have room to grow, so in the future, you may have more control over which camera is selected. If you need that kind of control right now, you may need to use Camera2.