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