AndroidCameraAgentImpl.java revision a0842b40441db5332a5290f941021636b1182761
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 mCamera = android.hardware.Camera.open(cameraId); 308 if (mCamera != null) { 309 mCameraId = cameraId; 310 mParametersIsDirty = true; 311 312 // Get an instance of Camera.Parameters for later use. 313 mParamsToSet = mCamera.getParameters(); 314 mCharacteristics = 315 AndroidCameraDeviceInfo.create().getCharacteristics(cameraId); 316 mCapabilities = new AndroidCameraCapabilities(mParamsToSet); 317 318 mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE); 319 if (openCallback != null) { 320 openCallback.onCameraOpened( 321 new AndroidCameraProxyImpl(cameraId, mCamera, 322 mCharacteristics, mCapabilities)); 323 } 324 } else { 325 if (openCallback != null) { 326 openCallback.onDeviceOpenFailure(cameraId, generateHistoryString(cameraId)); 327 } 328 } 329 break; 330 } 331 332 case CameraActions.RELEASE: { 333 if (mCamera != null) { 334 mCamera.release(); 335 mCameraState.setState(AndroidCameraStateHolder.CAMERA_UNOPENED); 336 mCamera = null; 337 } else { 338 Log.w(TAG, "Releasing camera without any camera opened."); 339 } 340 break; 341 } 342 343 case CameraActions.RECONNECT: { 344 final CameraOpenCallbackForward cbForward = 345 (CameraOpenCallbackForward) msg.obj; 346 final int cameraId = msg.arg1; 347 try { 348 mCamera.reconnect(); 349 } catch (IOException ex) { 350 if (cbForward != null) { 351 cbForward.onReconnectionFailure(AndroidCameraAgentImpl.this, 352 generateHistoryString(mCameraId)); 353 } 354 break; 355 } 356 357 mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE); 358 if (cbForward != null) { 359 cbForward.onCameraOpened( 360 new AndroidCameraProxyImpl(cameraId, mCamera, mCharacteristics, 361 mCapabilities)); 362 } 363 break; 364 } 365 366 case CameraActions.UNLOCK: { 367 mCamera.unlock(); 368 mCameraState.setState(AndroidCameraStateHolder.CAMERA_UNLOCKED); 369 break; 370 } 371 372 case CameraActions.LOCK: { 373 mCamera.lock(); 374 mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE); 375 break; 376 } 377 378 case CameraActions.SET_PREVIEW_TEXTURE_ASYNC: { 379 setPreviewTexture(msg.obj); 380 break; 381 } 382 383 case CameraActions.SET_PREVIEW_DISPLAY_ASYNC: { 384 try { 385 mCamera.setPreviewDisplay((SurfaceHolder) msg.obj); 386 } catch (IOException e) { 387 throw new RuntimeException(e); 388 } 389 break; 390 } 391 392 case CameraActions.START_PREVIEW_ASYNC: { 393 final CameraStartPreviewCallbackForward cbForward = 394 (CameraStartPreviewCallbackForward) msg.obj; 395 mCamera.startPreview(); 396 if (cbForward != null) { 397 cbForward.onPreviewStarted(); 398 } 399 break; 400 } 401 402 case CameraActions.STOP_PREVIEW: { 403 mCamera.stopPreview(); 404 break; 405 } 406 407 case CameraActions.SET_PREVIEW_CALLBACK_WITH_BUFFER: { 408 mCamera.setPreviewCallbackWithBuffer((PreviewCallback) msg.obj); 409 break; 410 } 411 412 case CameraActions.SET_ONE_SHOT_PREVIEW_CALLBACK: { 413 mCamera.setOneShotPreviewCallback((PreviewCallback) msg.obj); 414 break; 415 } 416 417 case CameraActions.ADD_CALLBACK_BUFFER: { 418 mCamera.addCallbackBuffer((byte[]) msg.obj); 419 break; 420 } 421 422 case CameraActions.AUTO_FOCUS: { 423 mCameraState.setState(AndroidCameraStateHolder.CAMERA_FOCUSING); 424 mCamera.autoFocus((AutoFocusCallback) msg.obj); 425 break; 426 } 427 428 case CameraActions.CANCEL_AUTO_FOCUS: { 429 mCamera.cancelAutoFocus(); 430 mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE); 431 break; 432 } 433 434 case CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK: { 435 setAutoFocusMoveCallback(mCamera, msg.obj); 436 break; 437 } 438 439 case CameraActions.SET_DISPLAY_ORIENTATION: { 440 mCamera.setDisplayOrientation(msg.arg1); 441 break; 442 } 443 444 case CameraActions.SET_ZOOM_CHANGE_LISTENER: { 445 mCamera.setZoomChangeListener((OnZoomChangeListener) msg.obj); 446 break; 447 } 448 449 case CameraActions.SET_FACE_DETECTION_LISTENER: { 450 setFaceDetectionListener((FaceDetectionListener) msg.obj); 451 break; 452 } 453 454 case CameraActions.START_FACE_DETECTION: { 455 startFaceDetection(); 456 break; 457 } 458 459 case CameraActions.STOP_FACE_DETECTION: { 460 stopFaceDetection(); 461 break; 462 } 463 464 case CameraActions.SET_ERROR_CALLBACK: { 465 mCamera.setErrorCallback((ErrorCallback) msg.obj); 466 break; 467 } 468 469 case CameraActions.APPLY_SETTINGS: { 470 mParametersIsDirty = true; 471 CameraSettings settings = (CameraSettings) msg.obj; 472 applyToParameters(settings); 473 mCamera.setParameters(mParamsToSet); 474 break; 475 } 476 477 case CameraActions.SET_PARAMETERS: { 478 mParametersIsDirty = true; 479 mParamsToSet.unflatten((String) msg.obj); 480 mCamera.setParameters(mParamsToSet); 481 break; 482 } 483 484 case CameraActions.GET_PARAMETERS: { 485 if (mParametersIsDirty) { 486 mParameters = mCamera.getParameters(); 487 mParametersIsDirty = false; 488 } 489 break; 490 } 491 492 case CameraActions.SET_PREVIEW_CALLBACK: { 493 mCamera.setPreviewCallback((PreviewCallback) msg.obj); 494 break; 495 } 496 497 case CameraActions.ENABLE_SHUTTER_SOUND: { 498 enableShutterSound((msg.arg1 == 1) ? true : false); 499 break; 500 } 501 502 case CameraActions.REFRESH_PARAMETERS: { 503 mParametersIsDirty = true; 504 break; 505 } 506 507 case CameraActions.CAPTURE_PHOTO: { 508 mCameraState.setState(AndroidCameraStateHolder.CAMERA_CAPTURING); 509 capture((CaptureCallbacks) msg.obj); 510 break; 511 } 512 513 default: { 514 throw new RuntimeException("Invalid CameraProxy message=" + msg.what); 515 } 516 } 517 } catch (final RuntimeException e) { 518 if (msg.what != CameraActions.RELEASE && mCamera != null) { 519 try { 520 mCamera.release(); 521 mCameraState.setState(AndroidCameraStateHolder.CAMERA_UNOPENED); 522 } catch (Exception ex) { 523 Log.e(TAG, "Fail to release the camera."); 524 } 525 mCamera = null; 526 } else { 527 if (mCamera == null) { 528 if (msg.what == CameraActions.OPEN_CAMERA) { 529 final int cameraId = msg.arg1; 530 if (msg.obj != null) { 531 ((CameraOpenCallback) msg.obj).onDeviceOpenFailure( 532 msg.arg1, generateHistoryString(cameraId)); 533 } 534 } else { 535 Log.w(TAG, "Cannot handle message " + msg.what + ", mCamera is null."); 536 } 537 return; 538 } 539 } 540 synchronized (mCameraExceptionCallback) { 541 mCameraExceptionCallbackHandler.post(new Runnable() { 542 @Override 543 public void run() { 544 mCameraExceptionCallback.onCameraException(e); 545 } 546 }); 547 } 548 } 549 } 550 551 private void applyToParameters(final CameraSettings settings) { 552 final CameraCapabilities.Stringifier stringifier = mCapabilities.getStringifier(); 553 Size photoSize = settings.getCurrentPhotoSize(); 554 mParamsToSet.setPictureSize(photoSize.width(), photoSize.height()); 555 Size previewSize = settings.getCurrentPreviewSize(); 556 mParamsToSet.setPreviewSize(previewSize.width(), previewSize.height()); 557 if (settings.getPreviewFrameRate() == -1) { 558 mParamsToSet.setPreviewFpsRange(settings.getPreviewFpsRangeMin(), 559 settings.getPreviewFpsRangeMax()); 560 } else { 561 mParamsToSet.setPreviewFrameRate(settings.getPreviewFrameRate()); 562 } 563 mParamsToSet.setPreviewFormat(settings.getCurrentPreviewFormat()); 564 mParamsToSet.setJpegQuality(settings.getPhotoJpegCompressionQuality()); 565 if (mCapabilities.supports(CameraCapabilities.Feature.ZOOM)) { 566 // Should use settings.getCurrentZoomRatio() instead here. 567 mParamsToSet.setZoom(settings.getCurrentZoomIndex()); 568 } 569 mParamsToSet.setRotation((int) settings.getCurrentPhotoRotationDegrees()); 570 mParamsToSet.setExposureCompensation(settings.getExposureCompensationIndex()); 571 if (mCapabilities.supports(CameraCapabilities.Feature.AUTO_EXPOSURE_LOCK)) { 572 mParamsToSet.setAutoExposureLock(settings.isAutoExposureLocked()); 573 } 574 mParamsToSet.setFocusMode(stringifier.stringify(settings.getCurrentFocusMode())); 575 if (mCapabilities.supports(CameraCapabilities.Feature.AUTO_WHITE_BALANCE_LOCK)) { 576 mParamsToSet.setAutoWhiteBalanceLock(settings.isAutoWhiteBalanceLocked()); 577 } 578 if (mCapabilities.supports(CameraCapabilities.Feature.FOCUS_AREA)) { 579 if (settings.getFocusAreas().size() != 0) { 580 mParamsToSet.setFocusAreas(settings.getFocusAreas()); 581 } 582 } 583 if (mCapabilities.supports(CameraCapabilities.Feature.METERING_AREA)) { 584 if (settings.getMeteringAreas().size() != 0) { 585 mParamsToSet.setMeteringAreas(settings.getMeteringAreas()); 586 } 587 } 588 if (settings.getCurrentFlashMode() != CameraCapabilities.FlashMode.NO_FLASH) { 589 mParamsToSet.setFlashMode(stringifier.stringify(settings.getCurrentFlashMode())); 590 } 591 if (settings.getCurrentSceneMode() != CameraCapabilities.SceneMode.NO_SCENE_MODE) { 592 if (settings.getCurrentSceneMode() != null) { 593 mParamsToSet 594 .setSceneMode(stringifier.stringify(settings.getCurrentSceneMode())); 595 } 596 } 597 mParamsToSet.setRecordingHint(settings.isRecordingHintEnabled()); 598 Size jpegThumbSize = settings.getExifThumbnailSize(); 599 mParamsToSet.setJpegThumbnailSize(jpegThumbSize.width(), jpegThumbSize.height()); 600 mParamsToSet.setPictureFormat(settings.getCurrentPhotoFormat()); 601 602 CameraSettings.GpsData gpsData = settings.getGpsData(); 603 if (gpsData == null) { 604 mParamsToSet.removeGpsData(); 605 } else { 606 mParamsToSet.setGpsTimestamp(gpsData.timeStamp); 607 if (gpsData.processingMethod != null) { 608 // It's a hack since we always use GPS time stamp but does 609 // not use other fields sometimes. Setting processing 610 // method to null means the other fields should not be used. 611 mParamsToSet.setGpsAltitude(gpsData.altitude); 612 mParamsToSet.setGpsLatitude(gpsData.latitude); 613 mParamsToSet.setGpsLongitude(gpsData.longitude); 614 mParamsToSet.setGpsProcessingMethod(gpsData.processingMethod); 615 } 616 } 617 618 } 619 } 620 621 /** 622 * A class which implements {@link CameraAgent.CameraProxy} and 623 * camera handler thread. 624 */ 625 private class AndroidCameraProxyImpl extends CameraAgent.CameraProxy { 626 private final int mCameraId; 627 /* TODO: remove this Camera instance. */ 628 private final Camera mCamera; 629 private final CameraDeviceInfo.Characteristics mCharacteristics; 630 private final AndroidCameraCapabilities mCapabilities; 631 632 private AndroidCameraProxyImpl(int cameraId, Camera camera, 633 CameraDeviceInfo.Characteristics characteristics, 634 AndroidCameraCapabilities capabilities) { 635 mCamera = camera; 636 mCameraId = cameraId; 637 mCharacteristics = characteristics; 638 mCapabilities = capabilities; 639 } 640 641 @Override 642 public android.hardware.Camera getCamera() { 643 return mCamera; 644 } 645 646 @Override 647 public int getCameraId() { 648 return mCameraId; 649 } 650 651 @Override 652 public CameraDeviceInfo.Characteristics getCharacteristics() { 653 return mCharacteristics; 654 } 655 656 @Override 657 public CameraCapabilities getCapabilities() { 658 return new AndroidCameraCapabilities(mCapabilities); 659 } 660 661 @Override 662 public void setPreviewDataCallback( 663 final Handler handler, final CameraPreviewDataCallback cb) { 664 mDispatchThread.runJob(new Runnable() { 665 @Override 666 public void run() { 667 mCameraHandler.obtainMessage(CameraActions.SET_PREVIEW_CALLBACK, 668 PreviewCallbackForward.getNewInstance( 669 handler, AndroidCameraProxyImpl.this, cb)) 670 .sendToTarget(); 671 } 672 }); 673 } 674 675 @Override 676 public void setOneShotPreviewCallback(final Handler handler, 677 final CameraPreviewDataCallback cb) { 678 mDispatchThread.runJob(new Runnable() { 679 @Override 680 public void run() { 681 mCameraHandler.obtainMessage(CameraActions.SET_ONE_SHOT_PREVIEW_CALLBACK, 682 PreviewCallbackForward 683 .getNewInstance(handler, AndroidCameraProxyImpl.this, cb)) 684 .sendToTarget(); 685 } 686 }); 687 } 688 689 @Override 690 public void setPreviewDataCallbackWithBuffer( 691 final Handler handler, final CameraPreviewDataCallback cb) { 692 mDispatchThread.runJob(new Runnable() { 693 @Override 694 public void run() { 695 mCameraHandler.obtainMessage(CameraActions.SET_PREVIEW_CALLBACK_WITH_BUFFER, 696 PreviewCallbackForward 697 .getNewInstance(handler, AndroidCameraProxyImpl.this, cb)) 698 .sendToTarget(); 699 } 700 }); 701 } 702 703 @Override 704 public void autoFocus(final Handler handler, final CameraAFCallback cb) { 705 final AutoFocusCallback afCallback = new AutoFocusCallback() { 706 @Override 707 public void onAutoFocus(final boolean b, Camera camera) { 708 if (mCameraState.getState() != AndroidCameraStateHolder.CAMERA_FOCUSING) { 709 Log.w(TAG, "onAutoFocus callback returning when not focusing"); 710 } else { 711 mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE); 712 } 713 handler.post(new Runnable() { 714 @Override 715 public void run() { 716 cb.onAutoFocus(b, AndroidCameraProxyImpl.this); 717 } 718 }); 719 } 720 }; 721 mDispatchThread.runJob(new Runnable() { 722 @Override 723 public void run() { 724 mCameraState.waitForStates(AndroidCameraStateHolder.CAMERA_IDLE); 725 mCameraHandler.obtainMessage(CameraActions.AUTO_FOCUS, afCallback) 726 .sendToTarget(); 727 } 728 }); 729 } 730 731 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 732 @Override 733 public void setAutoFocusMoveCallback( 734 final Handler handler, final CameraAFMoveCallback cb) { 735 mDispatchThread.runJob(new Runnable() { 736 @Override 737 public void run() { 738 mCameraHandler.obtainMessage(CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK, 739 AFMoveCallbackForward.getNewInstance( 740 handler, AndroidCameraProxyImpl.this, cb)) 741 .sendToTarget(); 742 } 743 }); 744 } 745 746 @Override 747 public void takePicture( 748 final Handler handler, final CameraShutterCallback shutter, 749 final CameraPictureCallback raw, final CameraPictureCallback post, 750 final CameraPictureCallback jpeg) { 751 final PictureCallback jpegCallback = new PictureCallback() { 752 @Override 753 public void onPictureTaken(final byte[] data, Camera camera) { 754 if (mCameraState.getState() != AndroidCameraStateHolder.CAMERA_CAPTURING) { 755 Log.w(TAG, "picture callback returning when not capturing"); 756 } else { 757 mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE); 758 } 759 handler.post(new Runnable() { 760 @Override 761 public void run() { 762 jpeg.onPictureTaken(data, AndroidCameraProxyImpl.this); 763 } 764 }); 765 } 766 }; 767 768 mDispatchThread.runJob(new Runnable() { 769 @Override 770 public void run() { 771 mCameraState.waitForStates(CameraStateHolder.CAMERA_IDLE | 772 AndroidCameraStateHolder.CAMERA_UNLOCKED); 773 mCameraHandler.requestTakePicture(ShutterCallbackForward 774 .getNewInstance(handler, AndroidCameraProxyImpl.this, shutter), 775 PictureCallbackForward 776 .getNewInstance(handler, AndroidCameraProxyImpl.this, raw), 777 PictureCallbackForward 778 .getNewInstance(handler, AndroidCameraProxyImpl.this, post), 779 jpegCallback 780 ); 781 } 782 }); 783 } 784 785 @Override 786 public void setZoomChangeListener(final OnZoomChangeListener listener) { 787 mDispatchThread.runJob(new Runnable() { 788 @Override 789 public void run() { 790 mCameraHandler.obtainMessage(CameraActions.SET_ZOOM_CHANGE_LISTENER, listener) 791 .sendToTarget(); 792 } 793 }); 794 } 795 796 @Override 797 public void setFaceDetectionCallback(final Handler handler, 798 final CameraFaceDetectionCallback cb) { 799 mDispatchThread.runJob(new Runnable() { 800 @Override 801 public void run() { 802 mCameraHandler.obtainMessage(CameraActions.SET_FACE_DETECTION_LISTENER, 803 FaceDetectionCallbackForward 804 .getNewInstance(handler, AndroidCameraProxyImpl.this, cb)) 805 .sendToTarget(); 806 } 807 }); 808 } 809 810 @Override 811 public void setErrorCallback(final Handler handler, final CameraErrorCallback cb) { 812 mDispatchThread.runJob(new Runnable() { 813 @Override 814 public void run() { 815 mCameraHandler.obtainMessage(CameraActions.SET_ERROR_CALLBACK, 816 ErrorCallbackForward.getNewInstance( 817 handler, AndroidCameraProxyImpl.this, cb)) 818 .sendToTarget(); 819 } 820 }); 821 } 822 823 @Override 824 public void setParameters(final Parameters params) { 825 if (params == null) { 826 Log.v(TAG, "null parameters in setParameters()"); 827 return; 828 } 829 final String flattenedParameters = params.flatten(); 830 mDispatchThread.runJob(new Runnable() { 831 @Override 832 public void run() { 833 mCameraState.waitForStates(AndroidCameraStateHolder.CAMERA_IDLE | 834 AndroidCameraStateHolder.CAMERA_UNLOCKED); 835 mCameraHandler.obtainMessage(CameraActions.SET_PARAMETERS, flattenedParameters) 836 .sendToTarget(); 837 } 838 }); 839 } 840 841 @Override 842 public Parameters getParameters() { 843 final WaitDoneBundle bundle = new WaitDoneBundle(); 844 mDispatchThread.runJobSync(new Runnable() { 845 @Override 846 public void run() { 847 mCameraHandler.sendEmptyMessage(CameraActions.GET_PARAMETERS); 848 mCameraHandler.post(bundle.mUnlockRunnable); 849 } 850 }, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "get parameters"); 851 return mParameters; 852 } 853 854 @Override 855 public CameraSettings getSettings() { 856 return new AndroidCameraSettings(mCapabilities, getParameters()); 857 } 858 859 @Override 860 public boolean applySettings(CameraSettings settings) { 861 return applySettingsHelper(settings, AndroidCameraStateHolder.CAMERA_IDLE | 862 AndroidCameraStateHolder.CAMERA_UNLOCKED); 863 } 864 865 @Override 866 public String dumpDeviceSettings() { 867 String flattened = mParameters.flatten(); 868 StringTokenizer tokenizer = new StringTokenizer(flattened, ";"); 869 String dumpedSettings = new String(); 870 while (tokenizer.hasMoreElements()) { 871 dumpedSettings += tokenizer.nextToken() + '\n'; 872 } 873 874 return dumpedSettings; 875 } 876 877 @Override 878 public Handler getCameraHandler() { 879 return AndroidCameraAgentImpl.this.getCameraHandler(); 880 } 881 882 @Override 883 public DispatchThread getDispatchThread() { 884 return AndroidCameraAgentImpl.this.getDispatchThread(); 885 } 886 887 @Override 888 public CameraStateHolder getCameraState() { 889 return mCameraState; 890 } 891 } 892 893 private static class AndroidCameraStateHolder extends CameraStateHolder { 894 /* Camera states */ 895 // These states are defined bitwise so we can easily to specify a set of 896 // states together. 897 public static final int CAMERA_UNOPENED = 1; 898 public static final int CAMERA_IDLE = 1 << 1; 899 public static final int CAMERA_UNLOCKED = 1 << 2; 900 public static final int CAMERA_CAPTURING = 1 << 3; 901 public static final int CAMERA_FOCUSING = 1 << 4; 902 903 private int mState; 904 905 public AndroidCameraStateHolder() { 906 this(CAMERA_UNOPENED); 907 } 908 909 public AndroidCameraStateHolder(int state) { 910 setState(state); 911 } 912 913 @Override 914 public synchronized void setState(int state) { 915 mState = state; 916 this.notifyAll(); 917 } 918 919 @Override 920 public synchronized int getState() { 921 return mState; 922 } 923 } 924 925 /** 926 * A helper class to forward AutoFocusCallback to another thread. 927 */ 928 private static class AFCallbackForward implements AutoFocusCallback { 929 private final Handler mHandler; 930 private final CameraProxy mCamera; 931 private final CameraAFCallback mCallback; 932 933 /** 934 * Returns a new instance of {@link AFCallbackForward}. 935 * 936 * @param handler The handler in which the callback will be invoked in. 937 * @param camera The {@link CameraProxy} which the callback is from. 938 * @param cb The callback to be invoked. 939 * @return The instance of the {@link AFCallbackForward}, 940 * or null if any parameter is null. 941 */ 942 public static AFCallbackForward getNewInstance( 943 Handler handler, CameraProxy camera, CameraAFCallback cb) { 944 if (handler == null || camera == null || cb == null) { 945 return null; 946 } 947 return new AFCallbackForward(handler, camera, cb); 948 } 949 950 private AFCallbackForward( 951 Handler h, CameraProxy camera, CameraAFCallback cb) { 952 mHandler = h; 953 mCamera = camera; 954 mCallback = cb; 955 } 956 957 @Override 958 public void onAutoFocus(final boolean b, Camera camera) { 959 mHandler.post(new Runnable() { 960 @Override 961 public void run() { 962 mCallback.onAutoFocus(b, mCamera); 963 } 964 }); 965 } 966 } 967 968 /** 969 * A helper class to forward ErrorCallback to another thread. 970 */ 971 private static class ErrorCallbackForward implements Camera.ErrorCallback { 972 private final Handler mHandler; 973 private final CameraProxy mCamera; 974 private final CameraErrorCallback mCallback; 975 976 /** 977 * Returns a new instance of {@link AFCallbackForward}. 978 * 979 * @param handler The handler in which the callback will be invoked in. 980 * @param camera The {@link CameraProxy} which the callback is from. 981 * @param cb The callback to be invoked. 982 * @return The instance of the {@link AFCallbackForward}, 983 * or null if any parameter is null. 984 */ 985 public static ErrorCallbackForward getNewInstance( 986 Handler handler, CameraProxy camera, CameraErrorCallback cb) { 987 if (handler == null || camera == null || cb == null) { 988 return null; 989 } 990 return new ErrorCallbackForward(handler, camera, cb); 991 } 992 993 private ErrorCallbackForward( 994 Handler h, CameraProxy camera, CameraErrorCallback cb) { 995 mHandler = h; 996 mCamera = camera; 997 mCallback = cb; 998 } 999 1000 @Override 1001 public void onError(final int error, Camera camera) { 1002 mHandler.post(new Runnable() { 1003 @Override 1004 public void run() { 1005 mCallback.onError(error, mCamera); 1006 } 1007 }); 1008 } 1009 } 1010 1011 /** A helper class to forward AutoFocusMoveCallback to another thread. */ 1012 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 1013 private static class AFMoveCallbackForward implements AutoFocusMoveCallback { 1014 private final Handler mHandler; 1015 private final CameraAFMoveCallback mCallback; 1016 private final CameraProxy mCamera; 1017 1018 /** 1019 * Returns a new instance of {@link AFMoveCallbackForward}. 1020 * 1021 * @param handler The handler in which the callback will be invoked in. 1022 * @param camera The {@link CameraProxy} which the callback is from. 1023 * @param cb The callback to be invoked. 1024 * @return The instance of the {@link AFMoveCallbackForward}, 1025 * or null if any parameter is null. 1026 */ 1027 public static AFMoveCallbackForward getNewInstance( 1028 Handler handler, CameraProxy camera, CameraAFMoveCallback cb) { 1029 if (handler == null || camera == null || cb == null) { 1030 return null; 1031 } 1032 return new AFMoveCallbackForward(handler, camera, cb); 1033 } 1034 1035 private AFMoveCallbackForward( 1036 Handler h, CameraProxy camera, CameraAFMoveCallback cb) { 1037 mHandler = h; 1038 mCamera = camera; 1039 mCallback = cb; 1040 } 1041 1042 @Override 1043 public void onAutoFocusMoving( 1044 final boolean moving, android.hardware.Camera camera) { 1045 mHandler.post(new Runnable() { 1046 @Override 1047 public void run() { 1048 mCallback.onAutoFocusMoving(moving, mCamera); 1049 } 1050 }); 1051 } 1052 } 1053 1054 /** 1055 * A helper class to forward ShutterCallback to to another thread. 1056 */ 1057 private static class ShutterCallbackForward implements ShutterCallback { 1058 private final Handler mHandler; 1059 private final CameraShutterCallback mCallback; 1060 private final CameraProxy mCamera; 1061 1062 /** 1063 * Returns a new instance of {@link ShutterCallbackForward}. 1064 * 1065 * @param handler The handler in which the callback will be invoked in. 1066 * @param camera The {@link CameraProxy} which the callback is from. 1067 * @param cb The callback to be invoked. 1068 * @return The instance of the {@link ShutterCallbackForward}, 1069 * or null if any parameter is null. 1070 */ 1071 public static ShutterCallbackForward getNewInstance( 1072 Handler handler, CameraProxy camera, CameraShutterCallback cb) { 1073 if (handler == null || camera == null || cb == null) { 1074 return null; 1075 } 1076 return new ShutterCallbackForward(handler, camera, cb); 1077 } 1078 1079 private ShutterCallbackForward( 1080 Handler h, CameraProxy camera, CameraShutterCallback cb) { 1081 mHandler = h; 1082 mCamera = camera; 1083 mCallback = cb; 1084 } 1085 1086 @Override 1087 public void onShutter() { 1088 mHandler.post(new Runnable() { 1089 @Override 1090 public void run() { 1091 mCallback.onShutter(mCamera); 1092 } 1093 }); 1094 } 1095 } 1096 1097 /** 1098 * A helper class to forward PictureCallback to another thread. 1099 */ 1100 private static class PictureCallbackForward implements PictureCallback { 1101 private final Handler mHandler; 1102 private final CameraPictureCallback mCallback; 1103 private final CameraProxy mCamera; 1104 1105 /** 1106 * Returns a new instance of {@link PictureCallbackForward}. 1107 * 1108 * @param handler The handler in which the callback will be invoked in. 1109 * @param camera The {@link CameraProxy} which the callback is from. 1110 * @param cb The callback to be invoked. 1111 * @return The instance of the {@link PictureCallbackForward}, 1112 * or null if any parameters is null. 1113 */ 1114 public static PictureCallbackForward getNewInstance( 1115 Handler handler, CameraProxy camera, CameraPictureCallback cb) { 1116 if (handler == null || camera == null || cb == null) { 1117 return null; 1118 } 1119 return new PictureCallbackForward(handler, camera, cb); 1120 } 1121 1122 private PictureCallbackForward( 1123 Handler h, CameraProxy camera, CameraPictureCallback cb) { 1124 mHandler = h; 1125 mCamera = camera; 1126 mCallback = cb; 1127 } 1128 1129 @Override 1130 public void onPictureTaken( 1131 final byte[] data, android.hardware.Camera camera) { 1132 mHandler.post(new Runnable() { 1133 @Override 1134 public void run() { 1135 mCallback.onPictureTaken(data, mCamera); 1136 } 1137 }); 1138 } 1139 } 1140 1141 /** 1142 * A helper class to forward PreviewCallback to another thread. 1143 */ 1144 private static class PreviewCallbackForward implements PreviewCallback { 1145 private final Handler mHandler; 1146 private final CameraPreviewDataCallback mCallback; 1147 private final CameraProxy mCamera; 1148 1149 /** 1150 * Returns a new instance of {@link PreviewCallbackForward}. 1151 * 1152 * @param handler The handler in which the callback will be invoked in. 1153 * @param camera The {@link CameraProxy} which the callback is from. 1154 * @param cb The callback to be invoked. 1155 * @return The instance of the {@link PreviewCallbackForward}, 1156 * or null if any parameters is null. 1157 */ 1158 public static PreviewCallbackForward getNewInstance( 1159 Handler handler, CameraProxy camera, CameraPreviewDataCallback cb) { 1160 if (handler == null || camera == null || cb == null) { 1161 return null; 1162 } 1163 return new PreviewCallbackForward(handler, camera, cb); 1164 } 1165 1166 private PreviewCallbackForward( 1167 Handler h, CameraProxy camera, CameraPreviewDataCallback cb) { 1168 mHandler = h; 1169 mCamera = camera; 1170 mCallback = cb; 1171 } 1172 1173 @Override 1174 public void onPreviewFrame( 1175 final byte[] data, android.hardware.Camera camera) { 1176 mHandler.post(new Runnable() { 1177 @Override 1178 public void run() { 1179 mCallback.onPreviewFrame(data, mCamera); 1180 } 1181 }); 1182 } 1183 } 1184 1185 private static class FaceDetectionCallbackForward implements FaceDetectionListener { 1186 private final Handler mHandler; 1187 private final CameraFaceDetectionCallback mCallback; 1188 private final CameraProxy mCamera; 1189 1190 /** 1191 * Returns a new instance of {@link FaceDetectionCallbackForward}. 1192 * 1193 * @param handler The handler in which the callback will be invoked in. 1194 * @param camera The {@link CameraProxy} which the callback is from. 1195 * @param cb The callback to be invoked. 1196 * @return The instance of the {@link FaceDetectionCallbackForward}, 1197 * or null if any parameter is null. 1198 */ 1199 public static FaceDetectionCallbackForward getNewInstance( 1200 Handler handler, CameraProxy camera, CameraFaceDetectionCallback cb) { 1201 if (handler == null || camera == null || cb == null) { 1202 return null; 1203 } 1204 return new FaceDetectionCallbackForward(handler, camera, cb); 1205 } 1206 1207 private FaceDetectionCallbackForward( 1208 Handler h, CameraProxy camera, CameraFaceDetectionCallback cb) { 1209 mHandler = h; 1210 mCamera = camera; 1211 mCallback = cb; 1212 } 1213 1214 @Override 1215 public void onFaceDetection( 1216 final Camera.Face[] faces, Camera camera) { 1217 mHandler.post(new Runnable() { 1218 @Override 1219 public void run() { 1220 mCallback.onFaceDetection(faces, mCamera); 1221 } 1222 }); 1223 } 1224 } 1225} 1226