AutoFocusStateMachine.java revision 2d8e55f45e52ac0b18c0e46de602e6a6d5ab1001
1/* 2 * Copyright 2013 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 */ 16package com.android.ex.camera2.pos; 17 18import android.hardware.camera2.CameraDevice; 19import android.hardware.camera2.CameraMetadata.Key; 20import android.hardware.camera2.CaptureRequest; 21import android.hardware.camera2.CaptureResult; 22import android.util.Log; 23 24import com.android.ex.camera2.utils.SysTrace; 25 26/** 27 * Manage the auto focus state machine for CameraDevice. 28 * 29 * <p>Requests are created only when the AF needs to be manipulated from the user, 30 * but automatic camera-caused AF state changes are broadcasted from any new result.</p> 31 */ 32public class AutoFocusStateMachine { 33 34 public interface AutoFocusStateListener { 35 /** 36 * The camera is currently focused (either active or passive). 37 * 38 * @param locked True if the lens has been locked from moving, false otherwise. 39 */ 40 void onAutoFocusSuccess(CaptureResult result, boolean locked); 41 42 /** 43 * The camera is currently not focused (either active or passive). 44 * 45 * @param locked False if the AF is still scanning, true if needs a restart. 46 */ 47 void onAutoFocusFail(CaptureResult result, boolean locked); 48 49 /** 50 * The camera is currently scanning (either active or passive) 51 * and has not yet converged. 52 * 53 * <p>This is not called for results where the AF either succeeds or fails.</p> 54 */ 55 void onAutoFocusScan(CaptureResult result); 56 57 /** 58 * The camera is currently not doing anything with the autofocus. 59 * 60 * <p>Autofocus could be off, or this could be an intermediate state transition as 61 * scanning restarts.</p> 62 */ 63 void onAutoFocusInactive(CaptureResult result); 64 } 65 66 private static final String TAG = "AutoFocusStateMachine"; 67 private static final boolean DEBUG_LOGGING = Log.isLoggable(TAG, Log.DEBUG); 68 private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE); 69 private static final int AF_UNINITIALIZED = -1; 70 71 private final AutoFocusStateListener mListener; 72 private int mLastAfState = AF_UNINITIALIZED; 73 private int mLastAfMode = AF_UNINITIALIZED; 74 private int mCurrentAfMode = AF_UNINITIALIZED; 75 private int mCurrentAfTrigger = AF_UNINITIALIZED; 76 77 private int mCurrentAfCookie = AF_UNINITIALIZED; 78 private String mCurrentAfTrace = ""; 79 private int mLastAfCookie = 0; 80 81 public AutoFocusStateMachine(AutoFocusStateListener listener) { 82 if (listener == null) { 83 throw new IllegalArgumentException("listener should not be null"); 84 } 85 mListener = listener; 86 } 87 88 /** 89 * Invoke every time we get a new CaptureResult via 90 * {@link CameraDevice.CaptureListener#onCaptureCompleted}. 91 * 92 * <p>This function is responsible for dispatching updates via the 93 * {@link AutoFocusStateListener} so without calling this on a regular basis, no 94 * AF changes will be observed.</p> 95 * 96 * @param result CaptureResult 97 */ 98 public synchronized void onCaptureCompleted(CaptureResult result) { 99 100 /** 101 * Work-around for b/11269834 102 * Although these should never-ever happen, harden for ship 103 */ 104 if (result == null) { 105 Log.w(TAG, "onCaptureCompleted - missing result, skipping AF update"); 106 return; 107 } 108 109 Key<Integer> keyAfState = CaptureResult.CONTROL_AF_STATE; 110 if (keyAfState == null) { 111 Log.e(TAG, "onCaptureCompleted - missing android.control.afState key, " + 112 "skipping AF update"); 113 return; 114 } 115 116 Key<Integer> keyAfMode = CaptureResult.CONTROL_AF_MODE; 117 if (keyAfMode == null) { 118 Log.e(TAG, "onCaptureCompleted - missing android.control.afMode key, " + 119 "skipping AF update"); 120 return; 121 } 122 123 Integer afState = result.get(CaptureResult.CONTROL_AF_STATE); 124 Integer afMode = result.get(CaptureResult.CONTROL_AF_MODE); 125 126 /** 127 * Work-around for b/11238865 128 * This is a HAL bug as these fields should be there always. 129 */ 130 if (afState == null) { 131 Log.w(TAG, "onCaptureCompleted - missing android.control.afState !"); 132 return; 133 } else if (afMode == null) { 134 Log.w(TAG, "onCaptureCompleted - missing android.control.afMode !"); 135 return; 136 } 137 138 if (DEBUG_LOGGING) Log.d(TAG, "onCaptureCompleted - new AF mode = " + afMode + 139 " new AF state = " + afState); 140 141 if (mLastAfState == afState && afMode == mLastAfMode) { 142 // Same AF state as last time, nothing else needs to be done. 143 return; 144 } 145 146 if (VERBOSE_LOGGING) Log.v(TAG, "onCaptureCompleted - new AF mode = " + afMode + 147 " new AF state = " + afState); 148 149 mLastAfState = afState; 150 mLastAfMode = afMode; 151 152 switch (afState) { 153 case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED: 154 mListener.onAutoFocusSuccess(result, /*locked*/true); 155 endTraceAsync(); 156 break; 157 case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED: 158 mListener.onAutoFocusFail(result, /*locked*/true); 159 endTraceAsync(); 160 break; 161 case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED: 162 mListener.onAutoFocusSuccess(result, /*locked*/false); 163 break; 164 case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED: 165 mListener.onAutoFocusFail(result, /*locked*/false); 166 break; 167 case CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN: 168 mListener.onAutoFocusScan(result); 169 break; 170 case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN: 171 mListener.onAutoFocusScan(result); 172 break; 173 case CaptureResult.CONTROL_AF_STATE_INACTIVE: 174 mListener.onAutoFocusInactive(result); 175 break; 176 } 177 } 178 179 /** 180 * Lock the lens from moving. Typically used before taking a picture. 181 * 182 * <p>After calling this function, submit the new requestBuilder as a separate capture. 183 * Do not submit it as a repeating request or the AF lock will be repeated every time.</p> 184 * 185 * <p>Create a new repeating request from repeatingBuilder and set that as the updated 186 * repeating request.</p> 187 * 188 * <p>If the lock succeeds, {@link AutoFocusStateListener#onAutoFocusSuccess} with 189 * {@code locked == true} will be invoked. If the lock fails, 190 * {@link AutoFocusStateListener#onAutoFocusFail} with {@code scanning == false} will be 191 * invoked.</p> 192 * 193 * @param repeatingBuilder Builder for a repeating request. 194 * @param requestBuilder Builder for a non-repeating request. 195 * 196 */ 197 public synchronized void lockAutoFocus(CaptureRequest.Builder repeatingBuilder, 198 CaptureRequest.Builder requestBuilder) { 199 200 if (VERBOSE_LOGGING) Log.v(TAG, "lockAutoFocus"); 201 202 if (mCurrentAfMode == AF_UNINITIALIZED) { 203 throw new IllegalStateException("AF mode was not enabled"); 204 } 205 206 beginTraceAsync("AFSM_lockAutoFocus"); 207 208 mCurrentAfTrigger = CaptureRequest.CONTROL_AF_TRIGGER_START; 209 210 repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode); 211 requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode); 212 213 repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, 214 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 215 requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, 216 CaptureRequest.CONTROL_AF_TRIGGER_START); 217 } 218 219 /** 220 * Unlock the lens, allowing it to move again. Typically used after taking a picture. 221 * 222 * <p>After calling this function, submit the new requestBuilder as a separate capture. 223 * Do not submit it as a repeating request or the AF lock will be repeated every time.</p> 224 * 225 * <p>Create a new repeating request from repeatingBuilder and set that as the updated 226 * repeating request.</p> 227 * 228 * <p>Once the unlock takes effect, {@link AutoFocusStateListener#onAutoFocusInactive} is 229 * invoked, and after that the effects depend on which mode you were in: 230 * <ul> 231 * <li>Passive - Scanning restarts with {@link AutoFocusStateListener#onAutoFocusScan}</li> 232 * <li>Active - The lens goes back to a default position (no callbacks)</li> 233 * </ul> 234 * </p> 235 * 236 * @param repeatingBuilder Builder for a repeating request. 237 * @param requestBuilder Builder for a non-repeating request. 238 * 239 */ 240 public synchronized void unlockAutoFocus(CaptureRequest.Builder repeatingBuilder, 241 CaptureRequest.Builder requestBuilder) { 242 243 if (VERBOSE_LOGGING) Log.v(TAG, "unlockAutoFocus"); 244 245 if (mCurrentAfMode == AF_UNINITIALIZED) { 246 throw new IllegalStateException("AF mode was not enabled"); 247 } 248 249 mCurrentAfTrigger = CaptureRequest.CONTROL_AF_TRIGGER_CANCEL; 250 251 repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode); 252 requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode); 253 254 repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, 255 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 256 requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, 257 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); 258 } 259 260 /** 261 * Enable active auto focus, immediately triggering a converging scan. 262 * 263 * <p>This is typically only used when locking the passive AF has failed.</p> 264 * 265 * <p>Once active AF scanning starts, {@link AutoFocusStateListener#onAutoFocusScan} will be 266 * invoked.</p> 267 * 268 * <p>If the active scan succeeds, {@link AutoFocusStateListener#onAutoFocusSuccess} with 269 * {@code locked == true} will be invoked. If the active scan fails, 270 * {@link AutoFocusStateListener#onAutoFocusFail} with {@code scanning == false} will be 271 * invoked.</p> 272 * 273 * <p>After calling this function, submit the new requestBuilder as a separate capture. 274 * Do not submit it as a repeating request or the AF trigger will be repeated every time.</p> 275 * 276 * <p>Create a new repeating request from repeatingBuilder and set that as the updated 277 * repeating request.</p> 278 * 279 * @param repeatingBuilder Builder for a repeating request. 280 * @param requestBuilder Builder for a non-repeating request. 281 * 282 * @param repeatingBuilder Builder for a repeating request. 283 */ 284 public synchronized void setActiveAutoFocus(CaptureRequest.Builder repeatingBuilder, 285 CaptureRequest.Builder requestBuilder) { 286 if (VERBOSE_LOGGING) Log.v(TAG, "setActiveAutoFocus"); 287 288 beginTraceAsync("AFSM_setActiveAutoFocus"); 289 290 mCurrentAfMode = CaptureRequest.CONTROL_AF_MODE_AUTO; 291 292 repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode); 293 requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode); 294 295 repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, 296 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 297 requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, 298 CaptureRequest.CONTROL_AF_TRIGGER_START); 299 } 300 301 /** 302 * Enable passive autofocus, immediately triggering a non-converging scan. 303 * 304 * <p>While passive autofocus is enabled, use {@link #lockAutoFocus} to lock 305 * the lens before taking a picture. Once a picture is taken, use {@link #unlockAutoFocus} 306 * to let the lens go back into passive scanning.</p> 307 * 308 * <p>Once passive AF scanning starts, {@link AutoFocusStateListener#onAutoFocusScan} will be 309 * invoked.</p> 310 * 311 * @param repeatingBuilder Builder for a repeating request. 312 * @param picture True for still capture AF, false for video AF. 313 */ 314 public synchronized void setPassiveAutoFocus(boolean picture, 315 CaptureRequest.Builder repeatingBuilder) { 316 if (VERBOSE_LOGGING) Log.v(TAG, "setPassiveAutoFocus - picture " + picture); 317 318 if (picture) { 319 mCurrentAfMode = CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE; 320 } else { 321 mCurrentAfMode = CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO; 322 } 323 324 repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode); 325 } 326 327 private synchronized void beginTraceAsync(String sectionName) { 328 if (mCurrentAfCookie != AF_UNINITIALIZED) { 329 // Terminate any currently active async sections before beginning another section 330 SysTrace.endSectionAsync(mCurrentAfTrace, mCurrentAfCookie); 331 } 332 333 mLastAfCookie++; 334 mCurrentAfCookie = mLastAfCookie; 335 mCurrentAfTrace = sectionName; 336 337 SysTrace.beginSectionAsync(sectionName, mCurrentAfCookie); 338 } 339 340 private synchronized void endTraceAsync() { 341 if (mCurrentAfCookie == AF_UNINITIALIZED) { 342 Log.w(TAG, "endTraceAsync - no current trace active"); 343 return; 344 } 345 346 SysTrace.endSectionAsync(mCurrentAfTrace, mCurrentAfCookie); 347 mCurrentAfCookie = AF_UNINITIALIZED; 348 } 349} 350