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