1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.camera.integration.extensions 18 19 import android.hardware.camera2.CameraCaptureSession 20 import android.hardware.camera2.CameraExtensionSession 21 import android.hardware.camera2.CameraMetadata.CONTROL_AF_TRIGGER_CANCEL 22 import android.hardware.camera2.CameraMetadata.CONTROL_AF_TRIGGER_IDLE 23 import android.hardware.camera2.CaptureRequest 24 import android.hardware.camera2.CaptureResult 25 import android.hardware.camera2.TotalCaptureResult 26 import android.hardware.camera2.params.MeteringRectangle 27 import android.util.Log 28 import androidx.annotation.RequiresApi 29 import java.util.concurrent.Executors 30 import java.util.concurrent.ScheduledExecutorService 31 import java.util.concurrent.ScheduledFuture 32 import java.util.concurrent.TimeUnit 33 34 val EMPTY_RECTANGLES = arrayOfNulls<MeteringRectangle>(0) 35 36 private const val TAG = "FocusMeteringControl" 37 private const val AUTO_FOCUS_TIMEOUT_DURATION_MS = 5000L 38 39 /** 40 * A class to manage focus-metering related operations. This class will help to monitor whether the 41 * state is locked or not and then make the AF-Trigger become to idle or cancel state. 42 */ 43 @RequiresApi(31) 44 class FocusMeteringControl( 45 private val startAfTriggerImpl: (Array<MeteringRectangle?>) -> Unit, 46 private val cancelAfTriggerImpl: (Int) -> Unit 47 ) { 48 49 private val scheduler: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor() 50 private var currentAfState: Int = CaptureResult.CONTROL_AF_STATE_INACTIVE 51 private var autoCancelHandle: ScheduledFuture<*>? = null 52 private var autoFocusTimeoutHandle: ScheduledFuture<*>? = null 53 private var focusTimeoutCounter: Long = 0 54 private var isAutoFocusCompleted: Boolean = true 55 56 private val captureCallbackExtensionMode = 57 object : CameraExtensionSession.ExtensionCaptureCallback() { onCaptureResultAvailablenull58 override fun onCaptureResultAvailable( 59 session: CameraExtensionSession, 60 request: CaptureRequest, 61 result: TotalCaptureResult 62 ) { 63 result.get(CaptureResult.CONTROL_AF_STATE)?.let { handleCaptureResultForAf(it) } 64 } 65 } 66 67 private val captureCallbackNormalMode = 68 object : CameraCaptureSession.CaptureCallback() { onCaptureCompletednull69 override fun onCaptureCompleted( 70 session: CameraCaptureSession, 71 request: CaptureRequest, 72 result: TotalCaptureResult 73 ) { 74 result.get(CaptureResult.CONTROL_AF_STATE)?.let { handleCaptureResultForAf(it) } 75 } 76 } 77 handleCaptureResultForAfnull78 private fun handleCaptureResultForAf(afState: Int?) { 79 if (isAutoFocusCompleted) { 80 return 81 } 82 83 if (afState == null) { 84 Log.e(TAG, "afState == null") 85 // set isAutoFocusCompleted to true when camera does not support AF_AUTO. 86 isAutoFocusCompleted = true 87 } else if (currentAfState == CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN) { 88 if (afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED) { 89 Log.d(TAG, "afState == CONTROL_AF_STATE_FOCUSED_LOCKED") 90 isAutoFocusCompleted = true 91 } else if (afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) { 92 Log.d(TAG, "afState == CONTROL_AF_STATE_NOT_FOCUSED_LOCKED") 93 isAutoFocusCompleted = true 94 } 95 } 96 97 // Check 3A regions 98 if (isAutoFocusCompleted) { 99 clearAutoFocusTimeoutHandle() 100 Log.d(TAG, "cancelAfTrigger: CONTROL_AF_TRIGGER_IDLE") 101 cancelAfTriggerImpl.invoke(CONTROL_AF_TRIGGER_IDLE) 102 } 103 104 if (currentAfState != afState && afState != null) { 105 currentAfState = afState 106 } 107 } 108 updateMeteringRectanglesnull109 fun updateMeteringRectangles(meteringRectangles: Array<MeteringRectangle?>) { 110 clearAutoFocusTimeoutHandle() 111 isAutoFocusCompleted = false 112 val timeoutId: Long = ++focusTimeoutCounter 113 autoFocusTimeoutHandle = 114 scheduler.schedule( 115 { 116 Log.d(TAG, "cancelAfTrigger: CONTROL_AF_TRIGGER_CANCEL") 117 cancelAfTriggerImpl.invoke(CONTROL_AF_TRIGGER_CANCEL) 118 if (timeoutId == focusTimeoutCounter) { 119 isAutoFocusCompleted = true 120 } 121 }, 122 AUTO_FOCUS_TIMEOUT_DURATION_MS, 123 TimeUnit.MILLISECONDS 124 ) 125 currentAfState = CaptureResult.CONTROL_AF_STATE_INACTIVE 126 startAfTriggerImpl.invoke(meteringRectangles) 127 } 128 getCaptureCallbacknull129 fun getCaptureCallback(extensionEnabled: Boolean): Any = 130 if (extensionEnabled) { 131 captureCallbackExtensionMode 132 } else { 133 captureCallbackNormalMode 134 } 135 clearAutoFocusTimeoutHandlenull136 private fun clearAutoFocusTimeoutHandle() { 137 autoFocusTimeoutHandle?.let { 138 it.cancel(/* mayInterruptIfRunning= */ true) 139 autoCancelHandle = null 140 } 141 } 142 } 143