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 com.android.ex.camera2.portability; 18 19 import android.annotation.TargetApi; 20 import android.content.Context; 21 import android.graphics.ImageFormat; 22 import android.graphics.Matrix; 23 import android.graphics.Rect; 24 import android.graphics.RectF; 25 import android.graphics.SurfaceTexture; 26 import android.hardware.camera2.CameraAccessException; 27 import android.hardware.camera2.CameraCaptureSession; 28 import android.hardware.camera2.CameraCharacteristics; 29 import android.hardware.camera2.CameraDevice; 30 import android.hardware.camera2.CameraManager; 31 import android.hardware.camera2.CaptureFailure; 32 import android.hardware.camera2.CaptureRequest; 33 import android.hardware.camera2.CaptureResult; 34 import android.hardware.camera2.TotalCaptureResult; 35 import android.hardware.camera2.params.MeteringRectangle; 36 import android.media.Image; 37 import android.media.ImageReader; 38 import android.media.MediaActionSound; 39 import android.os.Build; 40 import android.os.Handler; 41 import android.os.HandlerThread; 42 import android.os.Looper; 43 import android.os.Message; 44 import android.view.Surface; 45 46 import com.android.ex.camera2.portability.debug.Log; 47 import com.android.ex.camera2.utils.Camera2RequestSettingsSet; 48 49 import java.nio.ByteBuffer; 50 import java.util.ArrayList; 51 import java.util.Arrays; 52 import java.util.HashSet; 53 import java.util.List; 54 import java.util.Set; 55 56 /** 57 * A class to implement {@link CameraAgent} of the Android camera2 framework. 58 */ 59 class AndroidCamera2AgentImpl extends CameraAgent { 60 private static final Log.Tag TAG = new Log.Tag("AndCam2AgntImp"); 61 62 private final Camera2Handler mCameraHandler; 63 private final HandlerThread mCameraHandlerThread; 64 private final CameraStateHolder mCameraState; 65 private final DispatchThread mDispatchThread; 66 private final CameraManager mCameraManager; 67 private final MediaActionSound mNoisemaker; 68 private CameraExceptionHandler mExceptionHandler; 69 70 /** 71 * Number of camera devices. The length of {@code mCameraDevices} does not reveal this 72 * information because that list may contain since-invalidated indices. 73 */ 74 private int mNumCameraDevices; 75 76 /** 77 * Transformation between integral camera indices and the {@link java.lang.String} indices used 78 * by the underlying API. Note that devices may disappear because they've been disconnected or 79 * have otherwise gone offline. Because we need to keep the meanings of whatever indices we 80 * expose stable, we cannot simply remove them in such a case; instead, we insert {@code null}s 81 * to invalidate any such indices. Whenever new devices appear, they are appended to the end of 82 * the list, and thereby assigned the lowest index that has never yet been used. 83 */ 84 private final List<String> mCameraDevices; 85 AndroidCamera2AgentImpl(Context context)86 AndroidCamera2AgentImpl(Context context) { 87 mCameraHandlerThread = new HandlerThread("Camera2 Handler Thread"); 88 mCameraHandlerThread.start(); 89 mCameraHandler = new Camera2Handler(mCameraHandlerThread.getLooper()); 90 mExceptionHandler = new CameraExceptionHandler(mCameraHandler); 91 mCameraState = new AndroidCamera2StateHolder(); 92 mDispatchThread = new DispatchThread(mCameraHandler, mCameraHandlerThread); 93 mDispatchThread.start(); 94 mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); 95 mNoisemaker = new MediaActionSound(); 96 mNoisemaker.load(MediaActionSound.SHUTTER_CLICK); 97 98 mNumCameraDevices = 0; 99 mCameraDevices = new ArrayList<String>(); 100 updateCameraDevices(); 101 } 102 103 /** 104 * Updates the camera device index assignments stored in {@link mCameraDevices}, without 105 * reappropriating any currently-assigned index. 106 * @return Whether the operation was successful 107 */ updateCameraDevices()108 private boolean updateCameraDevices() { 109 try { 110 String[] currentCameraDevices = mCameraManager.getCameraIdList(); 111 Set<String> currentSet = new HashSet<String>(Arrays.asList(currentCameraDevices)); 112 113 // Invalidate the indices assigned to any camera devices that are no longer present 114 for (int index = 0; index < mCameraDevices.size(); ++index) { 115 if (!currentSet.contains(mCameraDevices.get(index))) { 116 mCameraDevices.set(index, null); 117 --mNumCameraDevices; 118 } 119 } 120 121 // Assign fresh indices to any new camera devices 122 currentSet.removeAll(mCameraDevices); // The devices we didn't know about 123 for (String device : currentCameraDevices) { 124 if (currentSet.contains(device)) { 125 mCameraDevices.add(device); 126 ++mNumCameraDevices; 127 } 128 } 129 130 return true; 131 } catch (CameraAccessException ex) { 132 Log.e(TAG, "Could not get device listing from camera subsystem", ex); 133 return false; 134 } 135 } 136 137 // TODO: Implement 138 @Override recycle()139 public void recycle() {} 140 141 // TODO: Some indices may now be invalid; ensure everyone can handle that and update the docs 142 @Override getCameraDeviceInfo()143 public CameraDeviceInfo getCameraDeviceInfo() { 144 updateCameraDevices(); 145 return new AndroidCamera2DeviceInfo(mCameraManager, mCameraDevices.toArray(new String[0]), 146 mNumCameraDevices); 147 } 148 149 @Override getCameraHandler()150 protected Handler getCameraHandler() { 151 return mCameraHandler; 152 } 153 154 @Override getDispatchThread()155 protected DispatchThread getDispatchThread() { 156 return mDispatchThread; 157 } 158 159 @Override getCameraState()160 protected CameraStateHolder getCameraState() { 161 return mCameraState; 162 } 163 164 @Override getCameraExceptionHandler()165 protected CameraExceptionHandler getCameraExceptionHandler() { 166 return mExceptionHandler; 167 } 168 169 @Override setCameraExceptionHandler(CameraExceptionHandler exceptionHandler)170 public void setCameraExceptionHandler(CameraExceptionHandler exceptionHandler) { 171 mExceptionHandler = exceptionHandler; 172 } 173 174 private static abstract class CaptureAvailableListener 175 extends CameraCaptureSession.CaptureCallback 176 implements ImageReader.OnImageAvailableListener {}; 177 178 private class Camera2Handler extends HistoryHandler { 179 // Caller-provided when leaving CAMERA_UNOPENED state: 180 private CameraOpenCallback mOpenCallback; 181 private int mCameraIndex; 182 private String mCameraId; 183 private int mCancelAfPending = 0; 184 185 // Available in CAMERA_UNCONFIGURED state and above: 186 private CameraDevice mCamera; 187 private AndroidCamera2ProxyImpl mCameraProxy; 188 private Camera2RequestSettingsSet mPersistentSettings; 189 private Rect mActiveArray; 190 private boolean mLegacyDevice; 191 192 // Available in CAMERA_CONFIGURED state and above: 193 private Size mPreviewSize; 194 private Size mPhotoSize; 195 196 // Available in PREVIEW_READY state and above: 197 private SurfaceTexture mPreviewTexture; 198 private Surface mPreviewSurface; 199 private CameraCaptureSession mSession; 200 private ImageReader mCaptureReader; 201 202 // Available from the beginning of PREVIEW_ACTIVE until the first preview frame arrives: 203 private CameraStartPreviewCallback mOneshotPreviewingCallback; 204 205 // Available in FOCUS_LOCKED between AF trigger receipt and whenever the lens stops moving: 206 private CameraAFCallback mOneshotAfCallback; 207 208 // Available when taking picture between AE trigger receipt and autoexposure convergence 209 private CaptureAvailableListener mOneshotCaptureCallback; 210 211 // Available whenever setAutoFocusMoveCallback() was last invoked with a non-null argument: 212 private CameraAFMoveCallback mPassiveAfCallback; 213 214 // Gets reset on every state change 215 private int mCurrentAeState = CaptureResult.CONTROL_AE_STATE_INACTIVE; 216 Camera2Handler(Looper looper)217 Camera2Handler(Looper looper) { 218 super(looper); 219 } 220 221 @Override handleMessage(final Message msg)222 public void handleMessage(final Message msg) { 223 super.handleMessage(msg); 224 Log.v(TAG, "handleMessage - action = '" + CameraActions.stringify(msg.what) + "'"); 225 int cameraAction = msg.what; 226 try { 227 switch (cameraAction) { 228 case CameraActions.OPEN_CAMERA: 229 case CameraActions.RECONNECT: { 230 CameraOpenCallback openCallback = (CameraOpenCallback) msg.obj; 231 int cameraIndex = msg.arg1; 232 233 if (mCameraState.getState() > AndroidCamera2StateHolder.CAMERA_UNOPENED) { 234 openCallback.onDeviceOpenedAlready(cameraIndex, 235 generateHistoryString(cameraIndex)); 236 break; 237 } 238 239 mOpenCallback = openCallback; 240 mCameraIndex = cameraIndex; 241 mCameraId = mCameraDevices.get(mCameraIndex); 242 Log.i(TAG, String.format("Opening camera index %d (id %s) with camera2 API", 243 cameraIndex, mCameraId)); 244 245 if (mCameraId == null) { 246 mOpenCallback.onCameraDisabled(msg.arg1); 247 break; 248 } 249 mCameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, this); 250 251 break; 252 } 253 254 case CameraActions.RELEASE: { 255 if (mCameraState.getState() == AndroidCamera2StateHolder.CAMERA_UNOPENED) { 256 Log.w(TAG, "Ignoring release at inappropriate time"); 257 break; 258 } 259 260 if (mSession != null) { 261 closePreviewSession(); 262 mSession = null; 263 } 264 if (mCamera != null) { 265 mCamera.close(); 266 mCamera = null; 267 } 268 mCameraProxy = null; 269 mPersistentSettings = null; 270 mActiveArray = null; 271 if (mPreviewSurface != null) { 272 mPreviewSurface.release(); 273 mPreviewSurface = null; 274 } 275 mPreviewTexture = null; 276 if (mCaptureReader != null) { 277 mCaptureReader.close(); 278 mCaptureReader = null; 279 } 280 mPreviewSize = null; 281 mPhotoSize = null; 282 mCameraIndex = 0; 283 mCameraId = null; 284 changeState(AndroidCamera2StateHolder.CAMERA_UNOPENED); 285 break; 286 } 287 288 /*case CameraActions.UNLOCK: { 289 break; 290 } 291 292 case CameraActions.LOCK: { 293 break; 294 }*/ 295 296 case CameraActions.SET_PREVIEW_TEXTURE_ASYNC: { 297 setPreviewTexture((SurfaceTexture) msg.obj); 298 break; 299 } 300 301 case CameraActions.START_PREVIEW_ASYNC: { 302 if (mCameraState.getState() != 303 AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) { 304 // TODO: Provide better feedback here? 305 Log.w(TAG, "Refusing to start preview at inappropriate time"); 306 break; 307 } 308 309 mOneshotPreviewingCallback = (CameraStartPreviewCallback) msg.obj; 310 changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE); 311 try { 312 mSession.setRepeatingRequest( 313 mPersistentSettings.createRequest(mCamera, 314 CameraDevice.TEMPLATE_PREVIEW, mPreviewSurface), 315 /*listener*/mCameraResultStateCallback, /*handler*/this); 316 } catch(CameraAccessException ex) { 317 Log.w(TAG, "Unable to start preview", ex); 318 changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY); 319 } 320 break; 321 } 322 323 // FIXME: We need to tear down the CameraCaptureSession here 324 // (and unlock the CameraSettings object from our 325 // CameraProxy) so that the preview/photo sizes can be 326 // changed again while no preview is running. 327 case CameraActions.STOP_PREVIEW: { 328 if (mCameraState.getState() < 329 AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) { 330 Log.w(TAG, "Refusing to stop preview at inappropriate time"); 331 break; 332 } 333 334 mSession.stopRepeating(); 335 changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY); 336 break; 337 } 338 339 /*case CameraActions.SET_PREVIEW_CALLBACK_WITH_BUFFER: { 340 break; 341 } 342 343 case CameraActions.ADD_CALLBACK_BUFFER: { 344 break; 345 } 346 347 case CameraActions.SET_PREVIEW_DISPLAY_ASYNC: { 348 break; 349 } 350 351 case CameraActions.SET_PREVIEW_CALLBACK: { 352 break; 353 } 354 355 case CameraActions.SET_ONE_SHOT_PREVIEW_CALLBACK: { 356 break; 357 } 358 359 case CameraActions.SET_PARAMETERS: { 360 break; 361 } 362 363 case CameraActions.GET_PARAMETERS: { 364 break; 365 } 366 367 case CameraActions.REFRESH_PARAMETERS: { 368 break; 369 }*/ 370 371 case CameraActions.APPLY_SETTINGS: { 372 AndroidCamera2Settings settings = (AndroidCamera2Settings) msg.obj; 373 applyToRequest(settings); 374 break; 375 } 376 377 case CameraActions.AUTO_FOCUS: { 378 if (mCancelAfPending > 0) { 379 Log.v(TAG, "handleMessage - Ignored AUTO_FOCUS because there was " 380 + mCancelAfPending + " pending CANCEL_AUTO_FOCUS messages"); 381 break; // ignore AF because a CANCEL_AF is queued after this 382 } 383 // We only support locking the focus while a preview is being displayed. 384 // However, it can be requested multiple times in succession; the effect of 385 // the subsequent invocations is determined by the focus mode defined in the 386 // provided CameraSettings object. In passive (CONTINUOUS_*) mode, the 387 // duplicate requests are no-ops and leave the lens locked at its current 388 // position, but in active (AUTO) mode, they perform another scan and lock 389 // once that is finished. In any manual focus mode, this call is a no-op, 390 // and most notably, this is the only case where the callback isn't invoked. 391 if (mCameraState.getState() < 392 AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) { 393 Log.w(TAG, "Ignoring attempt to autofocus without preview"); 394 break; 395 } 396 397 // The earliest we can reliably tell whether the autofocus has locked in 398 // response to our latest request is when our one-time capture progresses. 399 // However, it will probably take longer than that, so once that happens, 400 // just start checking the repeating preview requests as they complete. 401 final CameraAFCallback callback = (CameraAFCallback) msg.obj; 402 CameraCaptureSession.CaptureCallback deferredCallbackSetter = 403 new CameraCaptureSession.CaptureCallback() { 404 private boolean mAlreadyDispatched = false; 405 406 @Override 407 public void onCaptureProgressed(CameraCaptureSession session, 408 CaptureRequest request, 409 CaptureResult result) { 410 checkAfState(result); 411 } 412 413 @Override 414 public void onCaptureCompleted(CameraCaptureSession session, 415 CaptureRequest request, 416 TotalCaptureResult result) { 417 checkAfState(result); 418 } 419 420 private void checkAfState(CaptureResult result) { 421 if (result.get(CaptureResult.CONTROL_AF_STATE) != null && 422 !mAlreadyDispatched) { 423 // Now our mCameraResultStateCallback will invoke the callback 424 // the first time it finds the focus motor to be locked. 425 mAlreadyDispatched = true; 426 mOneshotAfCallback = callback; 427 // This is an optimization: check the AF state of this frame 428 // instead of simply waiting for the next. 429 mCameraResultStateCallback.monitorControlStates(result); 430 } 431 } 432 433 @Override 434 public void onCaptureFailed(CameraCaptureSession session, 435 CaptureRequest request, 436 CaptureFailure failure) { 437 Log.e(TAG, "Focusing failed with reason " + failure.getReason()); 438 callback.onAutoFocus(false, mCameraProxy); 439 }}; 440 441 // Send a one-time capture to trigger the camera driver to lock focus. 442 changeState(AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED); 443 Camera2RequestSettingsSet trigger = 444 new Camera2RequestSettingsSet(mPersistentSettings); 445 trigger.set(CaptureRequest.CONTROL_AF_TRIGGER, 446 CaptureRequest.CONTROL_AF_TRIGGER_START); 447 try { 448 mSession.capture( 449 trigger.createRequest(mCamera, CameraDevice.TEMPLATE_PREVIEW, 450 mPreviewSurface), 451 /*listener*/deferredCallbackSetter, /*handler*/ this); 452 } catch(CameraAccessException ex) { 453 Log.e(TAG, "Unable to lock autofocus", ex); 454 changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE); 455 } 456 break; 457 } 458 459 case CameraActions.CANCEL_AUTO_FOCUS: { 460 // Ignore all AFs that were already queued until we see 461 // a CANCEL_AUTO_FOCUS_FINISH 462 mCancelAfPending++; 463 // Why would you want to unlock the lens if it isn't already locked? 464 if (mCameraState.getState() < 465 AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) { 466 Log.w(TAG, "Ignoring attempt to release focus lock without preview"); 467 break; 468 } 469 470 // Send a one-time capture to trigger the camera driver to resume scanning. 471 changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE); 472 Camera2RequestSettingsSet cancel = 473 new Camera2RequestSettingsSet(mPersistentSettings); 474 cancel.set(CaptureRequest.CONTROL_AF_TRIGGER, 475 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); 476 try { 477 mSession.capture( 478 cancel.createRequest(mCamera, CameraDevice.TEMPLATE_PREVIEW, 479 mPreviewSurface), 480 /*listener*/null, /*handler*/this); 481 } catch(CameraAccessException ex) { 482 Log.e(TAG, "Unable to cancel autofocus", ex); 483 changeState(AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED); 484 } 485 break; 486 } 487 488 case CameraActions.CANCEL_AUTO_FOCUS_FINISH: { 489 // Stop ignoring AUTO_FOCUS messages unless there are additional 490 // CANCEL_AUTO_FOCUSes that were added 491 mCancelAfPending--; 492 break; 493 } 494 495 case CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK: { 496 mPassiveAfCallback = (CameraAFMoveCallback) msg.obj; 497 break; 498 } 499 500 /*case CameraActions.SET_ZOOM_CHANGE_LISTENER: { 501 break; 502 } 503 504 case CameraActions.SET_FACE_DETECTION_LISTENER: { 505 break; 506 } 507 508 case CameraActions.START_FACE_DETECTION: { 509 break; 510 } 511 512 case CameraActions.STOP_FACE_DETECTION: { 513 break; 514 } 515 516 case CameraActions.SET_ERROR_CALLBACK: { 517 break; 518 } 519 520 case CameraActions.ENABLE_SHUTTER_SOUND: { 521 break; 522 }*/ 523 524 case CameraActions.SET_DISPLAY_ORIENTATION: { 525 // Only set the JPEG capture orientation if requested to do so; otherwise, 526 // capture in the sensor's physical orientation. (e.g., JPEG rotation is 527 // necessary in auto-rotate mode. 528 mPersistentSettings.set(CaptureRequest.JPEG_ORIENTATION, msg.arg2 > 0 ? 529 mCameraProxy.getCharacteristics().getJpegOrientation(msg.arg1) : 0); 530 break; 531 } 532 533 case CameraActions.SET_JPEG_ORIENTATION: { 534 mPersistentSettings.set(CaptureRequest.JPEG_ORIENTATION, msg.arg1); 535 break; 536 } 537 538 case CameraActions.CAPTURE_PHOTO: { 539 if (mCameraState.getState() < 540 AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) { 541 Log.e(TAG, "Photos may only be taken when a preview is active"); 542 break; 543 } 544 if (mCameraState.getState() != 545 AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED) { 546 Log.w(TAG, "Taking a (likely blurry) photo without the lens locked"); 547 } 548 549 final CaptureAvailableListener listener = 550 (CaptureAvailableListener) msg.obj; 551 if (mLegacyDevice || 552 (mCurrentAeState == CaptureResult.CONTROL_AE_STATE_CONVERGED && 553 !mPersistentSettings.matches(CaptureRequest.CONTROL_AE_MODE, 554 CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH) && 555 !mPersistentSettings.matches(CaptureRequest.FLASH_MODE, 556 CaptureRequest.FLASH_MODE_SINGLE))) 557 { 558 // Legacy devices don't support the precapture state keys and instead 559 // perform autoexposure convergence automatically upon capture. 560 561 // On other devices, as long as it has already converged, it determined 562 // that flash was not required, and we're not going to invalidate the 563 // current exposure levels by forcing the force on, we can save 564 // significant capture time by not forcing a recalculation. 565 Log.i(TAG, "Skipping pre-capture autoexposure convergence"); 566 mCaptureReader.setOnImageAvailableListener(listener, /*handler*/this); 567 try { 568 mSession.capture( 569 mPersistentSettings.createRequest(mCamera, 570 CameraDevice.TEMPLATE_STILL_CAPTURE, 571 mCaptureReader.getSurface()), 572 listener, /*handler*/this); 573 } catch (CameraAccessException ex) { 574 Log.e(TAG, "Unable to initiate immediate capture", ex); 575 } 576 } else { 577 // We need to let AE converge before capturing. Once our one-time 578 // trigger capture has made it into the pipeline, we'll start checking 579 // for the completion of that convergence, capturing when that happens. 580 Log.i(TAG, "Forcing pre-capture autoexposure convergence"); 581 CameraCaptureSession.CaptureCallback deferredCallbackSetter = 582 new CameraCaptureSession.CaptureCallback() { 583 private boolean mAlreadyDispatched = false; 584 585 @Override 586 public void onCaptureProgressed(CameraCaptureSession session, 587 CaptureRequest request, 588 CaptureResult result) { 589 checkAeState(result); 590 } 591 592 @Override 593 public void onCaptureCompleted(CameraCaptureSession session, 594 CaptureRequest request, 595 TotalCaptureResult result) { 596 checkAeState(result); 597 } 598 599 private void checkAeState(CaptureResult result) { 600 if (result.get(CaptureResult.CONTROL_AE_STATE) != null && 601 !mAlreadyDispatched) { 602 // Now our mCameraResultStateCallback will invoke the 603 // callback once the autoexposure routine has converged. 604 mAlreadyDispatched = true; 605 mOneshotCaptureCallback = listener; 606 // This is an optimization: check the AE state of this frame 607 // instead of simply waiting for the next. 608 mCameraResultStateCallback.monitorControlStates(result); 609 } 610 } 611 612 @Override 613 public void onCaptureFailed(CameraCaptureSession session, 614 CaptureRequest request, 615 CaptureFailure failure) { 616 Log.e(TAG, "Autoexposure and capture failed with reason " + 617 failure.getReason()); 618 // TODO: Make an error callback? 619 }}; 620 621 // Set a one-time capture to trigger the camera driver's autoexposure: 622 Camera2RequestSettingsSet expose = 623 new Camera2RequestSettingsSet(mPersistentSettings); 624 expose.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 625 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 626 try { 627 mSession.capture( 628 expose.createRequest(mCamera, CameraDevice.TEMPLATE_PREVIEW, 629 mPreviewSurface), 630 /*listener*/deferredCallbackSetter, /*handler*/this); 631 } catch (CameraAccessException ex) { 632 Log.e(TAG, "Unable to run autoexposure and perform capture", ex); 633 } 634 } 635 break; 636 } 637 638 default: { 639 // TODO: Rephrase once everything has been implemented 640 throw new RuntimeException("Unimplemented CameraProxy message=" + msg.what); 641 } 642 } 643 } catch (final Exception ex) { 644 if (cameraAction != CameraActions.RELEASE && mCamera != null) { 645 // TODO: Handle this better 646 mCamera.close(); 647 mCamera = null; 648 } else if (mCamera == null) { 649 if (cameraAction == CameraActions.OPEN_CAMERA) { 650 if (mOpenCallback != null) { 651 mOpenCallback.onDeviceOpenFailure(mCameraIndex, 652 generateHistoryString(mCameraIndex)); 653 } 654 } else { 655 Log.w(TAG, "Cannot handle message " + msg.what + ", mCamera is null"); 656 } 657 return; 658 } 659 660 if (ex instanceof RuntimeException) { 661 String commandHistory = generateHistoryString(Integer.parseInt(mCameraId)); 662 mExceptionHandler.onCameraException((RuntimeException) ex, commandHistory, 663 cameraAction, mCameraState.getState()); 664 } 665 } finally { 666 WaitDoneBundle.unblockSyncWaiters(msg); 667 } 668 } 669 buildSettings(AndroidCamera2Capabilities caps)670 public CameraSettings buildSettings(AndroidCamera2Capabilities caps) { 671 try { 672 return new AndroidCamera2Settings(mCamera, CameraDevice.TEMPLATE_PREVIEW, 673 mActiveArray, mPreviewSize, mPhotoSize); 674 } catch (CameraAccessException ex) { 675 Log.e(TAG, "Unable to query camera device to build settings representation"); 676 return null; 677 } 678 } 679 680 /** 681 * Simply propagates settings from provided {@link CameraSettings} 682 * object to our {@link CaptureRequest.Builder} for use in captures. 683 * <p>Most conversions to match the API 2 formats are performed by 684 * {@link AndroidCamera2Capabilities.IntegralStringifier}; otherwise 685 * any final adjustments are done here before updating the builder.</p> 686 * 687 * @param settings The new/updated settings 688 */ applyToRequest(AndroidCamera2Settings settings)689 private void applyToRequest(AndroidCamera2Settings settings) { 690 // TODO: If invoked when in PREVIEW_READY state, a new preview size will not take effect 691 692 mPersistentSettings.union(settings.getRequestSettings()); 693 mPreviewSize = settings.getCurrentPreviewSize(); 694 mPhotoSize = settings.getCurrentPhotoSize(); 695 696 if (mCameraState.getState() >= AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) { 697 // If we're already previewing, reflect most settings immediately 698 try { 699 mSession.setRepeatingRequest( 700 mPersistentSettings.createRequest(mCamera, 701 CameraDevice.TEMPLATE_PREVIEW, mPreviewSurface), 702 /*listener*/mCameraResultStateCallback, /*handler*/this); 703 } catch (CameraAccessException ex) { 704 Log.e(TAG, "Failed to apply updated request settings", ex); 705 } 706 } else if (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) { 707 // If we're already ready to preview, this doesn't regress our state 708 changeState(AndroidCamera2StateHolder.CAMERA_CONFIGURED); 709 } 710 } 711 setPreviewTexture(SurfaceTexture surfaceTexture)712 private void setPreviewTexture(SurfaceTexture surfaceTexture) { 713 // TODO: Must be called after providing a .*Settings populated with sizes 714 // TODO: We don't technically offer a selection of sizes tailored to SurfaceTextures! 715 716 // TODO: Handle this error condition with a callback or exception 717 if (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_CONFIGURED) { 718 Log.w(TAG, "Ignoring texture setting at inappropriate time"); 719 return; 720 } 721 722 // Avoid initializing another capture session unless we absolutely have to 723 if (surfaceTexture == mPreviewTexture) { 724 Log.i(TAG, "Optimizing out redundant preview texture setting"); 725 return; 726 } 727 728 if (mSession != null) { 729 closePreviewSession(); 730 } 731 732 mPreviewTexture = surfaceTexture; 733 surfaceTexture.setDefaultBufferSize(mPreviewSize.width(), mPreviewSize.height()); 734 735 if (mPreviewSurface != null) { 736 mPreviewSurface.release(); 737 } 738 mPreviewSurface = new Surface(surfaceTexture); 739 740 if (mCaptureReader != null) { 741 mCaptureReader.close(); 742 } 743 mCaptureReader = ImageReader.newInstance( 744 mPhotoSize.width(), mPhotoSize.height(), ImageFormat.JPEG, 1); 745 746 try { 747 mCamera.createCaptureSession( 748 Arrays.asList(mPreviewSurface, mCaptureReader.getSurface()), 749 mCameraPreviewStateCallback, this); 750 } catch (CameraAccessException ex) { 751 Log.e(TAG, "Failed to create camera capture session", ex); 752 } 753 } 754 closePreviewSession()755 private void closePreviewSession() { 756 try { 757 mSession.abortCaptures(); 758 mSession = null; 759 } catch (CameraAccessException ex) { 760 Log.e(TAG, "Failed to close existing camera capture session", ex); 761 } 762 changeState(AndroidCamera2StateHolder.CAMERA_CONFIGURED); 763 } 764 changeState(int newState)765 private void changeState(int newState) { 766 if (mCameraState.getState() != newState) { 767 mCameraState.setState(newState); 768 if (newState < AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) { 769 mCurrentAeState = CaptureResult.CONTROL_AE_STATE_INACTIVE; 770 mCameraResultStateCallback.resetState(); 771 } 772 } 773 } 774 775 // This callback monitors our connection to and disconnection from camera devices. 776 private CameraDevice.StateCallback mCameraDeviceStateCallback = 777 new CameraDevice.StateCallback() { 778 @Override 779 public void onOpened(CameraDevice camera) { 780 mCamera = camera; 781 if (mOpenCallback != null) { 782 try { 783 CameraCharacteristics props = 784 mCameraManager.getCameraCharacteristics(mCameraId); 785 CameraDeviceInfo.Characteristics characteristics = 786 getCameraDeviceInfo().getCharacteristics(mCameraIndex); 787 mCameraProxy = new AndroidCamera2ProxyImpl(AndroidCamera2AgentImpl.this, 788 mCameraIndex, mCamera, characteristics, props); 789 mPersistentSettings = new Camera2RequestSettingsSet(); 790 mActiveArray = 791 props.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 792 mLegacyDevice = 793 props.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) == 794 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; 795 changeState(AndroidCamera2StateHolder.CAMERA_UNCONFIGURED); 796 mOpenCallback.onCameraOpened(mCameraProxy); 797 } catch (CameraAccessException ex) { 798 mOpenCallback.onDeviceOpenFailure(mCameraIndex, 799 generateHistoryString(mCameraIndex)); 800 } 801 } 802 } 803 804 @Override 805 public void onDisconnected(CameraDevice camera) { 806 Log.w(TAG, "Camera device '" + mCameraIndex + "' was disconnected"); 807 } 808 809 @Override 810 public void onError(CameraDevice camera, int error) { 811 Log.e(TAG, "Camera device '" + mCameraIndex + "' encountered error code '" + 812 error + '\''); 813 if (mOpenCallback != null) { 814 mOpenCallback.onDeviceOpenFailure(mCameraIndex, 815 generateHistoryString(mCameraIndex)); 816 } 817 }}; 818 819 // This callback monitors our camera session (i.e. our transition into and out of preview). 820 private CameraCaptureSession.StateCallback mCameraPreviewStateCallback = 821 new CameraCaptureSession.StateCallback() { 822 @Override 823 public void onConfigured(CameraCaptureSession session) { 824 mSession = session; 825 changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY); 826 } 827 828 @Override 829 public void onConfigureFailed(CameraCaptureSession session) { 830 // TODO: Invoke a callback 831 Log.e(TAG, "Failed to configure the camera for capture"); 832 } 833 834 @Override 835 public void onActive(CameraCaptureSession session) { 836 if (mOneshotPreviewingCallback != null) { 837 // The session is up and processing preview requests. Inform the caller. 838 mOneshotPreviewingCallback.onPreviewStarted(); 839 mOneshotPreviewingCallback = null; 840 } 841 }}; 842 843 private abstract class CameraResultStateCallback 844 extends CameraCaptureSession.CaptureCallback { monitorControlStates(CaptureResult result)845 public abstract void monitorControlStates(CaptureResult result); 846 resetState()847 public abstract void resetState(); 848 } 849 850 // This callback monitors requested captures and notifies any relevant callbacks. 851 private CameraResultStateCallback mCameraResultStateCallback = 852 new CameraResultStateCallback() { 853 private int mLastAfState = -1; 854 private long mLastAfFrameNumber = -1; 855 private long mLastAeFrameNumber = -1; 856 857 @Override 858 public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, 859 CaptureResult result) { 860 monitorControlStates(result); 861 } 862 863 @Override 864 public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, 865 TotalCaptureResult result) { 866 monitorControlStates(result); 867 } 868 869 @Override 870 public void monitorControlStates(CaptureResult result) { 871 Integer afStateMaybe = result.get(CaptureResult.CONTROL_AF_STATE); 872 if (afStateMaybe != null) { 873 int afState = afStateMaybe; 874 // Since we handle both partial and total results for multiple frames here, we 875 // might get the final callbacks for an earlier frame after receiving one or 876 // more that correspond to the next one. To prevent our data from oscillating, 877 // we never consider AF states that are older than the last one we've seen. 878 if (result.getFrameNumber() > mLastAfFrameNumber) { 879 boolean afStateChanged = afState != mLastAfState; 880 mLastAfState = afState; 881 mLastAfFrameNumber = result.getFrameNumber(); 882 883 switch (afState) { 884 case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN: 885 case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED: 886 case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED: { 887 if (afStateChanged && mPassiveAfCallback != null) { 888 // A CameraAFMoveCallback is attached. If we just started to 889 // scan, the motor is moving; otherwise, it has settled. 890 mPassiveAfCallback.onAutoFocusMoving( 891 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN, 892 mCameraProxy); 893 } 894 break; 895 } 896 897 case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED: 898 case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED: { 899 // This check must be made regardless of whether the focus state has 900 // changed recently to avoid infinite waiting during autoFocus() 901 // when the algorithm has already either converged or failed to. 902 if (mOneshotAfCallback != null) { 903 // A call to autoFocus() was just made to request a focus lock. 904 // Notify the caller that the lens is now indefinitely fixed, 905 // and report whether the image we're stuck with is in focus. 906 mOneshotAfCallback.onAutoFocus( 907 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED, 908 mCameraProxy); 909 mOneshotAfCallback = null; 910 } 911 break; 912 } 913 } 914 } 915 } 916 917 Integer aeStateMaybe = result.get(CaptureResult.CONTROL_AE_STATE); 918 if (aeStateMaybe != null) { 919 int aeState = aeStateMaybe; 920 // Since we handle both partial and total results for multiple frames here, we 921 // might get the final callbacks for an earlier frame after receiving one or 922 // more that correspond to the next one. To prevent our data from oscillating, 923 // we never consider AE states that are older than the last one we've seen. 924 if (result.getFrameNumber() > mLastAeFrameNumber) { 925 mCurrentAeState = aeStateMaybe; 926 mLastAeFrameNumber = result.getFrameNumber(); 927 928 switch (aeState) { 929 case CaptureResult.CONTROL_AE_STATE_CONVERGED: 930 case CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED: 931 case CaptureResult.CONTROL_AE_STATE_LOCKED: { 932 // This check must be made regardless of whether the exposure state 933 // has changed recently to avoid infinite waiting during 934 // takePicture() when the algorithm has already converged. 935 if (mOneshotCaptureCallback != null) { 936 // A call to takePicture() was just made, and autoexposure 937 // converged so it's time to initiate the capture! 938 mCaptureReader.setOnImageAvailableListener( 939 /*listener*/mOneshotCaptureCallback, 940 /*handler*/Camera2Handler.this); 941 try { 942 mSession.capture( 943 mPersistentSettings.createRequest(mCamera, 944 CameraDevice.TEMPLATE_STILL_CAPTURE, 945 mCaptureReader.getSurface()), 946 /*callback*/mOneshotCaptureCallback, 947 /*handler*/Camera2Handler.this); 948 } catch (CameraAccessException ex) { 949 Log.e(TAG, "Unable to initiate capture", ex); 950 } finally { 951 mOneshotCaptureCallback = null; 952 } 953 } 954 break; 955 } 956 } 957 } 958 } 959 } 960 961 @Override 962 public void resetState() { 963 mLastAfState = -1; 964 mLastAfFrameNumber = -1; 965 mLastAeFrameNumber = -1; 966 } 967 968 @Override 969 public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, 970 CaptureFailure failure) { 971 Log.e(TAG, "Capture attempt failed with reason " + failure.getReason()); 972 }}; 973 } 974 975 private class AndroidCamera2ProxyImpl extends CameraAgent.CameraProxy { 976 private final AndroidCamera2AgentImpl mCameraAgent; 977 private final int mCameraIndex; 978 private final CameraDevice mCamera; 979 private final CameraDeviceInfo.Characteristics mCharacteristics; 980 private final AndroidCamera2Capabilities mCapabilities; 981 private CameraSettings mLastSettings; 982 private boolean mShutterSoundEnabled; 983 AndroidCamera2ProxyImpl( AndroidCamera2AgentImpl agent, int cameraIndex, CameraDevice camera, CameraDeviceInfo.Characteristics characteristics, CameraCharacteristics properties)984 public AndroidCamera2ProxyImpl( 985 AndroidCamera2AgentImpl agent, 986 int cameraIndex, 987 CameraDevice camera, 988 CameraDeviceInfo.Characteristics characteristics, 989 CameraCharacteristics properties) { 990 mCameraAgent = agent; 991 mCameraIndex = cameraIndex; 992 mCamera = camera; 993 mCharacteristics = characteristics; 994 mCapabilities = new AndroidCamera2Capabilities(properties); 995 mLastSettings = null; 996 mShutterSoundEnabled = true; 997 } 998 999 // TODO: Implement 1000 @Override getCamera()1001 public android.hardware.Camera getCamera() { return null; } 1002 1003 @Override getCameraId()1004 public int getCameraId() { 1005 return mCameraIndex; 1006 } 1007 1008 @Override getCharacteristics()1009 public CameraDeviceInfo.Characteristics getCharacteristics() { 1010 return mCharacteristics; 1011 } 1012 1013 @Override getCapabilities()1014 public CameraCapabilities getCapabilities() { 1015 return mCapabilities; 1016 } 1017 getAgent()1018 public CameraAgent getAgent() { 1019 return mCameraAgent; 1020 } 1021 getSpecializedCapabilities()1022 private AndroidCamera2Capabilities getSpecializedCapabilities() { 1023 return mCapabilities; 1024 } 1025 1026 // FIXME: Unlock the sizes in stopPreview(), as per the corresponding 1027 // explanation on the STOP_PREVIEW case in the handler. 1028 @Override setPreviewTexture(SurfaceTexture surfaceTexture)1029 public void setPreviewTexture(SurfaceTexture surfaceTexture) { 1030 // Once the Surface has been selected, we configure the session and 1031 // are no longer able to change the sizes. 1032 getSettings().setSizesLocked(true); 1033 super.setPreviewTexture(surfaceTexture); 1034 } 1035 1036 // FIXME: Unlock the sizes in stopPreview(), as per the corresponding 1037 // explanation on the STOP_PREVIEW case in the handler. 1038 @Override setPreviewTextureSync(SurfaceTexture surfaceTexture)1039 public void setPreviewTextureSync(SurfaceTexture surfaceTexture) { 1040 // Once the Surface has been selected, we configure the session and 1041 // are no longer able to change the sizes. 1042 getSettings().setSizesLocked(true); 1043 super.setPreviewTexture(surfaceTexture); 1044 } 1045 1046 // TODO: Implement 1047 @Override setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb)1048 public void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb) {} 1049 1050 // TODO: Implement 1051 @Override setOneShotPreviewCallback(Handler handler, CameraPreviewDataCallback cb)1052 public void setOneShotPreviewCallback(Handler handler, CameraPreviewDataCallback cb) {} 1053 1054 // TODO: Implement 1055 @Override setPreviewDataCallbackWithBuffer(Handler handler, CameraPreviewDataCallback cb)1056 public void setPreviewDataCallbackWithBuffer(Handler handler, CameraPreviewDataCallback cb) 1057 {} 1058 1059 // TODO: Implement addCallbackBuffer(final byte[] callbackBuffer)1060 public void addCallbackBuffer(final byte[] callbackBuffer) {} 1061 1062 @Override autoFocus(final Handler handler, final CameraAFCallback cb)1063 public void autoFocus(final Handler handler, final CameraAFCallback cb) { 1064 try { 1065 mDispatchThread.runJob(new Runnable() { 1066 @Override 1067 public void run() { 1068 CameraAFCallback cbForward = null; 1069 if (cb != null) { 1070 cbForward = new CameraAFCallback() { 1071 @Override 1072 public void onAutoFocus(final boolean focused, 1073 final CameraProxy camera) { 1074 handler.post(new Runnable() { 1075 @Override 1076 public void run() { 1077 cb.onAutoFocus(focused, camera); 1078 } 1079 }); 1080 } 1081 }; 1082 } 1083 1084 mCameraState.waitForStates(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE | 1085 AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED); 1086 mCameraHandler.obtainMessage(CameraActions.AUTO_FOCUS, cbForward) 1087 .sendToTarget(); 1088 } 1089 }); 1090 } catch (RuntimeException ex) { 1091 mCameraAgent.getCameraExceptionHandler().onDispatchThreadException(ex); 1092 } 1093 } 1094 1095 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 1096 @Override setAutoFocusMoveCallback(final Handler handler, final CameraAFMoveCallback cb)1097 public void setAutoFocusMoveCallback(final Handler handler, final CameraAFMoveCallback cb) { 1098 try { 1099 mDispatchThread.runJob(new Runnable() { 1100 @Override 1101 public void run() { 1102 CameraAFMoveCallback cbForward = null; 1103 if (cb != null) { 1104 cbForward = new CameraAFMoveCallback() { 1105 @Override 1106 public void onAutoFocusMoving(final boolean moving, 1107 final CameraProxy camera) { 1108 handler.post(new Runnable() { 1109 @Override 1110 public void run() { 1111 cb.onAutoFocusMoving(moving, camera); 1112 } 1113 }); 1114 } 1115 }; 1116 } 1117 1118 mCameraHandler.obtainMessage(CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK, 1119 cbForward).sendToTarget(); 1120 } 1121 }); 1122 } catch (RuntimeException ex) { 1123 mCameraAgent.getCameraExceptionHandler().onDispatchThreadException(ex); 1124 } 1125 } 1126 1127 @Override takePicture(final Handler handler, final CameraShutterCallback shutter, CameraPictureCallback raw, CameraPictureCallback postview, final CameraPictureCallback jpeg)1128 public void takePicture(final Handler handler, 1129 final CameraShutterCallback shutter, 1130 CameraPictureCallback raw, 1131 CameraPictureCallback postview, 1132 final CameraPictureCallback jpeg) { 1133 // TODO: We never call raw or postview 1134 final CaptureAvailableListener picListener = 1135 new CaptureAvailableListener() { 1136 @Override 1137 public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, 1138 long timestamp, long frameNumber) { 1139 if (shutter != null) { 1140 handler.post(new Runnable() { 1141 @Override 1142 public void run() { 1143 if (mShutterSoundEnabled) { 1144 mNoisemaker.play(MediaActionSound.SHUTTER_CLICK); 1145 } 1146 shutter.onShutter(AndroidCamera2ProxyImpl.this); 1147 }}); 1148 } 1149 } 1150 1151 @Override 1152 public void onImageAvailable(ImageReader reader) { 1153 try (Image image = reader.acquireNextImage()) { 1154 if (jpeg != null) { 1155 ByteBuffer buffer = image.getPlanes()[0].getBuffer(); 1156 final byte[] pixels = new byte[buffer.remaining()]; 1157 buffer.get(pixels); 1158 handler.post(new Runnable() { 1159 @Override 1160 public void run() { 1161 jpeg.onPictureTaken(pixels, AndroidCamera2ProxyImpl.this); 1162 }}); 1163 } 1164 } 1165 }}; 1166 try { 1167 mDispatchThread.runJob(new Runnable() { 1168 @Override 1169 public void run() { 1170 // Wait until PREVIEW_ACTIVE or better 1171 mCameraState.waitForStates( 1172 ~(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE - 1)); 1173 mCameraHandler.obtainMessage(CameraActions.CAPTURE_PHOTO, picListener) 1174 .sendToTarget(); 1175 } 1176 }); 1177 } catch (RuntimeException ex) { 1178 mCameraAgent.getCameraExceptionHandler().onDispatchThreadException(ex); 1179 } 1180 } 1181 1182 // TODO: Implement 1183 @Override setZoomChangeListener(android.hardware.Camera.OnZoomChangeListener listener)1184 public void setZoomChangeListener(android.hardware.Camera.OnZoomChangeListener listener) {} 1185 1186 // TODO: Implement 1187 @Override setFaceDetectionCallback(Handler handler, CameraFaceDetectionCallback callback)1188 public void setFaceDetectionCallback(Handler handler, CameraFaceDetectionCallback callback) 1189 {} 1190 1191 // TODO: Remove this method override once we handle this message 1192 @Override startFaceDetection()1193 public void startFaceDetection() {} 1194 1195 // TODO: Remove this method override once we handle this message 1196 @Override stopFaceDetection()1197 public void stopFaceDetection() {} 1198 1199 // TODO: Implement 1200 @Override setParameters(android.hardware.Camera.Parameters params)1201 public void setParameters(android.hardware.Camera.Parameters params) {} 1202 1203 // TODO: Implement 1204 @Override getParameters()1205 public android.hardware.Camera.Parameters getParameters() { return null; } 1206 1207 @Override getSettings()1208 public CameraSettings getSettings() { 1209 if (mLastSettings == null) { 1210 mLastSettings = mCameraHandler.buildSettings(mCapabilities); 1211 } 1212 return mLastSettings; 1213 } 1214 1215 @Override applySettings(CameraSettings settings)1216 public boolean applySettings(CameraSettings settings) { 1217 if (settings == null) { 1218 Log.w(TAG, "null parameters in applySettings()"); 1219 return false; 1220 } 1221 if (!(settings instanceof AndroidCamera2Settings)) { 1222 Log.e(TAG, "Provided settings not compatible with the backing framework API"); 1223 return false; 1224 } 1225 1226 // Wait for any state that isn't OPENED 1227 if (applySettingsHelper(settings, ~AndroidCamera2StateHolder.CAMERA_UNOPENED)) { 1228 mLastSettings = settings; 1229 return true; 1230 } 1231 return false; 1232 } 1233 1234 @Override enableShutterSound(boolean enable)1235 public void enableShutterSound(boolean enable) { 1236 mShutterSoundEnabled = enable; 1237 } 1238 1239 // TODO: Implement 1240 @Override dumpDeviceSettings()1241 public String dumpDeviceSettings() { return null; } 1242 1243 @Override getCameraHandler()1244 public Handler getCameraHandler() { 1245 return AndroidCamera2AgentImpl.this.getCameraHandler(); 1246 } 1247 1248 @Override getDispatchThread()1249 public DispatchThread getDispatchThread() { 1250 return AndroidCamera2AgentImpl.this.getDispatchThread(); 1251 } 1252 1253 @Override getCameraState()1254 public CameraStateHolder getCameraState() { 1255 return mCameraState; 1256 } 1257 } 1258 1259 /** A linear state machine: each state entails all the states below it. */ 1260 private static class AndroidCamera2StateHolder extends CameraStateHolder { 1261 // Usage flow: openCamera() -> applySettings() -> setPreviewTexture() -> startPreview() -> 1262 // autoFocus() -> takePicture() 1263 // States are mutually exclusive, but must be separate bits so that they can be used with 1264 // the StateHolder#waitForStates() and StateHolder#waitToAvoidStates() methods. 1265 // Do not set the state to be a combination of these values! 1266 /* Camera states */ 1267 /** No camera device is opened. */ 1268 public static final int CAMERA_UNOPENED = 1 << 0; 1269 /** A camera is opened, but no settings have been provided. */ 1270 public static final int CAMERA_UNCONFIGURED = 1 << 1; 1271 /** The open camera has been configured by providing it with settings. */ 1272 public static final int CAMERA_CONFIGURED = 1 << 2; 1273 /** A capture session is ready to stream a preview, but still has no repeating request. */ 1274 public static final int CAMERA_PREVIEW_READY = 1 << 3; 1275 /** A preview is currently being streamed. */ 1276 public static final int CAMERA_PREVIEW_ACTIVE = 1 << 4; 1277 /** The lens is locked on a particular region. */ 1278 public static final int CAMERA_FOCUS_LOCKED = 1 << 5; 1279 AndroidCamera2StateHolder()1280 public AndroidCamera2StateHolder() { 1281 this(CAMERA_UNOPENED); 1282 } 1283 AndroidCamera2StateHolder(int state)1284 public AndroidCamera2StateHolder(int state) { 1285 super(state); 1286 } 1287 } 1288 1289 private static class AndroidCamera2DeviceInfo implements CameraDeviceInfo { 1290 private final CameraManager mCameraManager; 1291 private final String[] mCameraIds; 1292 private final int mNumberOfCameras; 1293 private final int mFirstBackCameraId; 1294 private final int mFirstFrontCameraId; 1295 AndroidCamera2DeviceInfo(CameraManager cameraManager, String[] cameraIds, int numberOfCameras)1296 public AndroidCamera2DeviceInfo(CameraManager cameraManager, 1297 String[] cameraIds, int numberOfCameras) { 1298 mCameraManager = cameraManager; 1299 mCameraIds = cameraIds; 1300 mNumberOfCameras = numberOfCameras; 1301 1302 int firstBackId = NO_DEVICE; 1303 int firstFrontId = NO_DEVICE; 1304 for (int id = 0; id < cameraIds.length; ++id) { 1305 try { 1306 int lensDirection = cameraManager.getCameraCharacteristics(cameraIds[id]) 1307 .get(CameraCharacteristics.LENS_FACING); 1308 if (firstBackId == NO_DEVICE && 1309 lensDirection == CameraCharacteristics.LENS_FACING_BACK) { 1310 firstBackId = id; 1311 } 1312 if (firstFrontId == NO_DEVICE && 1313 lensDirection == CameraCharacteristics.LENS_FACING_FRONT) { 1314 firstFrontId = id; 1315 } 1316 } catch (CameraAccessException ex) { 1317 Log.w(TAG, "Couldn't get characteristics of camera '" + id + "'", ex); 1318 } 1319 } 1320 mFirstBackCameraId = firstBackId; 1321 mFirstFrontCameraId = firstFrontId; 1322 } 1323 1324 @Override getCharacteristics(int cameraId)1325 public Characteristics getCharacteristics(int cameraId) { 1326 String actualId = mCameraIds[cameraId]; 1327 try { 1328 CameraCharacteristics info = mCameraManager.getCameraCharacteristics(actualId); 1329 return new AndroidCharacteristics2(info); 1330 } catch (CameraAccessException ex) { 1331 return null; 1332 } 1333 } 1334 1335 @Override getNumberOfCameras()1336 public int getNumberOfCameras() { 1337 return mNumberOfCameras; 1338 } 1339 1340 @Override getFirstBackCameraId()1341 public int getFirstBackCameraId() { 1342 return mFirstBackCameraId; 1343 } 1344 1345 @Override getFirstFrontCameraId()1346 public int getFirstFrontCameraId() { 1347 return mFirstFrontCameraId; 1348 } 1349 1350 private static class AndroidCharacteristics2 extends Characteristics { 1351 private CameraCharacteristics mCameraInfo; 1352 AndroidCharacteristics2(CameraCharacteristics cameraInfo)1353 AndroidCharacteristics2(CameraCharacteristics cameraInfo) { 1354 mCameraInfo = cameraInfo; 1355 } 1356 1357 @Override isFacingBack()1358 public boolean isFacingBack() { 1359 return mCameraInfo.get(CameraCharacteristics.LENS_FACING) 1360 .equals(CameraCharacteristics.LENS_FACING_BACK); 1361 } 1362 1363 @Override isFacingFront()1364 public boolean isFacingFront() { 1365 return mCameraInfo.get(CameraCharacteristics.LENS_FACING) 1366 .equals(CameraCharacteristics.LENS_FACING_FRONT); 1367 } 1368 1369 @Override getSensorOrientation()1370 public int getSensorOrientation() { 1371 return mCameraInfo.get(CameraCharacteristics.SENSOR_ORIENTATION); 1372 } 1373 1374 @Override getPreviewTransform(int currentDisplayOrientation, RectF surfaceDimensions, RectF desiredBounds)1375 public Matrix getPreviewTransform(int currentDisplayOrientation, 1376 RectF surfaceDimensions, 1377 RectF desiredBounds) { 1378 if (!orientationIsValid(currentDisplayOrientation)) { 1379 return new Matrix(); 1380 } 1381 1382 // The system transparently transforms the image to fill the surface 1383 // when the device is in its natural orientation. We rotate the 1384 // coordinates of the rectangle's corners to be relative to the 1385 // original image, instead of to the current screen orientation. 1386 float[] surfacePolygon = rotate(convertRectToPoly(surfaceDimensions), 1387 2 * currentDisplayOrientation / 90); 1388 float[] desiredPolygon = convertRectToPoly(desiredBounds); 1389 1390 Matrix transform = new Matrix(); 1391 // Use polygons instead of rectangles so that rotation will be 1392 // calculated, since that is not done by the new camera API. 1393 transform.setPolyToPoly(surfacePolygon, 0, desiredPolygon, 0, 4); 1394 return transform; 1395 } 1396 1397 @Override canDisableShutterSound()1398 public boolean canDisableShutterSound() { 1399 return true; 1400 } 1401 convertRectToPoly(RectF rf)1402 private static float[] convertRectToPoly(RectF rf) { 1403 return new float[] {rf.left, rf.top, rf.right, rf.top, 1404 rf.right, rf.bottom, rf.left, rf.bottom}; 1405 } 1406 rotate(float[] arr, int times)1407 private static float[] rotate(float[] arr, int times) { 1408 if (times < 0) { 1409 times = times % arr.length + arr.length; 1410 } 1411 1412 float[] res = new float[arr.length]; 1413 for (int offset = 0; offset < arr.length; ++offset) { 1414 res[offset] = arr[(times + offset) % arr.length]; 1415 } 1416 return res; 1417 } 1418 } 1419 } 1420 } 1421