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