AndroidCameraAgentImpl.java revision 50f5b019ba3f333a09a1beb9667fd7290082dc31
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.ex.camera2.portability; 18 19import android.annotation.TargetApi; 20import android.graphics.SurfaceTexture; 21import android.hardware.Camera; 22import android.hardware.Camera.AutoFocusCallback; 23import android.hardware.Camera.AutoFocusMoveCallback; 24import android.hardware.Camera.ErrorCallback; 25import android.hardware.Camera.FaceDetectionListener; 26import android.hardware.Camera.OnZoomChangeListener; 27import android.hardware.Camera.Parameters; 28import android.hardware.Camera.PictureCallback; 29import android.hardware.Camera.PreviewCallback; 30import android.hardware.Camera.ShutterCallback; 31import android.os.Build; 32import android.os.Handler; 33import android.os.HandlerThread; 34import android.os.Looper; 35import android.os.Message; 36import android.view.SurfaceHolder; 37 38import com.android.ex.camera2.portability.debug.Log; 39 40import java.io.IOException; 41import java.util.StringTokenizer; 42 43/** 44 * A class to implement {@link CameraAgent} of the Android camera framework. 45 */ 46class AndroidCameraAgentImpl extends CameraAgent { 47 private static final Log.Tag TAG = new Log.Tag("AndCamAgntImp"); 48 49 private Parameters mParameters; 50 private boolean mParametersIsDirty; 51 private CameraDeviceInfo.Characteristics mCharacteristics; 52 private AndroidCameraCapabilities mCapabilities; 53 54 private final CameraHandler mCameraHandler; 55 private final HandlerThread mCameraHandlerThread; 56 private final CameraStateHolder mCameraState; 57 private final DispatchThread mDispatchThread; 58 59 private Handler mCameraExceptionCallbackHandler; 60 private CameraExceptionCallback mCameraExceptionCallback = 61 new CameraExceptionCallback() { 62 @Override 63 public void onCameraException(RuntimeException e) { 64 throw e; 65 } 66 }; 67 68 AndroidCameraAgentImpl() { 69 mCameraHandlerThread = new HandlerThread("Camera Handler Thread"); 70 mCameraHandlerThread.start(); 71 mCameraHandler = new CameraHandler(mCameraHandlerThread.getLooper()); 72 mCameraExceptionCallbackHandler = mCameraHandler; 73 mCameraState = new AndroidCameraStateHolder(); 74 mDispatchThread = new DispatchThread(mCameraHandler, mCameraHandlerThread); 75 mDispatchThread.start(); 76 } 77 78 @Override 79 public void setCameraDefaultExceptionCallback(CameraExceptionCallback callback, 80 Handler handler) { 81 synchronized (mCameraExceptionCallback) { 82 mCameraExceptionCallback = callback; 83 mCameraExceptionCallbackHandler = handler; 84 } 85 } 86 87 @Override 88 public void recycle() { 89 closeCamera(null, true); 90 mDispatchThread.end(); 91 } 92 93 @Override 94 public CameraDeviceInfo getCameraDeviceInfo() { 95 return AndroidCameraDeviceInfo.create(); 96 } 97 98 @Override 99 protected Handler getCameraHandler() { 100 return mCameraHandler; 101 } 102 103 @Override 104 protected DispatchThread getDispatchThread() { 105 return mDispatchThread; 106 } 107 108 private static class AndroidCameraDeviceInfo implements CameraDeviceInfo { 109 private final Camera.CameraInfo[] mCameraInfos; 110 private final int mNumberOfCameras; 111 private final int mFirstBackCameraId; 112 private final int mFirstFrontCameraId; 113 114 private AndroidCameraDeviceInfo(Camera.CameraInfo[] info, int numberOfCameras, 115 int firstBackCameraId, int firstFrontCameraId) { 116 117 mCameraInfos = info; 118 mNumberOfCameras = numberOfCameras; 119 mFirstBackCameraId = firstBackCameraId; 120 mFirstFrontCameraId = firstFrontCameraId; 121 } 122 123 public static AndroidCameraDeviceInfo create() { 124 int numberOfCameras; 125 Camera.CameraInfo[] cameraInfos; 126 try { 127 numberOfCameras = Camera.getNumberOfCameras(); 128 cameraInfos = new Camera.CameraInfo[numberOfCameras]; 129 for (int i = 0; i < numberOfCameras; i++) { 130 cameraInfos[i] = new Camera.CameraInfo(); 131 Camera.getCameraInfo(i, cameraInfos[i]); 132 } 133 } catch (RuntimeException ex) { 134 return null; 135 } 136 137 int firstFront = NO_DEVICE; 138 int firstBack = NO_DEVICE; 139 // Get the first (smallest) back and first front camera id. 140 for (int i = numberOfCameras - 1; i >= 0; i--) { 141 if (cameraInfos[i].facing == Camera.CameraInfo.CAMERA_FACING_BACK) { 142 firstBack = i; 143 } else { 144 if (cameraInfos[i].facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { 145 firstFront = i; 146 } 147 } 148 } 149 150 return new AndroidCameraDeviceInfo(cameraInfos, numberOfCameras, firstBack, firstFront); 151 } 152 153 @Override 154 public Characteristics getCharacteristics(int cameraId) { 155 Camera.CameraInfo info = mCameraInfos[cameraId]; 156 if (info != null) { 157 return new AndroidCharacteristics(info); 158 } else { 159 return null; 160 } 161 } 162 163 @Override 164 public int getNumberOfCameras() { 165 return mNumberOfCameras; 166 } 167 168 @Override 169 public int getFirstBackCameraId() { 170 return mFirstBackCameraId; 171 } 172 173 @Override 174 public int getFirstFrontCameraId() { 175 return mFirstFrontCameraId; 176 } 177 178 private static class AndroidCharacteristics implements Characteristics { 179 private Camera.CameraInfo mCameraInfo; 180 181 AndroidCharacteristics(Camera.CameraInfo cameraInfo) { 182 mCameraInfo = cameraInfo; 183 } 184 185 @Override 186 public boolean isFacingBack() { 187 return mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK; 188 } 189 190 @Override 191 public boolean isFacingFront() { 192 return mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT; 193 } 194 195 @Override 196 public int getSensorOrientation() { 197 return mCameraInfo.orientation; 198 } 199 200 @Override 201 public boolean canDisableShutterSound() { 202 return mCameraInfo.canDisableShutterSound; 203 } 204 } 205 } 206 207 /** 208 * The handler on which the actual camera operations happen. 209 */ 210 private class CameraHandler extends HistoryHandler { 211 212 // Used to retain a copy of Parameters for setting parameters. 213 private Parameters mParamsToSet; 214 private Camera mCamera; 215 private int mCameraId; 216 217 private class CaptureCallbacks { 218 public final ShutterCallback mShutter; 219 public final PictureCallback mRaw; 220 public final PictureCallback mPostView; 221 public final PictureCallback mJpeg; 222 223 CaptureCallbacks(ShutterCallback shutter, PictureCallback raw, PictureCallback postView, 224 PictureCallback jpeg) { 225 mShutter = shutter; 226 mRaw = raw; 227 mPostView = postView; 228 mJpeg = jpeg; 229 } 230 } 231 232 CameraHandler(Looper looper) { 233 super(looper); 234 } 235 236 private void startFaceDetection() { 237 mCamera.startFaceDetection(); 238 } 239 240 private void stopFaceDetection() { 241 mCamera.stopFaceDetection(); 242 } 243 244 private void setFaceDetectionListener(FaceDetectionListener listener) { 245 mCamera.setFaceDetectionListener(listener); 246 } 247 248 private void setPreviewTexture(Object surfaceTexture) { 249 try { 250 mCamera.setPreviewTexture((SurfaceTexture) surfaceTexture); 251 } catch (IOException e) { 252 Log.e(TAG, "Could not set preview texture", e); 253 } 254 } 255 256 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) 257 private void enableShutterSound(boolean enable) { 258 mCamera.enableShutterSound(enable); 259 } 260 261 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 262 private void setAutoFocusMoveCallback( 263 android.hardware.Camera camera, Object cb) { 264 try { 265 camera.setAutoFocusMoveCallback((AutoFocusMoveCallback) cb); 266 } catch (RuntimeException ex) { 267 Log.w(TAG, ex.getMessage()); 268 } 269 } 270 271 private void capture(final CaptureCallbacks cb) { 272 try { 273 mCamera.takePicture(cb.mShutter, cb.mRaw, cb.mPostView, cb.mJpeg); 274 } catch (RuntimeException e) { 275 // TODO: output camera state and focus state for debugging. 276 Log.e(TAG, "take picture failed."); 277 throw e; 278 } 279 } 280 281 public void requestTakePicture( 282 final ShutterCallback shutter, 283 final PictureCallback raw, 284 final PictureCallback postView, 285 final PictureCallback jpeg) { 286 final CaptureCallbacks callbacks = new CaptureCallbacks(shutter, raw, postView, jpeg); 287 obtainMessage(CameraActions.CAPTURE_PHOTO, callbacks).sendToTarget(); 288 } 289 290 /** 291 * This method does not deal with the API level check. Everyone should 292 * check first for supported operations before sending message to this handler. 293 */ 294 @Override 295 public void handleMessage(final Message msg) { 296 super.handleMessage(msg); 297 try { 298 switch (msg.what) { 299 case CameraActions.OPEN_CAMERA: { 300 final CameraOpenCallback openCallback = (CameraOpenCallback) msg.obj; 301 final int cameraId = msg.arg1; 302 if (mCameraState.getState() != AndroidCameraStateHolder.CAMERA_UNOPENED) { 303 openCallback.onDeviceOpenedAlready(cameraId, generateHistoryString(cameraId)); 304 break; 305 } 306 307 Log.i(TAG, "Opening camera " + cameraId + " with camera1 API"); 308 mCamera = android.hardware.Camera.open(cameraId); 309 if (mCamera != null) { 310 mCameraId = cameraId; 311 mParametersIsDirty = true; 312 313 // Get an instance of Camera.Parameters for later use. 314 mParamsToSet = mCamera.getParameters(); 315 mCharacteristics = 316 AndroidCameraDeviceInfo.create().getCharacteristics(cameraId); 317 mCapabilities = new AndroidCameraCapabilities(mParamsToSet); 318 319 mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE); 320 if (openCallback != null) { 321 openCallback.onCameraOpened( 322 new AndroidCameraProxyImpl(cameraId, mCamera, 323 mCharacteristics, mCapabilities)); 324 } 325 } else { 326 if (openCallback != null) { 327 openCallback.onDeviceOpenFailure(cameraId, generateHistoryString(cameraId)); 328 } 329 } 330 break; 331 } 332 333 case CameraActions.RELEASE: { 334 if (mCamera != null) { 335 mCamera.release(); 336 mCameraState.setState(AndroidCameraStateHolder.CAMERA_UNOPENED); 337 mCamera = null; 338 } else { 339 Log.w(TAG, "Releasing camera without any camera opened."); 340 } 341 break; 342 } 343 344 case CameraActions.RECONNECT: { 345 final CameraOpenCallbackForward cbForward = 346 (CameraOpenCallbackForward) msg.obj; 347 final int cameraId = msg.arg1; 348 try { 349 mCamera.reconnect(); 350 } catch (IOException ex) { 351 if (cbForward != null) { 352 cbForward.onReconnectionFailure(AndroidCameraAgentImpl.this, 353 generateHistoryString(mCameraId)); 354 } 355 break; 356 } 357 358 mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE); 359 if (cbForward != null) { 360 cbForward.onCameraOpened( 361 new AndroidCameraProxyImpl(cameraId, mCamera, mCharacteristics, 362 mCapabilities)); 363 } 364 break; 365 } 366 367 case CameraActions.UNLOCK: { 368 mCamera.unlock(); 369 mCameraState.setState(AndroidCameraStateHolder.CAMERA_UNLOCKED); 370 break; 371 } 372 373 case CameraActions.LOCK: { 374 mCamera.lock(); 375 mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE); 376 break; 377 } 378 379 case CameraActions.SET_PREVIEW_TEXTURE_ASYNC: { 380 setPreviewTexture(msg.obj); 381 break; 382 } 383 384 case CameraActions.SET_PREVIEW_DISPLAY_ASYNC: { 385 try { 386 mCamera.setPreviewDisplay((SurfaceHolder) msg.obj); 387 } catch (IOException e) { 388 throw new RuntimeException(e); 389 } 390 break; 391 } 392 393 case CameraActions.START_PREVIEW_ASYNC: { 394 final CameraStartPreviewCallbackForward cbForward = 395 (CameraStartPreviewCallbackForward) msg.obj; 396 mCamera.startPreview(); 397 if (cbForward != null) { 398 cbForward.onPreviewStarted(); 399 } 400 break; 401 } 402 403 case CameraActions.STOP_PREVIEW: { 404 mCamera.stopPreview(); 405 break; 406 } 407 408 case CameraActions.SET_PREVIEW_CALLBACK_WITH_BUFFER: { 409 mCamera.setPreviewCallbackWithBuffer((PreviewCallback) msg.obj); 410 break; 411 } 412 413 case CameraActions.SET_ONE_SHOT_PREVIEW_CALLBACK: { 414 mCamera.setOneShotPreviewCallback((PreviewCallback) msg.obj); 415 break; 416 } 417 418 case CameraActions.ADD_CALLBACK_BUFFER: { 419 mCamera.addCallbackBuffer((byte[]) msg.obj); 420 break; 421 } 422 423 case CameraActions.AUTO_FOCUS: { 424 mCameraState.setState(AndroidCameraStateHolder.CAMERA_FOCUSING); 425 mCamera.autoFocus((AutoFocusCallback) msg.obj); 426 break; 427 } 428 429 case CameraActions.CANCEL_AUTO_FOCUS: { 430 mCamera.cancelAutoFocus(); 431 mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE); 432 break; 433 } 434 435 case CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK: { 436 setAutoFocusMoveCallback(mCamera, msg.obj); 437 break; 438 } 439 440 case CameraActions.SET_DISPLAY_ORIENTATION: { 441 mCamera.setDisplayOrientation(msg.arg1); 442 break; 443 } 444 445 case CameraActions.SET_ZOOM_CHANGE_LISTENER: { 446 mCamera.setZoomChangeListener((OnZoomChangeListener) msg.obj); 447 break; 448 } 449 450 case CameraActions.SET_FACE_DETECTION_LISTENER: { 451 setFaceDetectionListener((FaceDetectionListener) msg.obj); 452 break; 453 } 454 455 case CameraActions.START_FACE_DETECTION: { 456 startFaceDetection(); 457 break; 458 } 459 460 case CameraActions.STOP_FACE_DETECTION: { 461 stopFaceDetection(); 462 break; 463 } 464 465 case CameraActions.SET_ERROR_CALLBACK: { 466 mCamera.setErrorCallback((ErrorCallback) msg.obj); 467 break; 468 } 469 470 case CameraActions.APPLY_SETTINGS: { 471 mParametersIsDirty = true; 472 CameraSettings settings = (CameraSettings) msg.obj; 473 applyToParameters(settings); 474 mCamera.setParameters(mParamsToSet); 475 break; 476 } 477 478 case CameraActions.SET_PARAMETERS: { 479 mParametersIsDirty = true; 480 mParamsToSet.unflatten((String) msg.obj); 481 mCamera.setParameters(mParamsToSet); 482 break; 483 } 484 485 case CameraActions.GET_PARAMETERS: { 486 if (mParametersIsDirty) { 487 mParameters = mCamera.getParameters(); 488 mParametersIsDirty = false; 489 } 490 break; 491 } 492 493 case CameraActions.SET_PREVIEW_CALLBACK: { 494 mCamera.setPreviewCallback((PreviewCallback) msg.obj); 495 break; 496 } 497 498 case CameraActions.ENABLE_SHUTTER_SOUND: { 499 enableShutterSound((msg.arg1 == 1) ? true : false); 500 break; 501 } 502 503 case CameraActions.REFRESH_PARAMETERS: { 504 mParametersIsDirty = true; 505 break; 506 } 507 508 case CameraActions.CAPTURE_PHOTO: { 509 mCameraState.setState(AndroidCameraStateHolder.CAMERA_CAPTURING); 510 capture((CaptureCallbacks) msg.obj); 511 break; 512 } 513 514 default: { 515 throw new RuntimeException("Invalid CameraProxy message=" + msg.what); 516 } 517 } 518 } catch (final RuntimeException e) { 519 if (msg.what != CameraActions.RELEASE && mCamera != null) { 520 try { 521 mCamera.release(); 522 mCameraState.setState(AndroidCameraStateHolder.CAMERA_UNOPENED); 523 } catch (Exception ex) { 524 Log.e(TAG, "Fail to release the camera."); 525 } 526 mCamera = null; 527 } else { 528 if (mCamera == null) { 529 if (msg.what == CameraActions.OPEN_CAMERA) { 530 final int cameraId = msg.arg1; 531 if (msg.obj != null) { 532 ((CameraOpenCallback) msg.obj).onDeviceOpenFailure( 533 msg.arg1, generateHistoryString(cameraId)); 534 } 535 } else { 536 Log.w(TAG, "Cannot handle message " + msg.what + ", mCamera is null."); 537 } 538 return; 539 } 540 } 541 synchronized (mCameraExceptionCallback) { 542 mCameraExceptionCallbackHandler.post(new Runnable() { 543 @Override 544 public void run() { 545 mCameraExceptionCallback.onCameraException(e); 546 } 547 }); 548 } 549 } 550 } 551 552 private void applyToParameters(final CameraSettings settings) { 553 final CameraCapabilities.Stringifier stringifier = mCapabilities.getStringifier(); 554 Size photoSize = settings.getCurrentPhotoSize(); 555 mParamsToSet.setPictureSize(photoSize.width(), photoSize.height()); 556 Size previewSize = settings.getCurrentPreviewSize(); 557 mParamsToSet.setPreviewSize(previewSize.width(), previewSize.height()); 558 if (settings.getPreviewFrameRate() == -1) { 559 mParamsToSet.setPreviewFpsRange(settings.getPreviewFpsRangeMin(), 560 settings.getPreviewFpsRangeMax()); 561 } else { 562 mParamsToSet.setPreviewFrameRate(settings.getPreviewFrameRate()); 563 } 564 mParamsToSet.setPreviewFormat(settings.getCurrentPreviewFormat()); 565 mParamsToSet.setJpegQuality(settings.getPhotoJpegCompressionQuality()); 566 if (mCapabilities.supports(CameraCapabilities.Feature.ZOOM)) { 567 // Should use settings.getCurrentZoomRatio() instead here. 568 mParamsToSet.setZoom(settings.getCurrentZoomIndex()); 569 } 570 mParamsToSet.setRotation((int) settings.getCurrentPhotoRotationDegrees()); 571 mParamsToSet.setExposureCompensation(settings.getExposureCompensationIndex()); 572 if (mCapabilities.supports(CameraCapabilities.Feature.AUTO_EXPOSURE_LOCK)) { 573 mParamsToSet.setAutoExposureLock(settings.isAutoExposureLocked()); 574 } 575 mParamsToSet.setFocusMode(stringifier.stringify(settings.getCurrentFocusMode())); 576 if (mCapabilities.supports(CameraCapabilities.Feature.AUTO_WHITE_BALANCE_LOCK)) { 577 mParamsToSet.setAutoWhiteBalanceLock(settings.isAutoWhiteBalanceLocked()); 578 } 579 if (mCapabilities.supports(CameraCapabilities.Feature.FOCUS_AREA)) { 580 if (settings.getFocusAreas().size() != 0) { 581 mParamsToSet.setFocusAreas(settings.getFocusAreas()); 582 } 583 } 584 if (mCapabilities.supports(CameraCapabilities.Feature.METERING_AREA)) { 585 if (settings.getMeteringAreas().size() != 0) { 586 mParamsToSet.setMeteringAreas(settings.getMeteringAreas()); 587 } 588 } 589 if (settings.getCurrentFlashMode() != CameraCapabilities.FlashMode.NO_FLASH) { 590 mParamsToSet.setFlashMode(stringifier.stringify(settings.getCurrentFlashMode())); 591 } 592 if (settings.getCurrentSceneMode() != CameraCapabilities.SceneMode.NO_SCENE_MODE) { 593 if (settings.getCurrentSceneMode() != null) { 594 mParamsToSet 595 .setSceneMode(stringifier.stringify(settings.getCurrentSceneMode())); 596 } 597 } 598 mParamsToSet.setRecordingHint(settings.isRecordingHintEnabled()); 599 Size jpegThumbSize = settings.getExifThumbnailSize(); 600 mParamsToSet.setJpegThumbnailSize(jpegThumbSize.width(), jpegThumbSize.height()); 601 mParamsToSet.setPictureFormat(settings.getCurrentPhotoFormat()); 602 603 CameraSettings.GpsData gpsData = settings.getGpsData(); 604 if (gpsData == null) { 605 mParamsToSet.removeGpsData(); 606 } else { 607 mParamsToSet.setGpsTimestamp(gpsData.timeStamp); 608 if (gpsData.processingMethod != null) { 609 // It's a hack since we always use GPS time stamp but does 610 // not use other fields sometimes. Setting processing 611 // method to null means the other fields should not be used. 612 mParamsToSet.setGpsAltitude(gpsData.altitude); 613 mParamsToSet.setGpsLatitude(gpsData.latitude); 614 mParamsToSet.setGpsLongitude(gpsData.longitude); 615 mParamsToSet.setGpsProcessingMethod(gpsData.processingMethod); 616 } 617 } 618 619 } 620 } 621 622 /** 623 * A class which implements {@link CameraAgent.CameraProxy} and 624 * camera handler thread. 625 */ 626 private class AndroidCameraProxyImpl extends CameraAgent.CameraProxy { 627 private final int mCameraId; 628 /* TODO: remove this Camera instance. */ 629 private final Camera mCamera; 630 private final CameraDeviceInfo.Characteristics mCharacteristics; 631 private final AndroidCameraCapabilities mCapabilities; 632 633 private AndroidCameraProxyImpl(int cameraId, Camera camera, 634 CameraDeviceInfo.Characteristics characteristics, 635 AndroidCameraCapabilities capabilities) { 636 mCamera = camera; 637 mCameraId = cameraId; 638 mCharacteristics = characteristics; 639 mCapabilities = capabilities; 640 } 641 642 @Override 643 public android.hardware.Camera getCamera() { 644 return mCamera; 645 } 646 647 @Override 648 public int getCameraId() { 649 return mCameraId; 650 } 651 652 @Override 653 public CameraDeviceInfo.Characteristics getCharacteristics() { 654 return mCharacteristics; 655 } 656 657 @Override 658 public CameraCapabilities getCapabilities() { 659 return new AndroidCameraCapabilities(mCapabilities); 660 } 661 662 @Override 663 public void setPreviewDataCallback( 664 final Handler handler, final CameraPreviewDataCallback cb) { 665 mDispatchThread.runJob(new Runnable() { 666 @Override 667 public void run() { 668 mCameraHandler.obtainMessage(CameraActions.SET_PREVIEW_CALLBACK, 669 PreviewCallbackForward.getNewInstance( 670 handler, AndroidCameraProxyImpl.this, cb)) 671 .sendToTarget(); 672 } 673 }); 674 } 675 676 @Override 677 public void setOneShotPreviewCallback(final Handler handler, 678 final CameraPreviewDataCallback cb) { 679 mDispatchThread.runJob(new Runnable() { 680 @Override 681 public void run() { 682 mCameraHandler.obtainMessage(CameraActions.SET_ONE_SHOT_PREVIEW_CALLBACK, 683 PreviewCallbackForward 684 .getNewInstance(handler, AndroidCameraProxyImpl.this, cb)) 685 .sendToTarget(); 686 } 687 }); 688 } 689 690 @Override 691 public void setPreviewDataCallbackWithBuffer( 692 final Handler handler, final CameraPreviewDataCallback cb) { 693 mDispatchThread.runJob(new Runnable() { 694 @Override 695 public void run() { 696 mCameraHandler.obtainMessage(CameraActions.SET_PREVIEW_CALLBACK_WITH_BUFFER, 697 PreviewCallbackForward 698 .getNewInstance(handler, AndroidCameraProxyImpl.this, cb)) 699 .sendToTarget(); 700 } 701 }); 702 } 703 704 @Override 705 public void autoFocus(final Handler handler, final CameraAFCallback cb) { 706 final AutoFocusCallback afCallback = new AutoFocusCallback() { 707 @Override 708 public void onAutoFocus(final boolean b, Camera camera) { 709 if (mCameraState.getState() != AndroidCameraStateHolder.CAMERA_FOCUSING) { 710 Log.w(TAG, "onAutoFocus callback returning when not focusing"); 711 } else { 712 mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE); 713 } 714 handler.post(new Runnable() { 715 @Override 716 public void run() { 717 cb.onAutoFocus(b, AndroidCameraProxyImpl.this); 718 } 719 }); 720 } 721 }; 722 mDispatchThread.runJob(new Runnable() { 723 @Override 724 public void run() { 725 mCameraState.waitForStates(AndroidCameraStateHolder.CAMERA_IDLE); 726 mCameraHandler.obtainMessage(CameraActions.AUTO_FOCUS, afCallback) 727 .sendToTarget(); 728 } 729 }); 730 } 731 732 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 733 @Override 734 public void setAutoFocusMoveCallback( 735 final Handler handler, final CameraAFMoveCallback cb) { 736 mDispatchThread.runJob(new Runnable() { 737 @Override 738 public void run() { 739 mCameraHandler.obtainMessage(CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK, 740 AFMoveCallbackForward.getNewInstance( 741 handler, AndroidCameraProxyImpl.this, cb)) 742 .sendToTarget(); 743 } 744 }); 745 } 746 747 @Override 748 public void takePicture( 749 final Handler handler, final CameraShutterCallback shutter, 750 final CameraPictureCallback raw, final CameraPictureCallback post, 751 final CameraPictureCallback jpeg) { 752 final PictureCallback jpegCallback = new PictureCallback() { 753 @Override 754 public void onPictureTaken(final byte[] data, Camera camera) { 755 if (mCameraState.getState() != AndroidCameraStateHolder.CAMERA_CAPTURING) { 756 Log.w(TAG, "picture callback returning when not capturing"); 757 } else { 758 mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE); 759 } 760 handler.post(new Runnable() { 761 @Override 762 public void run() { 763 jpeg.onPictureTaken(data, AndroidCameraProxyImpl.this); 764 } 765 }); 766 } 767 }; 768 769 mDispatchThread.runJob(new Runnable() { 770 @Override 771 public void run() { 772 mCameraState.waitForStates(AndroidCameraStateHolder.CAMERA_IDLE | 773 AndroidCameraStateHolder.CAMERA_UNLOCKED); 774 mCameraHandler.requestTakePicture(ShutterCallbackForward 775 .getNewInstance(handler, AndroidCameraProxyImpl.this, shutter), 776 PictureCallbackForward 777 .getNewInstance(handler, AndroidCameraProxyImpl.this, raw), 778 PictureCallbackForward 779 .getNewInstance(handler, AndroidCameraProxyImpl.this, post), 780 jpegCallback 781 ); 782 } 783 }); 784 } 785 786 @Override 787 public void setZoomChangeListener(final OnZoomChangeListener listener) { 788 mDispatchThread.runJob(new Runnable() { 789 @Override 790 public void run() { 791 mCameraHandler.obtainMessage(CameraActions.SET_ZOOM_CHANGE_LISTENER, listener) 792 .sendToTarget(); 793 } 794 }); 795 } 796 797 @Override 798 public void setFaceDetectionCallback(final Handler handler, 799 final CameraFaceDetectionCallback cb) { 800 mDispatchThread.runJob(new Runnable() { 801 @Override 802 public void run() { 803 mCameraHandler.obtainMessage(CameraActions.SET_FACE_DETECTION_LISTENER, 804 FaceDetectionCallbackForward 805 .getNewInstance(handler, AndroidCameraProxyImpl.this, cb)) 806 .sendToTarget(); 807 } 808 }); 809 } 810 811 @Override 812 public void setErrorCallback(final Handler handler, final CameraErrorCallback cb) { 813 mDispatchThread.runJob(new Runnable() { 814 @Override 815 public void run() { 816 mCameraHandler.obtainMessage(CameraActions.SET_ERROR_CALLBACK, 817 ErrorCallbackForward.getNewInstance( 818 handler, AndroidCameraProxyImpl.this, cb)) 819 .sendToTarget(); 820 } 821 }); 822 } 823 824 @Override 825 public void setParameters(final Parameters params) { 826 if (params == null) { 827 Log.v(TAG, "null parameters in setParameters()"); 828 return; 829 } 830 final String flattenedParameters = params.flatten(); 831 mDispatchThread.runJob(new Runnable() { 832 @Override 833 public void run() { 834 mCameraState.waitForStates(AndroidCameraStateHolder.CAMERA_IDLE | 835 AndroidCameraStateHolder.CAMERA_UNLOCKED); 836 mCameraHandler.obtainMessage(CameraActions.SET_PARAMETERS, flattenedParameters) 837 .sendToTarget(); 838 } 839 }); 840 } 841 842 @Override 843 public Parameters getParameters() { 844 final WaitDoneBundle bundle = new WaitDoneBundle(); 845 mDispatchThread.runJobSync(new Runnable() { 846 @Override 847 public void run() { 848 mCameraHandler.sendEmptyMessage(CameraActions.GET_PARAMETERS); 849 mCameraHandler.post(bundle.mUnlockRunnable); 850 } 851 }, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "get parameters"); 852 return mParameters; 853 } 854 855 @Override 856 public CameraSettings getSettings() { 857 return new AndroidCameraSettings(mCapabilities, getParameters()); 858 } 859 860 @Override 861 public boolean applySettings(CameraSettings settings) { 862 return applySettingsHelper(settings, AndroidCameraStateHolder.CAMERA_IDLE | 863 AndroidCameraStateHolder.CAMERA_UNLOCKED); 864 } 865 866 @Override 867 public String dumpDeviceSettings() { 868 String flattened = mParameters.flatten(); 869 StringTokenizer tokenizer = new StringTokenizer(flattened, ";"); 870 String dumpedSettings = new String(); 871 while (tokenizer.hasMoreElements()) { 872 dumpedSettings += tokenizer.nextToken() + '\n'; 873 } 874 875 return dumpedSettings; 876 } 877 878 @Override 879 public Handler getCameraHandler() { 880 return AndroidCameraAgentImpl.this.getCameraHandler(); 881 } 882 883 @Override 884 public DispatchThread getDispatchThread() { 885 return AndroidCameraAgentImpl.this.getDispatchThread(); 886 } 887 888 @Override 889 public CameraStateHolder getCameraState() { 890 return mCameraState; 891 } 892 } 893 894 private static class AndroidCameraStateHolder extends CameraStateHolder { 895 /* Camera states */ 896 // These states are defined bitwise so we can easily to specify a set of 897 // states together. 898 public static final int CAMERA_UNOPENED = 1; 899 public static final int CAMERA_IDLE = 1 << 1; 900 public static final int CAMERA_UNLOCKED = 1 << 2; 901 public static final int CAMERA_CAPTURING = 1 << 3; 902 public static final int CAMERA_FOCUSING = 1 << 4; 903 904 public AndroidCameraStateHolder() { 905 this(CAMERA_UNOPENED); 906 } 907 908 public AndroidCameraStateHolder(int state) { 909 super(state); 910 } 911 } 912 913 /** 914 * A helper class to forward AutoFocusCallback to another thread. 915 */ 916 private static class AFCallbackForward implements AutoFocusCallback { 917 private final Handler mHandler; 918 private final CameraProxy mCamera; 919 private final CameraAFCallback mCallback; 920 921 /** 922 * Returns a new instance of {@link AFCallbackForward}. 923 * 924 * @param handler The handler in which the callback will be invoked in. 925 * @param camera The {@link CameraProxy} which the callback is from. 926 * @param cb The callback to be invoked. 927 * @return The instance of the {@link AFCallbackForward}, 928 * or null if any parameter is null. 929 */ 930 public static AFCallbackForward getNewInstance( 931 Handler handler, CameraProxy camera, CameraAFCallback cb) { 932 if (handler == null || camera == null || cb == null) { 933 return null; 934 } 935 return new AFCallbackForward(handler, camera, cb); 936 } 937 938 private AFCallbackForward( 939 Handler h, CameraProxy camera, CameraAFCallback cb) { 940 mHandler = h; 941 mCamera = camera; 942 mCallback = cb; 943 } 944 945 @Override 946 public void onAutoFocus(final boolean b, Camera camera) { 947 mHandler.post(new Runnable() { 948 @Override 949 public void run() { 950 mCallback.onAutoFocus(b, mCamera); 951 } 952 }); 953 } 954 } 955 956 /** 957 * A helper class to forward ErrorCallback to another thread. 958 */ 959 private static class ErrorCallbackForward implements Camera.ErrorCallback { 960 private final Handler mHandler; 961 private final CameraProxy mCamera; 962 private final CameraErrorCallback mCallback; 963 964 /** 965 * Returns a new instance of {@link AFCallbackForward}. 966 * 967 * @param handler The handler in which the callback will be invoked in. 968 * @param camera The {@link CameraProxy} which the callback is from. 969 * @param cb The callback to be invoked. 970 * @return The instance of the {@link AFCallbackForward}, 971 * or null if any parameter is null. 972 */ 973 public static ErrorCallbackForward getNewInstance( 974 Handler handler, CameraProxy camera, CameraErrorCallback cb) { 975 if (handler == null || camera == null || cb == null) { 976 return null; 977 } 978 return new ErrorCallbackForward(handler, camera, cb); 979 } 980 981 private ErrorCallbackForward( 982 Handler h, CameraProxy camera, CameraErrorCallback cb) { 983 mHandler = h; 984 mCamera = camera; 985 mCallback = cb; 986 } 987 988 @Override 989 public void onError(final int error, Camera camera) { 990 mHandler.post(new Runnable() { 991 @Override 992 public void run() { 993 mCallback.onError(error, mCamera); 994 } 995 }); 996 } 997 } 998 999 /** A helper class to forward AutoFocusMoveCallback to another thread. */ 1000 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 1001 private static class AFMoveCallbackForward implements AutoFocusMoveCallback { 1002 private final Handler mHandler; 1003 private final CameraAFMoveCallback mCallback; 1004 private final CameraProxy mCamera; 1005 1006 /** 1007 * Returns a new instance of {@link AFMoveCallbackForward}. 1008 * 1009 * @param handler The handler in which the callback will be invoked in. 1010 * @param camera The {@link CameraProxy} which the callback is from. 1011 * @param cb The callback to be invoked. 1012 * @return The instance of the {@link AFMoveCallbackForward}, 1013 * or null if any parameter is null. 1014 */ 1015 public static AFMoveCallbackForward getNewInstance( 1016 Handler handler, CameraProxy camera, CameraAFMoveCallback cb) { 1017 if (handler == null || camera == null || cb == null) { 1018 return null; 1019 } 1020 return new AFMoveCallbackForward(handler, camera, cb); 1021 } 1022 1023 private AFMoveCallbackForward( 1024 Handler h, CameraProxy camera, CameraAFMoveCallback cb) { 1025 mHandler = h; 1026 mCamera = camera; 1027 mCallback = cb; 1028 } 1029 1030 @Override 1031 public void onAutoFocusMoving( 1032 final boolean moving, android.hardware.Camera camera) { 1033 mHandler.post(new Runnable() { 1034 @Override 1035 public void run() { 1036 mCallback.onAutoFocusMoving(moving, mCamera); 1037 } 1038 }); 1039 } 1040 } 1041 1042 /** 1043 * A helper class to forward ShutterCallback to to another thread. 1044 */ 1045 private static class ShutterCallbackForward implements ShutterCallback { 1046 private final Handler mHandler; 1047 private final CameraShutterCallback mCallback; 1048 private final CameraProxy mCamera; 1049 1050 /** 1051 * Returns a new instance of {@link ShutterCallbackForward}. 1052 * 1053 * @param handler The handler in which the callback will be invoked in. 1054 * @param camera The {@link CameraProxy} which the callback is from. 1055 * @param cb The callback to be invoked. 1056 * @return The instance of the {@link ShutterCallbackForward}, 1057 * or null if any parameter is null. 1058 */ 1059 public static ShutterCallbackForward getNewInstance( 1060 Handler handler, CameraProxy camera, CameraShutterCallback cb) { 1061 if (handler == null || camera == null || cb == null) { 1062 return null; 1063 } 1064 return new ShutterCallbackForward(handler, camera, cb); 1065 } 1066 1067 private ShutterCallbackForward( 1068 Handler h, CameraProxy camera, CameraShutterCallback cb) { 1069 mHandler = h; 1070 mCamera = camera; 1071 mCallback = cb; 1072 } 1073 1074 @Override 1075 public void onShutter() { 1076 mHandler.post(new Runnable() { 1077 @Override 1078 public void run() { 1079 mCallback.onShutter(mCamera); 1080 } 1081 }); 1082 } 1083 } 1084 1085 /** 1086 * A helper class to forward PictureCallback to another thread. 1087 */ 1088 private static class PictureCallbackForward implements PictureCallback { 1089 private final Handler mHandler; 1090 private final CameraPictureCallback mCallback; 1091 private final CameraProxy mCamera; 1092 1093 /** 1094 * Returns a new instance of {@link PictureCallbackForward}. 1095 * 1096 * @param handler The handler in which the callback will be invoked in. 1097 * @param camera The {@link CameraProxy} which the callback is from. 1098 * @param cb The callback to be invoked. 1099 * @return The instance of the {@link PictureCallbackForward}, 1100 * or null if any parameters is null. 1101 */ 1102 public static PictureCallbackForward getNewInstance( 1103 Handler handler, CameraProxy camera, CameraPictureCallback cb) { 1104 if (handler == null || camera == null || cb == null) { 1105 return null; 1106 } 1107 return new PictureCallbackForward(handler, camera, cb); 1108 } 1109 1110 private PictureCallbackForward( 1111 Handler h, CameraProxy camera, CameraPictureCallback cb) { 1112 mHandler = h; 1113 mCamera = camera; 1114 mCallback = cb; 1115 } 1116 1117 @Override 1118 public void onPictureTaken( 1119 final byte[] data, android.hardware.Camera camera) { 1120 mHandler.post(new Runnable() { 1121 @Override 1122 public void run() { 1123 mCallback.onPictureTaken(data, mCamera); 1124 } 1125 }); 1126 } 1127 } 1128 1129 /** 1130 * A helper class to forward PreviewCallback to another thread. 1131 */ 1132 private static class PreviewCallbackForward implements PreviewCallback { 1133 private final Handler mHandler; 1134 private final CameraPreviewDataCallback mCallback; 1135 private final CameraProxy mCamera; 1136 1137 /** 1138 * Returns a new instance of {@link PreviewCallbackForward}. 1139 * 1140 * @param handler The handler in which the callback will be invoked in. 1141 * @param camera The {@link CameraProxy} which the callback is from. 1142 * @param cb The callback to be invoked. 1143 * @return The instance of the {@link PreviewCallbackForward}, 1144 * or null if any parameters is null. 1145 */ 1146 public static PreviewCallbackForward getNewInstance( 1147 Handler handler, CameraProxy camera, CameraPreviewDataCallback cb) { 1148 if (handler == null || camera == null || cb == null) { 1149 return null; 1150 } 1151 return new PreviewCallbackForward(handler, camera, cb); 1152 } 1153 1154 private PreviewCallbackForward( 1155 Handler h, CameraProxy camera, CameraPreviewDataCallback cb) { 1156 mHandler = h; 1157 mCamera = camera; 1158 mCallback = cb; 1159 } 1160 1161 @Override 1162 public void onPreviewFrame( 1163 final byte[] data, android.hardware.Camera camera) { 1164 mHandler.post(new Runnable() { 1165 @Override 1166 public void run() { 1167 mCallback.onPreviewFrame(data, mCamera); 1168 } 1169 }); 1170 } 1171 } 1172 1173 private static class FaceDetectionCallbackForward implements FaceDetectionListener { 1174 private final Handler mHandler; 1175 private final CameraFaceDetectionCallback mCallback; 1176 private final CameraProxy mCamera; 1177 1178 /** 1179 * Returns a new instance of {@link FaceDetectionCallbackForward}. 1180 * 1181 * @param handler The handler in which the callback will be invoked in. 1182 * @param camera The {@link CameraProxy} which the callback is from. 1183 * @param cb The callback to be invoked. 1184 * @return The instance of the {@link FaceDetectionCallbackForward}, 1185 * or null if any parameter is null. 1186 */ 1187 public static FaceDetectionCallbackForward getNewInstance( 1188 Handler handler, CameraProxy camera, CameraFaceDetectionCallback cb) { 1189 if (handler == null || camera == null || cb == null) { 1190 return null; 1191 } 1192 return new FaceDetectionCallbackForward(handler, camera, cb); 1193 } 1194 1195 private FaceDetectionCallbackForward( 1196 Handler h, CameraProxy camera, CameraFaceDetectionCallback cb) { 1197 mHandler = h; 1198 mCamera = camera; 1199 mCallback = cb; 1200 } 1201 1202 @Override 1203 public void onFaceDetection( 1204 final Camera.Face[] faces, Camera camera) { 1205 mHandler.post(new Runnable() { 1206 @Override 1207 public void run() { 1208 mCallback.onFaceDetection(faces, mCamera); 1209 } 1210 }); 1211 } 1212 } 1213} 1214