1 /* 2 * Copyright (C) 2014 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 android.hardware.camera2.cts.helpers; 18 19 import android.graphics.Rect; 20 import android.hardware.camera2.CameraAccessException; 21 import android.hardware.camera2.CameraCaptureSession; 22 import android.hardware.camera2.CameraCaptureSession.CaptureCallback; 23 import android.hardware.camera2.CameraCharacteristics; 24 import android.hardware.camera2.CameraDevice; 25 import android.hardware.camera2.params.MeteringRectangle; 26 import android.hardware.camera2.CaptureRequest; 27 import android.hardware.camera2.CaptureResult; 28 import android.hardware.camera2.TotalCaptureResult; 29 import android.os.Handler; 30 import android.util.Log; 31 import android.view.Surface; 32 33 import com.android.ex.camera2.pos.AutoFocusStateMachine; 34 import com.android.ex.camera2.pos.AutoFocusStateMachine.AutoFocusStateListener; 35 36 /** 37 * A focuser utility class to assist camera to do auto focus. 38 * <p> 39 * This class need create repeating request and single request to do auto focus. 40 * The repeating request is used to get the auto focus states; the single 41 * request is used to trigger the auto focus. This class assumes the camera device 42 * supports auto-focus. Don't use this class if the camera device doesn't have focuser 43 * unit. 44 * </p> 45 */ 46 public class Camera2Focuser implements AutoFocusStateListener { 47 private static final String TAG = "Focuser"; 48 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 49 50 private final AutoFocusStateMachine mAutoFocus = new AutoFocusStateMachine(this); 51 private final Handler mHandler; 52 private final AutoFocusListener mAutoFocusListener; 53 private final CameraDevice mCamera; 54 private final CameraCaptureSession mSession; 55 private final Surface mRequestSurface; 56 private final StaticMetadata mStaticInfo; 57 58 private int mAfRun = 0; 59 private MeteringRectangle[] mAfRegions; 60 private boolean mLocked = false; 61 private boolean mSuccess = false; 62 private CaptureRequest.Builder mRepeatingBuilder; 63 64 /** 65 * The callback interface to notify auto focus result. 66 */ 67 public interface AutoFocusListener { 68 /** 69 * This callback is called when auto focus completes and locked. 70 * 71 * @param success true if focus was successful, false if otherwise 72 */ onAutoFocusLocked(boolean success)73 void onAutoFocusLocked(boolean success); 74 } 75 76 /** 77 * Construct a focuser object, with given capture requestSurface, listener 78 * and handler. 79 * <p> 80 * The focuser object will use camera and requestSurface to submit capture 81 * request and receive focus state changes. The {@link AutoFocusListener} is 82 * used to notify the auto focus callback. 83 * </p> 84 * 85 * @param camera The camera device associated with this focuser 86 * @param session The camera capture session associated with this focuser 87 * @param requestSurface The surface to issue the capture request with 88 * @param listener The auto focus listener to notify AF result 89 * @param staticInfo The CameraCharacteristics of the camera device 90 * @param handler The handler used to post auto focus callbacks 91 * @throws CameraAccessException 92 */ Camera2Focuser(CameraDevice camera, CameraCaptureSession session, Surface requestSurface, AutoFocusListener listener, CameraCharacteristics staticInfo, Handler handler)93 public Camera2Focuser(CameraDevice camera, CameraCaptureSession session, Surface requestSurface, 94 AutoFocusListener listener, CameraCharacteristics staticInfo, Handler handler) 95 throws CameraAccessException { 96 if (camera == null) { 97 throw new IllegalArgumentException("camera must not be null"); 98 } 99 if (session == null) { 100 throw new IllegalArgumentException("session must not be null"); 101 } 102 if (listener == null) { 103 throw new IllegalArgumentException("listener must not be null"); 104 } 105 if (handler == null) { 106 throw new IllegalArgumentException("handler must not be null"); 107 } 108 if (requestSurface == null) { 109 throw new IllegalArgumentException("requestSurface must not be null"); 110 } 111 if (staticInfo == null) { 112 throw new IllegalArgumentException("staticInfo must not be null"); 113 } 114 115 mCamera = camera; 116 mSession = session; 117 mRequestSurface = requestSurface; 118 mAutoFocusListener = listener; 119 mStaticInfo = new StaticMetadata(staticInfo, 120 StaticMetadata.CheckLevel.ASSERT, /*collector*/null); 121 mHandler = handler; 122 123 if (!mStaticInfo.hasFocuser()) { 124 throw new IllegalArgumentException("this camera doesn't have a focuser"); 125 } 126 127 /** 128 * Begin by always being in passive auto focus. 129 */ 130 cancelAutoFocus(); 131 } 132 133 @Override onAutoFocusSuccess(CaptureResult result, boolean locked)134 public synchronized void onAutoFocusSuccess(CaptureResult result, boolean locked) { 135 mSuccess = true; 136 mLocked = locked; 137 138 if (locked) { 139 dispatchAutoFocusStatusLocked(/*success*/true); 140 } 141 } 142 143 @Override onAutoFocusFail(CaptureResult result, boolean locked)144 public synchronized void onAutoFocusFail(CaptureResult result, boolean locked) { 145 mSuccess = false; 146 mLocked = locked; 147 148 if (locked) { 149 dispatchAutoFocusStatusLocked(/*success*/false); 150 } 151 } 152 153 @Override onAutoFocusScan(CaptureResult result)154 public synchronized void onAutoFocusScan(CaptureResult result) { 155 mSuccess = false; 156 mLocked = false; 157 } 158 159 @Override onAutoFocusInactive(CaptureResult result)160 public synchronized void onAutoFocusInactive(CaptureResult result) { 161 mSuccess = false; 162 mLocked = false; 163 } 164 165 /** 166 * Start a active auto focus scan based on the given regions. 167 * 168 * <p>This is usually used for touch for focus, it can make the auto-focus converge based 169 * on some particular region aggressively. But it is usually slow as a full active scan 170 * is initiated. After the auto focus is converged, the {@link cancelAutoFocus} must be called 171 * to resume the continuous auto-focus.</p> 172 * 173 * @param afRegions The AF regions used by focuser auto focus, full active 174 * array size is used if afRegions is null. 175 * @throws CameraAccessException 176 */ touchForAutoFocus(MeteringRectangle[] afRegions)177 public synchronized void touchForAutoFocus(MeteringRectangle[] afRegions) 178 throws CameraAccessException { 179 startAutoFocusLocked(/*active*/true, afRegions); 180 } 181 182 /** 183 * Start auto focus scan. 184 * <p> 185 * Start an auto focus scan if it was not done yet. If AF passively focused, 186 * lock it. If AF is already locked, return. Otherwise, initiate a full 187 * active scan. This is suitable for still capture: focus should need to be 188 * accurate, but the AF latency also need to be as short as possible. 189 * </p> 190 * 191 * @param afRegions The AF regions used by focuser auto focus, full active 192 * array size is used if afRegions is null. 193 * @throws CameraAccessException 194 */ startAutoFocus(MeteringRectangle[] afRegions)195 public synchronized void startAutoFocus(MeteringRectangle[] afRegions) 196 throws CameraAccessException { 197 startAutoFocusLocked(/*forceActive*/false, afRegions); 198 } 199 200 /** 201 * Cancel ongoing auto focus, unlock the auto-focus if it was locked, and 202 * resume to passive continuous auto focus. 203 * 204 * @throws CameraAccessException 205 */ cancelAutoFocus()206 public synchronized void cancelAutoFocus() throws CameraAccessException { 207 mSuccess = false; 208 mLocked = false; 209 210 // reset the AF regions: 211 setAfRegions(null); 212 213 // Create request builders, the af regions are automatically updated. 214 mRepeatingBuilder = createRequestBuilder(); 215 CaptureRequest.Builder requestBuilder = createRequestBuilder(); 216 mAutoFocus.setPassiveAutoFocus(/*picture*/true, mRepeatingBuilder); 217 mAutoFocus.unlockAutoFocus(mRepeatingBuilder, requestBuilder); 218 CaptureCallback listener = createCaptureListener(); 219 mSession.setRepeatingRequest(mRepeatingBuilder.build(), listener, mHandler); 220 mSession.capture(requestBuilder.build(), listener, mHandler); 221 } 222 223 /** 224 * Get current AF mode. 225 * @return current AF mode 226 * @throws IllegalStateException if there auto focus is not running. 227 */ getCurrentAfMode()228 public synchronized int getCurrentAfMode() { 229 if (mRepeatingBuilder == null) { 230 throw new IllegalStateException("Auto focus is not running, unable to get AF mode"); 231 } 232 233 return mRepeatingBuilder.get(CaptureRequest.CONTROL_AF_MODE); 234 } 235 startAutoFocusLocked( boolean forceActive, MeteringRectangle[] afRegions)236 private void startAutoFocusLocked( 237 boolean forceActive, MeteringRectangle[] afRegions) throws CameraAccessException { 238 239 setAfRegions(afRegions); 240 mAfRun++; 241 242 // Create request builders, the af regions are automatically updated. 243 mRepeatingBuilder = createRequestBuilder(); 244 CaptureRequest.Builder requestBuilder = createRequestBuilder(); 245 if (forceActive) { 246 startAutoFocusFullActiveLocked(); 247 } else { 248 // Not forcing a full active scan. If AF passively focused, lock it. If AF is already 249 // locked, return. Otherwise, initiate a full active scan. 250 if (mSuccess && mLocked) { 251 dispatchAutoFocusStatusLocked(/*success*/true); 252 return; 253 } else if (mSuccess) { 254 mAutoFocus.lockAutoFocus(mRepeatingBuilder, requestBuilder); 255 CaptureCallback listener = createCaptureListener(); 256 mSession.setRepeatingRequest(mRepeatingBuilder.build(), listener, mHandler); 257 mSession.capture(requestBuilder.build(), listener, mHandler); 258 } else { 259 startAutoFocusFullActiveLocked(); 260 } 261 } 262 } 263 startAutoFocusFullActiveLocked()264 private void startAutoFocusFullActiveLocked() throws CameraAccessException { 265 // Create request builders, the af regions are automatically updated. 266 mRepeatingBuilder = createRequestBuilder(); 267 CaptureRequest.Builder requestBuilder = createRequestBuilder(); 268 mAutoFocus.setActiveAutoFocus(mRepeatingBuilder, requestBuilder); 269 if (mRepeatingBuilder.get(CaptureRequest.CONTROL_AF_TRIGGER) 270 != CaptureRequest.CONTROL_AF_TRIGGER_IDLE) { 271 throw new AssertionError("Wrong trigger set in repeating request"); 272 } 273 if (requestBuilder.get(CaptureRequest.CONTROL_AF_TRIGGER) 274 != CaptureRequest.CONTROL_AF_TRIGGER_START) { 275 throw new AssertionError("Wrong trigger set in queued request"); 276 } 277 mAutoFocus.resetState(); 278 279 CaptureCallback listener = createCaptureListener(); 280 mSession.setRepeatingRequest(mRepeatingBuilder.build(), listener, mHandler); 281 mSession.capture(requestBuilder.build(), listener, mHandler); 282 } 283 dispatchAutoFocusStatusLocked(final boolean success)284 private void dispatchAutoFocusStatusLocked(final boolean success) { 285 mHandler.post(new Runnable() { 286 @Override 287 public void run() { 288 mAutoFocusListener.onAutoFocusLocked(success); 289 } 290 }); 291 } 292 293 /** 294 * Create request builder, set the af regions. 295 * @throws CameraAccessException 296 */ createRequestBuilder()297 private CaptureRequest.Builder createRequestBuilder() throws CameraAccessException { 298 CaptureRequest.Builder requestBuilder = 299 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 300 301 requestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, mAfRegions); 302 requestBuilder.addTarget(mRequestSurface); 303 304 return requestBuilder; 305 } 306 307 /** 308 * Set AF regions, fall back to default region if afRegions is null. 309 * 310 * @param afRegions The AF regions to set 311 * @throws IllegalArgumentException if the region is malformed (length is 0). 312 */ setAfRegions(MeteringRectangle[] afRegions)313 private void setAfRegions(MeteringRectangle[] afRegions) { 314 if (afRegions == null) { 315 setDefaultAfRegions(); 316 return; 317 } 318 // Throw IAE if AF regions are malformed. 319 if (afRegions.length == 0) { 320 throw new IllegalArgumentException("afRegions is malformed, length: 0"); 321 } 322 323 mAfRegions = afRegions; 324 } 325 326 /** 327 * Set default AF region to full active array size. 328 */ setDefaultAfRegions()329 private void setDefaultAfRegions() { 330 // Initialize AF regions with all zeros, meaning that it is up to camera device to device 331 // the regions used by AF. 332 mAfRegions = new MeteringRectangle[] { 333 new MeteringRectangle(0, 0, 0, 0, MeteringRectangle.METERING_WEIGHT_DONT_CARE)}; 334 } createCaptureListener()335 private CaptureCallback createCaptureListener() { 336 337 int thisAfRun; 338 synchronized (this) { 339 thisAfRun = mAfRun; 340 } 341 342 final int finalAfRun = thisAfRun; 343 344 return new CaptureCallback() { 345 private long mLatestFrameCount = -1; 346 347 @Override 348 public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, 349 CaptureResult result) { 350 // In case of a partial result, send to focuser if necessary 351 // 3A fields are present 352 if (result.get(CaptureResult.CONTROL_AF_STATE) != null && 353 result.get(CaptureResult.CONTROL_AF_MODE) != null) { 354 if (VERBOSE) { 355 Log.v(TAG, "Focuser - got early AF state"); 356 } 357 358 dispatchToFocuser(result); 359 } 360 } 361 362 @Override 363 public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, 364 TotalCaptureResult result) { 365 dispatchToFocuser(result); 366 } 367 368 private void dispatchToFocuser(CaptureResult result) { 369 int afRun; 370 synchronized (Camera2Focuser.this) { 371 // In case of partial results, don't send AF update twice 372 long frameCount = result.getFrameNumber(); 373 if (frameCount <= mLatestFrameCount) return; 374 mLatestFrameCount = frameCount; 375 376 afRun = mAfRun; 377 } 378 379 if (afRun != finalAfRun) { 380 if (VERBOSE) { 381 Log.w(TAG, 382 "onCaptureCompleted - Ignoring results from previous AF run " 383 + finalAfRun); 384 } 385 return; 386 } 387 388 mAutoFocus.onCaptureCompleted(result); 389 } 390 }; 391 } 392 } 393