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