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