How to auto-focus with Android CameraX

Android has released a new API camerax in recent months. I’m trying to understand how to get auto-focusing for the camera to work.

https://groups.google.com/a/android.com/forum/#!searchin/camerax-developers/auto$20focus|sort:date/camerax-developers/IQ3KZd8iOIY/LIbrRIqEBgAJ

Here is a discussion on the topic but there is almost no specific documentation on it.

https://github.com/android/camera-samples/tree/master/CameraXBasic/app/src/main/java/com/android/example/cameraxbasic

Here is also the basic camerax app but I couldn’t find any file dealing with the auto focusing.

Any tips or points to documentation is helpful. Also I’m fairly new to android so its very possible I’m missing something that makes the above links more useful.

Answer

With the current CameraX 1.0.0-rc02 & 1.0.0-alpha21 artifacts, you can proceed in this 2 ways:

  1. Auto-focus every X seconds:

     previewView.afterMeasured {
         val autoFocusPoint = SurfaceOrientedMeteringPointFactory(1f, 1f)
                 .createPoint(.5f, .5f)
         try {
             val autoFocusAction = FocusMeteringAction.Builder(
                 autoFocusPoint,
                 FocusMeteringAction.FLAG_AF
             ).apply {
                 //start auto-focusing after 2 seconds
                 setAutoCancelDuration(2, TimeUnit.SECONDS)
             }.build()
             camera.cameraControl.startFocusAndMetering(autoFocusAction)
         } catch (e: CameraInfoUnavailableException) {
             Log.d("ERROR", "cannot access camera", e)
         }
     }
    
  2. Focus on-tap:

     previewView.afterMeasured {
         previewView.setOnTouchListener { _, event ->
             [email protected] when (event.action) {
                 MotionEvent.ACTION_DOWN -> {
                     true
                 }
                 MotionEvent.ACTION_UP -> {
                     val factory: MeteringPointFactory = SurfaceOrientedMeteringPointFactory(
                         previewView.width.toFloat(), previewView.height.toFloat()
                     )
                     val autoFocusPoint = factory.createPoint(event.x, event.y)
                     try {
                         camera.cameraControl.startFocusAndMetering(
                             FocusMeteringAction.Builder(
                                 autoFocusPoint,
                                 FocusMeteringAction.FLAG_AF
                             ).apply {
                                 //focus only when the user tap the preview
                                 disableAutoCancel()
                             }.build()
                         )
                     } catch (e: CameraInfoUnavailableException) {
                         Log.d("ERROR", "cannot access camera", e)
                     }
                     true
                 }
                 else -> false // Unhandled event.
             }
         }
     }
    

afterMeasured extension function is a simple utility:

inline fun View.afterMeasured(crossinline block: () -> Unit) {
    viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            if (measuredWidth > 0 && measuredHeight > 0) {
                viewTreeObserver.removeOnGlobalLayoutListener(this)
                block()
            }
        }
    })
}

A Camera object can be obtained with

val camera = cameraProvider.bindToLifecycle(
    [email protected], cameraSelector, previewView //this is a PreviewView
)

Leave a Reply

Your email address will not be published. Required fields are marked *