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