AndroidCamera2AgentImpl.java revision 50f5b019ba3f333a09a1beb9667fd7290082dc31
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 17package com.android.ex.camera2.portability; 18 19import android.annotation.TargetApi; 20import android.content.Context; 21import android.graphics.Rect; 22import android.graphics.SurfaceTexture; 23import android.hardware.camera2.CameraAccessException; 24import android.hardware.camera2.CameraCaptureSession; 25import android.hardware.camera2.CameraCharacteristics; 26import android.hardware.camera2.CameraDevice; 27import android.hardware.camera2.CameraManager; 28import android.hardware.camera2.CaptureFailure; 29import android.hardware.camera2.CaptureRequest; 30import android.hardware.camera2.CaptureResult; 31import android.hardware.camera2.TotalCaptureResult; 32import android.hardware.camera2.params.MeteringRectangle; 33import android.os.Build; 34import android.os.Handler; 35import android.os.HandlerThread; 36import android.os.Looper; 37import android.os.Message; 38import android.view.Surface; 39 40import com.android.ex.camera2.portability.debug.Log; 41 42import java.util.ArrayList; 43import java.util.Arrays; 44import java.util.HashSet; 45import java.util.List; 46import java.util.Set; 47 48/** 49 * A class to implement {@link CameraAgent} of the Android camera2 framework. 50 */ 51class AndroidCamera2AgentImpl extends CameraAgent { 52 private static final Log.Tag TAG = new Log.Tag("AndCam2AgntImp"); 53 54 private final Camera2Handler mCameraHandler; 55 private final HandlerThread mCameraHandlerThread; 56 private final CameraStateHolder mCameraState; 57 private final DispatchThread mDispatchThread; 58 private final CameraManager mCameraManager; 59 60 /** 61 * Number of camera devices. The length of {@code mCameraDevices} does not reveal this 62 * information because that list may contain since-invalidated indices. 63 */ 64 private int mNumCameraDevices; 65 66 /** 67 * Transformation between integral camera indices and the {@link java.lang.String} indices used 68 * by the underlying API. Note that devices may disappear because they've been disconnected or 69 * have otherwise gone offline. Because we need to keep the meanings of whatever indices we 70 * expose stable, we cannot simply remove them in such a case; instead, we insert {@code null}s 71 * to invalidate any such indices. Whenever new devices appear, they are appended to the end of 72 * the list, and thereby assigned the lowest index that has never yet been used. 73 */ 74 private final List<String> mCameraDevices; 75 76 AndroidCamera2AgentImpl(Context context) { 77 mCameraHandlerThread = new HandlerThread("Camera2 Handler Thread"); 78 mCameraHandlerThread.start(); 79 mCameraHandler = new Camera2Handler(mCameraHandlerThread.getLooper()); 80 mCameraState = new AndroidCamera2StateHolder(); 81 mDispatchThread = new DispatchThread(mCameraHandler, mCameraHandlerThread); 82 mDispatchThread.start(); 83 mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); 84 85 mNumCameraDevices = 0; 86 mCameraDevices = new ArrayList<String>(); 87 updateCameraDevices(); 88 } 89 90 /** 91 * Updates the camera device index assignments stored in {@link mCameraDevices}, without 92 * reappropriating any currently-assigned index. 93 * @return Whether the operation was successful 94 */ 95 private boolean updateCameraDevices() { 96 try { 97 String[] currentCameraDevices = mCameraManager.getCameraIdList(); 98 Set<String> currentSet = new HashSet<String>(Arrays.asList(currentCameraDevices)); 99 100 // Invalidate the indices assigned to any camera devices that are no longer present 101 for (int index = 0; index < mCameraDevices.size(); ++index) { 102 if (!currentSet.contains(mCameraDevices.get(index))) { 103 mCameraDevices.set(index, null); 104 --mNumCameraDevices; 105 } 106 } 107 108 // Assign fresh indices to any new camera devices 109 currentSet.removeAll(mCameraDevices); // The devices we didn't know about 110 for (String device : currentCameraDevices) { 111 if (currentSet.contains(device)) { 112 mCameraDevices.add(device); 113 ++mNumCameraDevices; 114 } 115 } 116 117 return true; 118 } catch (CameraAccessException ex) { 119 Log.e(TAG, "Could not get device listing from camera subsystem", ex); 120 return false; 121 } 122 } 123 124 // TODO: Implement 125 @Override 126 public void setCameraDefaultExceptionCallback(CameraExceptionCallback callback, 127 Handler handler) {} 128 129 // TODO: Implement 130 @Override 131 public void recycle() {} 132 133 // TODO: Some indices may now be invalid; ensure everyone can handle that and update the docs 134 @Override 135 public CameraDeviceInfo getCameraDeviceInfo() { 136 updateCameraDevices(); 137 return new AndroidCamera2DeviceInfo(mCameraManager, mCameraDevices.toArray(new String[0]), 138 mNumCameraDevices); 139 } 140 141 @Override 142 protected Handler getCameraHandler() { 143 return mCameraHandler; 144 } 145 146 @Override 147 protected DispatchThread getDispatchThread() { 148 return mDispatchThread; 149 } 150 151 private class Camera2Handler extends HistoryHandler { 152 // Caller-provided when leaving CAMERA_UNOPENED state: 153 private CameraOpenCallback mOpenCallback; 154 private int mCameraIndex; 155 private String mCameraId; 156 157 // Available in CAMERA_UNCONFIGURED state and above: 158 private CameraDevice mCamera; 159 private AndroidCamera2ProxyImpl mCameraProxy; 160 private CaptureRequest.Builder mPersistentRequestBuilder; 161 private Rect mActiveArray; 162 163 // Available in CAMERA_CONFIGURED state and above: 164 private Size mPreviewSize; 165 private Size mPhotoSize; 166 167 // Available in PREVIEW_READY state and above: 168 private SurfaceTexture mPreviewTexture; 169 private Surface mPreviewSurface; 170 private CameraCaptureSession mSession; 171 172 // Available from the beginning of PREVIEW_ACTIVE until the first preview frame arrives: 173 private CameraStartPreviewCallback mOneshotPreviewingCallback; 174 175 // Available in FOCUS_LOCKED between AF trigger receipt and whenever the lens stops moving: 176 private CameraAFCallback mOneshotAfCallback; 177 178 // Available whenever setAutoFocusMoveCallback() was last invoked with a non-null argument: 179 private CameraAFMoveCallback mPassiveAfCallback; 180 181 Camera2Handler(Looper looper) { 182 super(looper); 183 } 184 185 @Override 186 public void handleMessage(final Message msg) { 187 super.handleMessage(msg); 188 try { 189 switch(msg.what) { 190 case CameraActions.OPEN_CAMERA: 191 case CameraActions.RECONNECT: { 192 CameraOpenCallback openCallback = (CameraOpenCallback) msg.obj; 193 int cameraIndex = msg.arg1; 194 195 if (mCameraState.getState() != AndroidCamera2StateHolder.CAMERA_UNOPENED) { 196 openCallback.onDeviceOpenedAlready(cameraIndex, 197 generateHistoryString(cameraIndex)); 198 break; 199 } 200 201 mOpenCallback = openCallback; 202 mCameraIndex = cameraIndex; 203 mCameraId = mCameraDevices.get(mCameraIndex); 204 Log.i(TAG, String.format("Opening camera index %d (id %s) with camera2 API", 205 cameraIndex, mCameraId)); 206 207 if (mCameraId == null) { 208 mOpenCallback.onCameraDisabled(msg.arg1); 209 break; 210 } 211 mCameraManager.openCamera(mCameraId, mCameraDeviceStateListener, this); 212 213 break; 214 } 215 216 case CameraActions.RELEASE: { 217 if (mCameraState.getState() == AndroidCamera2StateHolder.CAMERA_UNOPENED) { 218 Log.w(TAG, "Ignoring release at inappropriate time"); 219 break; 220 } 221 222 if (mSession != null) { 223 closePreviewSession(); 224 mSession = null; 225 } 226 if (mCamera != null) { 227 mCamera.close(); 228 mCamera = null; 229 } 230 mCameraProxy = null; 231 mPersistentRequestBuilder = null; 232 mActiveArray = null; 233 if (mPreviewSurface != null) { 234 mPreviewSurface.release(); 235 mPreviewSurface = null; 236 } 237 mPreviewTexture = null; 238 mPreviewSize = null; 239 mPhotoSize = null; 240 mCameraIndex = 0; 241 mCameraId = null; 242 mCameraState.setState(AndroidCamera2StateHolder.CAMERA_UNOPENED); 243 break; 244 } 245 246 /*case CameraActions.UNLOCK: { 247 break; 248 } 249 250 case CameraActions.LOCK: { 251 break; 252 }*/ 253 254 case CameraActions.SET_PREVIEW_TEXTURE_ASYNC: { 255 setPreviewTexture((SurfaceTexture) msg.obj); 256 break; 257 } 258 259 case CameraActions.START_PREVIEW_ASYNC: { 260 if (mCameraState.getState() != 261 AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) { 262 // TODO: Provide better feedback here? 263 Log.w(TAG, "Refusing to start preview at inappropriate time"); 264 break; 265 } 266 267 mOneshotPreviewingCallback = (CameraStartPreviewCallback) msg.obj; 268 mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE); 269 try { 270 mSession.setRepeatingRequest(mPersistentRequestBuilder.build(), 271 /*listener*/mCameraFocusStateListener, /*handler*/this); 272 } catch(CameraAccessException ex) { 273 Log.w(TAG, "Unable to start preview", ex); 274 mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY); 275 } 276 break; 277 } 278 279 case CameraActions.STOP_PREVIEW: { 280 if (mCameraState.getState() < 281 AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) { 282 Log.w(TAG, "Refusing to stop preview at inappropriate time"); 283 break; 284 } 285 286 mSession.stopRepeating(); 287 mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY); 288 break; 289 } 290 291 /*case CameraActions.SET_PREVIEW_CALLBACK_WITH_BUFFER: { 292 break; 293 } 294 295 case CameraActions.ADD_CALLBACK_BUFFER: { 296 break; 297 } 298 299 case CameraActions.SET_PREVIEW_DISPLAY_ASYNC: { 300 break; 301 } 302 303 case CameraActions.SET_PREVIEW_CALLBACK: { 304 break; 305 } 306 307 case CameraActions.SET_ONE_SHOT_PREVIEW_CALLBACK: { 308 break; 309 } 310 311 case CameraActions.SET_PARAMETERS: { 312 break; 313 } 314 315 case CameraActions.GET_PARAMETERS: { 316 break; 317 } 318 319 case CameraActions.REFRESH_PARAMETERS: { 320 break; 321 }*/ 322 323 case CameraActions.APPLY_SETTINGS: { 324 CameraSettings settings = (CameraSettings) msg.obj; 325 applyToRequest(settings); 326 break; 327 } 328 329 case CameraActions.AUTO_FOCUS: { 330 // We only support locking the focus while a preview is being displayed. 331 // However, it can be requested multiple times in succession; the effect of 332 // the subsequent invocations is determined by the focus mode defined in the 333 // provided CameraSettings object. In passive (CONTINUOUS_*) mode, the 334 // duplicate requests are no-ops and leave the lens locked at its current 335 // position, but in active (AUTO) mode, they perform another scan and lock 336 // once that is finished. In any manual focus mode, this call is a no-op, 337 // and most notably, this is the only case where the callback isn't invoked. 338 if (mCameraState.getState() < 339 AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) { 340 Log.w(TAG, "Ignoring attempt to autofocus without preview"); 341 break; 342 } 343 344 // The earliest we can reliably tell whether the autofocus has locked in 345 // response to our latest request is when our one-time capture completes. 346 // However, it will probably take longer than that, so once that happens, 347 // just start checking the repeating preview requests as they complete. 348 final CameraAFCallback callback = (CameraAFCallback) msg.obj; 349 CameraCaptureSession.CaptureListener deferredCallbackSetter = 350 new CameraCaptureSession.CaptureListener() { 351 @Override 352 public void onCaptureCompleted(CameraCaptureSession session, 353 CaptureRequest request, 354 TotalCaptureResult result) { 355 // Now our mCameraFocusStateListener will invoke the callback the 356 // first time it finds the focus motor to be locked. 357 mOneshotAfCallback = callback; 358 } 359 360 @Override 361 public void onCaptureFailed(CameraCaptureSession session, 362 CaptureRequest request, 363 CaptureFailure failure) { 364 Log.e(TAG, "Focusing failed with reason " + failure.getReason()); 365 callback.onAutoFocus(false, mCameraProxy); 366 }}; 367 368 // Send a one-time capture to trigger the camera driver to lock focus. 369 mCameraState.setState(AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED); 370 mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, 371 CaptureRequest.CONTROL_AF_TRIGGER_START); 372 try { 373 mSession.capture(mPersistentRequestBuilder.build(), 374 /*listener*/deferredCallbackSetter, /*handler*/ this); 375 } catch(CameraAccessException ex) { 376 Log.e(TAG, "Unable to lock autofocus", ex); 377 mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE); 378 } 379 mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, 380 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 381 break; 382 } 383 384 case CameraActions.CANCEL_AUTO_FOCUS: { 385 // Why would you want to unlock the lens if it isn't already locked? 386 if (mCameraState.getState() < 387 AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) { 388 Log.w(TAG, "Ignoring attempt to release focus lock without preview"); 389 break; 390 } 391 392 // Send a one-time capture to trigger the camera driver to resume scanning. 393 mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE); 394 mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, 395 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); 396 try { 397 mSession.capture(mPersistentRequestBuilder.build(), 398 /*listener*/null, /*handler*/this); 399 } catch(CameraAccessException ex) { 400 Log.e(TAG, "Unable to cancel autofocus", ex); 401 mCameraState.setState( 402 AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED); 403 } 404 mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, 405 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 406 break; 407 } 408 409 case CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK: { 410 mPassiveAfCallback = (CameraAFMoveCallback) msg.obj; 411 break; 412 } 413 414 /*case CameraActions.SET_ZOOM_CHANGE_LISTENER: { 415 break; 416 } 417 418 case CameraActions.SET_FACE_DETECTION_LISTENER: { 419 break; 420 } 421 422 case CameraActions.START_FACE_DETECTION: { 423 break; 424 } 425 426 case CameraActions.STOP_FACE_DETECTION: { 427 break; 428 } 429 430 case CameraActions.SET_ERROR_CALLBACK: { 431 break; 432 } 433 434 case CameraActions.ENABLE_SHUTTER_SOUND: { 435 break; 436 } 437 438 case CameraActions.SET_DISPLAY_ORIENTATION: { 439 break; 440 } 441 442 case CameraActions.CAPTURE_PHOTO: { 443 break; 444 }*/ 445 446 default: { 447 // TODO: Rephrase once everything has been implemented 448 throw new RuntimeException("Unimplemented CameraProxy message=" + msg.what); 449 } 450 } 451 } catch (final Exception ex) { 452 if (msg.what != CameraActions.RELEASE && mCamera != null) { 453 // TODO: Handle this better 454 mCamera.close(); 455 mCamera = null; 456 } else if (mCamera == null) { 457 if (msg.what == CameraActions.OPEN_CAMERA) { 458 if (mOpenCallback != null) { 459 mOpenCallback.onDeviceOpenFailure(mCameraIndex, 460 generateHistoryString(mCameraIndex)); 461 } 462 } else { 463 Log.w(TAG, "Cannot handle message " + msg.what + ", mCamera is null"); 464 } 465 return; 466 } 467 468 if (ex instanceof RuntimeException) { 469 post(new Runnable() { 470 @Override 471 public void run() { 472 sCameraExceptionCallback.onCameraException((RuntimeException) ex); 473 }}); 474 } 475 } 476 } 477 478 public CameraSettings buildSettings(AndroidCamera2Capabilities caps) { 479 return new AndroidCamera2Settings(caps, mPersistentRequestBuilder, mPreviewSize, 480 mPhotoSize); 481 } 482 483 /** 484 * Simply propagates settings from provided {@link CameraSettings} 485 * object to our {@link CaptureRequest.Builder} for use in captures. 486 * <p>Most conversions to match the API 2 formats are performed by 487 * {@link AndroidCamera2Capabilities.IntegralStringifier}; otherwise 488 * any final adjustments are done here before updating the builder.</p> 489 * 490 * @param settings The new/updated settings 491 */ 492 // TODO: Finish implementation to add support for all settings 493 private void applyToRequest(CameraSettings settings) { 494 // TODO: If invoked when in PREVIEW_READY state, a new preview size will not take effect 495 AndroidCamera2Capabilities.IntegralStringifier intifier = 496 mCameraProxy.getSpecializedCapabilities().getIntegralStringifier(); 497 mPreviewSize = settings.getCurrentPreviewSize(); 498 mPhotoSize = settings.getCurrentPhotoSize(); 499 mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, 500 intifier.intify(settings.getCurrentFocusMode())); 501 502 mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, 503 legacyAreasToMeteringRectangles(settings.getFocusAreas())); 504 mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AE_REGIONS, 505 legacyAreasToMeteringRectangles(settings.getMeteringAreas())); 506 507 if (settings.getCurrentFlashMode() != CameraCapabilities.FlashMode.NO_FLASH) { 508 mPersistentRequestBuilder.set(CaptureRequest.FLASH_MODE, 509 intifier.intify(settings.getCurrentFlashMode())); 510 } 511 if (settings.getCurrentSceneMode() != CameraCapabilities.SceneMode.NO_SCENE_MODE) { 512 mPersistentRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, 513 intifier.intify(settings.getCurrentSceneMode())); 514 } 515 516 if (mCameraState.getState() >= AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) { 517 // If we're already previewing, reflect most settings immediately 518 try { 519 mSession.setRepeatingRequest(mPersistentRequestBuilder.build(), 520 /*listener*/mCameraFocusStateListener, /*handler*/this); 521 } catch (CameraAccessException ex) { 522 Log.e(TAG, "Failed to apply updated request settings", ex); 523 } 524 } else if (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) { 525 // If we're already ready to preview, this doesn't regress our state 526 mCameraState.setState(AndroidCamera2StateHolder.CAMERA_CONFIGURED); 527 } 528 } 529 530 private MeteringRectangle[] legacyAreasToMeteringRectangles( 531 List<android.hardware.Camera.Area> reference) { 532 MeteringRectangle[] transformed = null; 533 if (reference.size() > 0) { 534 535 transformed = new MeteringRectangle[reference.size()]; 536 for (int index = 0; index < reference.size(); ++index) { 537 android.hardware.Camera.Area source = reference.get(index); 538 Rect rectangle = source.rect; 539 540 // Old API coordinates were [-1000,1000]; new ones are [0,ACTIVE_ARRAY_SIZE). 541 double oldLeft = (rectangle.left + 1000) / 2000.0; 542 double oldTop = (rectangle.top + 1000) / 2000.0; 543 double oldRight = (rectangle.right + 1000) / 2000.0; 544 double oldBottom = (rectangle.bottom + 1000) / 2000.0; 545 int left = toIntConstrained( 546 mActiveArray.width() * oldLeft + mActiveArray.left, 547 0, mActiveArray.width() - 1); 548 int top = toIntConstrained( 549 mActiveArray.height() * oldTop + mActiveArray.top, 550 0, mActiveArray.height() - 1); 551 int right = toIntConstrained( 552 mActiveArray.width() * oldRight + mActiveArray.left, 553 0, mActiveArray.width() - 1); 554 int bottom = toIntConstrained( 555 mActiveArray.height() * oldBottom + mActiveArray.top, 556 0, mActiveArray.height() - 1); 557 transformed[index] = new MeteringRectangle(left, top, 558 right - left, bottom - top, source.weight); 559 } 560 } 561 return transformed; 562 } 563 564 private int toIntConstrained(double original, int min, int max) { 565 original = Math.max(original, min); 566 original = Math.min(original, max); 567 return (int) original; 568 } 569 570 private void setPreviewTexture(SurfaceTexture surfaceTexture) { 571 // TODO: Must be called after providing a .*Settings populated with sizes 572 // TODO: We don't technically offer a selection of sizes tailored to SurfaceTextures! 573 574 // TODO: Handle this error condition with a callback or exception 575 if (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_CONFIGURED) { 576 Log.w(TAG, "Ignoring texture setting at inappropriate time"); 577 return; 578 } 579 580 // Avoid initializing another capture session unless we absolutely have to 581 if (surfaceTexture == mPreviewTexture) { 582 Log.i(TAG, "Optimizing out redundant preview texture setting"); 583 return; 584 } 585 586 if (mSession != null) { 587 closePreviewSession(); 588 } 589 590 mPreviewTexture = surfaceTexture; 591 surfaceTexture.setDefaultBufferSize(mPreviewSize.width(), mPreviewSize.height()); 592 593 if (mPreviewSurface != null) { 594 mPersistentRequestBuilder.removeTarget(mPreviewSurface); 595 mPreviewSurface.release(); 596 } 597 mPreviewSurface = new Surface(surfaceTexture); 598 mPersistentRequestBuilder.addTarget(mPreviewSurface); 599 600 try { 601 mCamera.createCaptureSession(Arrays.asList(mPreviewSurface), 602 mCameraPreviewStateListener, this); 603 } catch (CameraAccessException ex) { 604 Log.e(TAG, "Failed to create camera capture session", ex); 605 } 606 } 607 608 private void closePreviewSession() { 609 try { 610 mSession.abortCaptures(); 611 mSession = null; 612 } catch (CameraAccessException ex) { 613 Log.e(TAG, "Failed to close existing camera capture session", ex); 614 } 615 mCameraState.setState(AndroidCamera2StateHolder.CAMERA_CONFIGURED); 616 } 617 618 // This listener monitors our connection to and disconnection from camera devices. 619 private CameraDevice.StateListener mCameraDeviceStateListener = 620 new CameraDevice.StateListener() { 621 @Override 622 public void onOpened(CameraDevice camera) { 623 mCamera = camera; 624 if (mOpenCallback != null) { 625 try { 626 CameraCharacteristics props = 627 mCameraManager.getCameraCharacteristics(mCameraId); 628 mCameraProxy = new AndroidCamera2ProxyImpl(mCameraIndex, mCamera, 629 getCameraDeviceInfo().getCharacteristics(mCameraIndex), props); 630 mPersistentRequestBuilder = 631 camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 632 mActiveArray = 633 props.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 634 mCameraState.setState(AndroidCamera2StateHolder.CAMERA_UNCONFIGURED); 635 mOpenCallback.onCameraOpened(mCameraProxy); 636 } catch (CameraAccessException ex) { 637 mOpenCallback.onDeviceOpenFailure(mCameraIndex, 638 generateHistoryString(mCameraIndex)); 639 } 640 } 641 } 642 643 @Override 644 public void onDisconnected(CameraDevice camera) { 645 Log.w(TAG, "Camera device '" + mCameraIndex + "' was disconnected"); 646 } 647 648 @Override 649 public void onError(CameraDevice camera, int error) { 650 Log.e(TAG, "Camera device '" + mCameraIndex + "' encountered error code '" + 651 error + '\''); 652 if (mOpenCallback != null) { 653 mOpenCallback.onDeviceOpenFailure(mCameraIndex, 654 generateHistoryString(mCameraIndex)); 655 } 656 }}; 657 658 // This listener monitors our camera session (i.e. our transition into and out of preview). 659 private CameraCaptureSession.StateListener mCameraPreviewStateListener = 660 new CameraCaptureSession.StateListener() { 661 @Override 662 public void onConfigured(CameraCaptureSession session) { 663 mSession = session; 664 mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY); 665 } 666 667 @Override 668 public void onConfigureFailed(CameraCaptureSession session) { 669 // TODO: Invoke a callback 670 Log.e(TAG, "Failed to configure the camera for capture"); 671 } 672 673 @Override 674 public void onActive(CameraCaptureSession session) { 675 if (mOneshotPreviewingCallback != null) { 676 // The session is up and processing preview requests. Inform the caller. 677 mOneshotPreviewingCallback.onPreviewStarted(); 678 mOneshotPreviewingCallback = null; 679 } 680 }}; 681 682 // This listener monitors requested captures and notifies any relevant callbacks. 683 private CameraCaptureSession.CaptureListener mCameraFocusStateListener = 684 new CameraCaptureSession.CaptureListener() { 685 private int mLastAfState = -1; 686 687 @Override 688 public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, 689 TotalCaptureResult result) { 690 Integer afStateMaybe = result.get(CaptureResult.CONTROL_AF_STATE); 691 if (afStateMaybe != null) { 692 int afState = afStateMaybe; 693 boolean afStateChanged = false; 694 if (afState != mLastAfState) { 695 mLastAfState = afState; 696 afStateChanged = true; 697 } 698 699 switch (afState) { 700 case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN: 701 case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED: 702 case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED: { 703 if (afStateChanged && mPassiveAfCallback != null) { 704 // A CameraAFMoveCallback is attached. If we just started to scan, 705 // the motor is moving; otherwise, it has settled. 706 mPassiveAfCallback.onAutoFocusMoving( 707 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN, 708 mCameraProxy); 709 } 710 break; 711 } 712 713 case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED: 714 case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED: { 715 if (mOneshotAfCallback != null) { 716 // A call to autoFocus() was just made to request a focus lock. 717 // Notify the caller that the lens is now indefinitely fixed, and 718 // report whether the image we're now stuck with is in focus. 719 mOneshotAfCallback.onAutoFocus( 720 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED, 721 mCameraProxy); 722 mOneshotAfCallback = null; 723 } 724 break; 725 } 726 } 727 } 728 } 729 730 @Override 731 public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, 732 CaptureFailure failure) { 733 Log.e(TAG, "Capture attempt failed with reason " + failure.getReason()); 734 }}; 735 } 736 737 private class AndroidCamera2ProxyImpl extends CameraAgent.CameraProxy { 738 private final int mCameraIndex; 739 private final CameraDevice mCamera; 740 private final CameraDeviceInfo.Characteristics mCharacteristics; 741 private final AndroidCamera2Capabilities mCapabilities; 742 743 public AndroidCamera2ProxyImpl(int cameraIndex, CameraDevice camera, 744 CameraDeviceInfo.Characteristics characteristics, 745 CameraCharacteristics properties) { 746 mCameraIndex = cameraIndex; 747 mCamera = camera; 748 mCharacteristics = characteristics; 749 mCapabilities = new AndroidCamera2Capabilities(properties); 750 } 751 752 // TODO: Implement 753 @Override 754 public android.hardware.Camera getCamera() { return null; } 755 756 @Override 757 public int getCameraId() { 758 return mCameraIndex; 759 } 760 761 @Override 762 public CameraDeviceInfo.Characteristics getCharacteristics() { 763 return mCharacteristics; 764 } 765 766 @Override 767 public CameraCapabilities getCapabilities() { 768 return mCapabilities; 769 } 770 771 private AndroidCamera2Capabilities getSpecializedCapabilities() { 772 return mCapabilities; 773 } 774 775 // TODO: Implement 776 @Override 777 public void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb) {} 778 779 // TODO: Implement 780 @Override 781 public void setOneShotPreviewCallback(Handler handler, CameraPreviewDataCallback cb) {} 782 783 // TODO: Implement 784 @Override 785 public void setPreviewDataCallbackWithBuffer(Handler handler, CameraPreviewDataCallback cb) 786 {} 787 788 // TODO: Implement 789 public void addCallbackBuffer(final byte[] callbackBuffer) {} 790 791 @Override 792 public void autoFocus(final Handler handler, final CameraAFCallback cb) { 793 mDispatchThread.runJob(new Runnable() { 794 @Override 795 public void run() { 796 CameraAFCallback cbForward = null; 797 if (cb != null) { 798 cbForward = new CameraAFCallback() { 799 @Override 800 public void onAutoFocus(final boolean focused, 801 final CameraProxy camera) { 802 handler.post(new Runnable() { 803 @Override 804 public void run() { 805 cb.onAutoFocus(focused, camera); 806 }}); 807 }}; 808 } 809 810 mCameraState.waitForStates(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE | 811 AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED); 812 mCameraHandler.obtainMessage(CameraActions.AUTO_FOCUS, cbForward) 813 .sendToTarget(); 814 }}); 815 } 816 817 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 818 @Override 819 public void setAutoFocusMoveCallback(final Handler handler, final CameraAFMoveCallback cb) { 820 mDispatchThread.runJob(new Runnable() { 821 @Override 822 public void run() { 823 CameraAFMoveCallback cbForward = null; 824 if (cb != null) { 825 cbForward = new CameraAFMoveCallback() { 826 @Override 827 public void onAutoFocusMoving(final boolean moving, 828 final CameraProxy camera) { 829 handler.post(new Runnable() { 830 @Override 831 public void run() { 832 cb.onAutoFocusMoving(moving, camera); 833 }}); 834 }}; 835 } 836 837 mCameraHandler.obtainMessage(CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK, 838 cbForward).sendToTarget(); 839 }}); 840 } 841 842 // TODO: Implement 843 @Override 844 public void takePicture(Handler handler, 845 CameraShutterCallback shutter, 846 CameraPictureCallback raw, 847 CameraPictureCallback postview, 848 CameraPictureCallback jpeg) {} 849 850 // TODO: Remove this method override once we handle the message 851 @Override 852 public void setDisplayOrientation(int degrees) {} 853 854 // TODO: Implement 855 @Override 856 public void setZoomChangeListener(android.hardware.Camera.OnZoomChangeListener listener) {} 857 858 // TODO: Implement 859 @Override 860 public void setFaceDetectionCallback(Handler handler, CameraFaceDetectionCallback callback) 861 {} 862 863 // TODO: Remove this method override once we handle this message 864 @Override 865 public void startFaceDetection() {} 866 867 // TODO: Remove this method override once we handle this message 868 @Override 869 public void stopFaceDetection() {} 870 871 // TODO: Implement 872 @Override 873 public void setErrorCallback(Handler handler, CameraErrorCallback cb) {} 874 875 // TODO: Implement 876 @Override 877 public void setParameters(android.hardware.Camera.Parameters params) {} 878 879 // TODO: Implement 880 @Override 881 public android.hardware.Camera.Parameters getParameters() { return null; } 882 883 @Override 884 public CameraSettings getSettings() { 885 return mCameraHandler.buildSettings(mCapabilities); 886 } 887 888 @Override 889 public boolean applySettings(CameraSettings settings) { 890 return applySettingsHelper(settings, AndroidCamera2StateHolder.CAMERA_UNCONFIGURED | 891 AndroidCamera2StateHolder.CAMERA_CONFIGURED | 892 AndroidCamera2StateHolder.CAMERA_PREVIEW_READY); 893 } 894 895 // TODO: Implement 896 @Override 897 public String dumpDeviceSettings() { return null; } 898 899 @Override 900 public Handler getCameraHandler() { 901 return AndroidCamera2AgentImpl.this.getCameraHandler(); 902 } 903 904 @Override 905 public DispatchThread getDispatchThread() { 906 return AndroidCamera2AgentImpl.this.getDispatchThread(); 907 } 908 909 @Override 910 public CameraStateHolder getCameraState() { 911 return mCameraState; 912 } 913 } 914 915 /** A linear state machine: each state entails all the states below it. */ 916 private static class AndroidCamera2StateHolder extends CameraStateHolder { 917 // Usage flow: openCamera() -> applySettings() -> setPreviewTexture() -> startPreview() -> 918 // autoFocus() -> takePicture() 919 /* Camera states */ 920 /** No camera device is opened. */ 921 public static final int CAMERA_UNOPENED = 1; 922 /** A camera is opened, but no settings have been provided. */ 923 public static final int CAMERA_UNCONFIGURED = 2; 924 /** The open camera has been configured by providing it with settings. */ 925 public static final int CAMERA_CONFIGURED = 3; 926 /** A capture session is ready to stream a preview, but still has no repeating request. */ 927 public static final int CAMERA_PREVIEW_READY = 4; 928 /** A preview is currently being streamed. */ 929 public static final int CAMERA_PREVIEW_ACTIVE = 5; 930 /** The lens is locked on a particular region. */ 931 public static final int CAMERA_FOCUS_LOCKED = 6; 932 933 public AndroidCamera2StateHolder() { 934 this(CAMERA_UNOPENED); 935 } 936 937 public AndroidCamera2StateHolder(int state) { 938 super(state); 939 } 940 } 941 942 private static class AndroidCamera2DeviceInfo implements CameraDeviceInfo { 943 private final CameraManager mCameraManager; 944 private final String[] mCameraIds; 945 private final int mNumberOfCameras; 946 private final int mFirstBackCameraId; 947 private final int mFirstFrontCameraId; 948 949 public AndroidCamera2DeviceInfo(CameraManager cameraManager, 950 String[] cameraIds, int numberOfCameras) { 951 mCameraManager = cameraManager; 952 mCameraIds = cameraIds; 953 mNumberOfCameras = numberOfCameras; 954 955 int firstBackId = NO_DEVICE; 956 int firstFrontId = NO_DEVICE; 957 for (int id = 0; id < cameraIds.length; ++id) { 958 try { 959 int lensDirection = cameraManager.getCameraCharacteristics(cameraIds[id]) 960 .get(CameraCharacteristics.LENS_FACING); 961 if (firstBackId == NO_DEVICE && 962 lensDirection == CameraCharacteristics.LENS_FACING_BACK) { 963 firstBackId = id; 964 } 965 if (firstFrontId == NO_DEVICE && 966 lensDirection == CameraCharacteristics.LENS_FACING_FRONT) { 967 firstFrontId = id; 968 } 969 } catch (CameraAccessException ex) { 970 Log.w(TAG, "Couldn't get characteristics of camera '" + id + "'", ex); 971 } 972 } 973 mFirstBackCameraId = firstBackId; 974 mFirstFrontCameraId = firstFrontId; 975 } 976 977 @Override 978 public Characteristics getCharacteristics(int cameraId) { 979 String actualId = mCameraIds[cameraId]; 980 try { 981 CameraCharacteristics info = mCameraManager.getCameraCharacteristics(actualId); 982 return new AndroidCharacteristics2(info); 983 } catch (CameraAccessException ex) { 984 return null; 985 } 986 } 987 988 @Override 989 public int getNumberOfCameras() { 990 return mNumberOfCameras; 991 } 992 993 @Override 994 public int getFirstBackCameraId() { 995 return mFirstBackCameraId; 996 } 997 998 @Override 999 public int getFirstFrontCameraId() { 1000 return mFirstFrontCameraId; 1001 } 1002 1003 private static class AndroidCharacteristics2 implements Characteristics { 1004 private CameraCharacteristics mCameraInfo; 1005 1006 AndroidCharacteristics2(CameraCharacteristics cameraInfo) { 1007 mCameraInfo = cameraInfo; 1008 } 1009 1010 @Override 1011 public boolean isFacingBack() { 1012 return mCameraInfo.get(CameraCharacteristics.LENS_FACING) 1013 .equals(CameraCharacteristics.LENS_FACING_BACK); 1014 } 1015 1016 @Override 1017 public boolean isFacingFront() { 1018 return mCameraInfo.get(CameraCharacteristics.LENS_FACING) 1019 .equals(CameraCharacteristics.LENS_FACING_FRONT); 1020 } 1021 1022 @Override 1023 public int getSensorOrientation() { 1024 return mCameraInfo.get(CameraCharacteristics.SENSOR_ORIENTATION); 1025 } 1026 1027 @Override 1028 public boolean canDisableShutterSound() { 1029 // The new API doesn't support this operation, so don't encourage people to try it. 1030 // TODO: What kind of assumptions have callers made about this result's meaning? 1031 return false; 1032 } 1033 } 1034 } 1035 1036 private static final CameraExceptionCallback sCameraExceptionCallback = 1037 new CameraExceptionCallback() { 1038 @Override 1039 public synchronized void onCameraException(RuntimeException e) { 1040 throw e; 1041 } 1042 }; 1043} 1044