AndroidCameraAgentImpl.java revision 2569329d6cff25bfe9941df539df14a0aeb4c4f4
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 // TODO: Lock the CameraSettings object's sizes 404 case CameraActions.SET_PREVIEW_TEXTURE_ASYNC: { 405 setPreviewTexture(msg.obj); 406 break; 407 } 408 409 case CameraActions.SET_PREVIEW_DISPLAY_ASYNC: { 410 try { 411 mCamera.setPreviewDisplay((SurfaceHolder) msg.obj); 412 } catch (IOException e) { 413 throw new RuntimeException(e); 414 } 415 break; 416 } 417 418 case CameraActions.START_PREVIEW_ASYNC: { 419 final CameraStartPreviewCallbackForward cbForward = 420 (CameraStartPreviewCallbackForward) msg.obj; 421 mCamera.startPreview(); 422 if (cbForward != null) { 423 cbForward.onPreviewStarted(); 424 } 425 break; 426 } 427 428 // TODO: Unlock the CameraSettings object's sizes 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 parameters.setZoom(zoomRatioToIndex(settings.getCurrentZoomRatio(), 604 parameters.getZoomRatios())); 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 * @param ratio Desired zoom ratio, in [1.0f,+Inf). 658 * @param percentages Available zoom ratios, as percentages. 659 * @return Index of the closest corresponding ratio, rounded up toward 660 * that of the maximum available ratio. 661 */ 662 private int zoomRatioToIndex(float ratio, List<Integer> percentages) { 663 int percent = (int) (ratio * AndroidCameraCapabilities.ZOOM_MULTIPLIER); 664 int index = Collections.binarySearch(percentages, percent); 665 if (index >= 0) { 666 // Found the desired ratio in the supported list 667 return index; 668 } else { 669 // Didn't find an exact match. Where would it have been? 670 index = -(index + 1); 671 if (index == percentages.size()) { 672 // Put it back in bounds by setting to the maximum allowable zoom 673 --index; 674 } 675 return index; 676 } 677 } 678 } 679 680 /** 681 * A class which implements {@link CameraAgent.CameraProxy} and 682 * camera handler thread. 683 */ 684 private class AndroidCameraProxyImpl extends CameraAgent.CameraProxy { 685 private final int mCameraId; 686 /* TODO: remove this Camera instance. */ 687 private final Camera mCamera; 688 private final CameraDeviceInfo.Characteristics mCharacteristics; 689 private final AndroidCameraCapabilities mCapabilities; 690 691 private AndroidCameraProxyImpl(int cameraId, Camera camera, 692 CameraDeviceInfo.Characteristics characteristics, 693 AndroidCameraCapabilities capabilities) { 694 mCamera = camera; 695 mCameraId = cameraId; 696 mCharacteristics = characteristics; 697 mCapabilities = capabilities; 698 } 699 700 @Deprecated 701 @Override 702 public android.hardware.Camera getCamera() { 703 return mCamera; 704 } 705 706 @Override 707 public int getCameraId() { 708 return mCameraId; 709 } 710 711 @Override 712 public CameraDeviceInfo.Characteristics getCharacteristics() { 713 return mCharacteristics; 714 } 715 716 @Override 717 public CameraCapabilities getCapabilities() { 718 return new AndroidCameraCapabilities(mCapabilities); 719 } 720 721 @Override 722 public void setPreviewDataCallback( 723 final Handler handler, final CameraPreviewDataCallback cb) { 724 mDispatchThread.runJob(new Runnable() { 725 @Override 726 public void run() { 727 mCameraHandler.obtainMessage(CameraActions.SET_PREVIEW_CALLBACK, 728 PreviewCallbackForward.getNewInstance( 729 handler, AndroidCameraProxyImpl.this, cb)) 730 .sendToTarget(); 731 } 732 }); 733 } 734 735 @Override 736 public void setOneShotPreviewCallback(final Handler handler, 737 final CameraPreviewDataCallback cb) { 738 mDispatchThread.runJob(new Runnable() { 739 @Override 740 public void run() { 741 mCameraHandler.obtainMessage(CameraActions.SET_ONE_SHOT_PREVIEW_CALLBACK, 742 PreviewCallbackForward 743 .getNewInstance(handler, AndroidCameraProxyImpl.this, cb)) 744 .sendToTarget(); 745 } 746 }); 747 } 748 749 @Override 750 public void setPreviewDataCallbackWithBuffer( 751 final Handler handler, final CameraPreviewDataCallback cb) { 752 mDispatchThread.runJob(new Runnable() { 753 @Override 754 public void run() { 755 mCameraHandler.obtainMessage(CameraActions.SET_PREVIEW_CALLBACK_WITH_BUFFER, 756 PreviewCallbackForward 757 .getNewInstance(handler, AndroidCameraProxyImpl.this, cb)) 758 .sendToTarget(); 759 } 760 }); 761 } 762 763 @Override 764 public void autoFocus(final Handler handler, final CameraAFCallback cb) { 765 final AutoFocusCallback afCallback = new AutoFocusCallback() { 766 @Override 767 public void onAutoFocus(final boolean b, Camera camera) { 768 if (mCameraState.getState() != AndroidCameraStateHolder.CAMERA_FOCUSING) { 769 Log.w(TAG, "onAutoFocus callback returning when not focusing"); 770 } else { 771 mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE); 772 } 773 handler.post(new Runnable() { 774 @Override 775 public void run() { 776 cb.onAutoFocus(b, AndroidCameraProxyImpl.this); 777 } 778 }); 779 } 780 }; 781 mDispatchThread.runJob(new Runnable() { 782 @Override 783 public void run() { 784 mCameraState.waitForStates(AndroidCameraStateHolder.CAMERA_IDLE); 785 mCameraHandler.obtainMessage(CameraActions.AUTO_FOCUS, afCallback) 786 .sendToTarget(); 787 } 788 }); 789 } 790 791 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 792 @Override 793 public void setAutoFocusMoveCallback( 794 final Handler handler, final CameraAFMoveCallback cb) { 795 mDispatchThread.runJob(new Runnable() { 796 @Override 797 public void run() { 798 mCameraHandler.obtainMessage(CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK, 799 AFMoveCallbackForward.getNewInstance( 800 handler, AndroidCameraProxyImpl.this, cb)) 801 .sendToTarget(); 802 } 803 }); 804 } 805 806 @Override 807 public void takePicture( 808 final Handler handler, final CameraShutterCallback shutter, 809 final CameraPictureCallback raw, final CameraPictureCallback post, 810 final CameraPictureCallback jpeg) { 811 final PictureCallback jpegCallback = new PictureCallback() { 812 @Override 813 public void onPictureTaken(final byte[] data, Camera camera) { 814 if (mCameraState.getState() != AndroidCameraStateHolder.CAMERA_CAPTURING) { 815 Log.w(TAG, "picture callback returning when not capturing"); 816 } else { 817 mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE); 818 } 819 handler.post(new Runnable() { 820 @Override 821 public void run() { 822 jpeg.onPictureTaken(data, AndroidCameraProxyImpl.this); 823 } 824 }); 825 } 826 }; 827 828 mDispatchThread.runJob(new Runnable() { 829 @Override 830 public void run() { 831 mCameraState.waitForStates(AndroidCameraStateHolder.CAMERA_IDLE | 832 AndroidCameraStateHolder.CAMERA_UNLOCKED); 833 mCameraHandler.requestTakePicture(ShutterCallbackForward 834 .getNewInstance(handler, AndroidCameraProxyImpl.this, shutter), 835 PictureCallbackForward 836 .getNewInstance(handler, AndroidCameraProxyImpl.this, raw), 837 PictureCallbackForward 838 .getNewInstance(handler, AndroidCameraProxyImpl.this, post), 839 jpegCallback 840 ); 841 } 842 }); 843 } 844 845 @Override 846 public void setZoomChangeListener(final OnZoomChangeListener listener) { 847 mDispatchThread.runJob(new Runnable() { 848 @Override 849 public void run() { 850 mCameraHandler.obtainMessage(CameraActions.SET_ZOOM_CHANGE_LISTENER, listener) 851 .sendToTarget(); 852 } 853 }); 854 } 855 856 @Override 857 public void setFaceDetectionCallback(final Handler handler, 858 final CameraFaceDetectionCallback cb) { 859 mDispatchThread.runJob(new Runnable() { 860 @Override 861 public void run() { 862 mCameraHandler.obtainMessage(CameraActions.SET_FACE_DETECTION_LISTENER, 863 FaceDetectionCallbackForward 864 .getNewInstance(handler, AndroidCameraProxyImpl.this, cb)) 865 .sendToTarget(); 866 } 867 }); 868 } 869 870 @Override 871 public void setErrorCallback(final Handler handler, final CameraErrorCallback cb) { 872 mDispatchThread.runJob(new Runnable() { 873 @Override 874 public void run() { 875 mCameraHandler.obtainMessage(CameraActions.SET_ERROR_CALLBACK, 876 ErrorCallbackForward.getNewInstance( 877 handler, AndroidCameraProxyImpl.this, cb)) 878 .sendToTarget(); 879 } 880 }); 881 } 882 883 @Deprecated 884 @Override 885 public void setParameters(final Parameters params) { 886 if (params == null) { 887 Log.v(TAG, "null parameters in setParameters()"); 888 return; 889 } 890 final String flattenedParameters = params.flatten(); 891 mDispatchThread.runJob(new Runnable() { 892 @Override 893 public void run() { 894 mCameraState.waitForStates(AndroidCameraStateHolder.CAMERA_IDLE | 895 AndroidCameraStateHolder.CAMERA_UNLOCKED); 896 mCameraHandler.obtainMessage(CameraActions.SET_PARAMETERS, flattenedParameters) 897 .sendToTarget(); 898 } 899 }); 900 } 901 902 @Deprecated 903 @Override 904 public Parameters getParameters() { 905 final WaitDoneBundle bundle = new WaitDoneBundle(); 906 final Parameters[] parametersHolder = new Parameters[1]; 907 mDispatchThread.runJobSync(new Runnable() { 908 @Override 909 public void run() { 910 Message getParametersMessage = mCameraHandler.obtainMessage( 911 CameraActions.GET_PARAMETERS, parametersHolder); 912 mCameraHandler.sendMessage(getParametersMessage); 913 mCameraHandler.post(bundle.mUnlockRunnable); 914 } 915 }, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "get parameters"); 916 return parametersHolder[0]; 917 } 918 919 @Override 920 public CameraSettings getSettings() { 921 return new AndroidCameraSettings(mCapabilities, getParameters()); 922 } 923 924 @Override 925 public boolean applySettings(CameraSettings settings) { 926 return applySettingsHelper(settings, AndroidCameraStateHolder.CAMERA_IDLE | 927 AndroidCameraStateHolder.CAMERA_UNLOCKED); 928 } 929 930 @Override 931 public String dumpDeviceSettings() { 932 Parameters parameters = getParameters(); 933 if (parameters != null) { 934 String flattened = getParameters().flatten(); 935 StringTokenizer tokenizer = new StringTokenizer(flattened, ";"); 936 String dumpedSettings = new String(); 937 while (tokenizer.hasMoreElements()) { 938 dumpedSettings += tokenizer.nextToken() + '\n'; 939 } 940 941 return dumpedSettings; 942 } else { 943 return "[no parameters retrieved]"; 944 } 945 } 946 947 @Override 948 public Handler getCameraHandler() { 949 return AndroidCameraAgentImpl.this.getCameraHandler(); 950 } 951 952 @Override 953 public DispatchThread getDispatchThread() { 954 return AndroidCameraAgentImpl.this.getDispatchThread(); 955 } 956 957 @Override 958 public CameraStateHolder getCameraState() { 959 return mCameraState; 960 } 961 } 962 963 private static class AndroidCameraStateHolder extends CameraStateHolder { 964 /* Camera states */ 965 // These states are defined bitwise so we can easily to specify a set of 966 // states together. 967 public static final int CAMERA_UNOPENED = 1; 968 public static final int CAMERA_IDLE = 1 << 1; 969 public static final int CAMERA_UNLOCKED = 1 << 2; 970 public static final int CAMERA_CAPTURING = 1 << 3; 971 public static final int CAMERA_FOCUSING = 1 << 4; 972 973 public AndroidCameraStateHolder() { 974 this(CAMERA_UNOPENED); 975 } 976 977 public AndroidCameraStateHolder(int state) { 978 super(state); 979 } 980 } 981 982 /** 983 * A helper class to forward AutoFocusCallback to another thread. 984 */ 985 private static class AFCallbackForward implements AutoFocusCallback { 986 private final Handler mHandler; 987 private final CameraProxy mCamera; 988 private final CameraAFCallback mCallback; 989 990 /** 991 * Returns a new instance of {@link AFCallbackForward}. 992 * 993 * @param handler The handler in which the callback will be invoked in. 994 * @param camera The {@link CameraProxy} which the callback is from. 995 * @param cb The callback to be invoked. 996 * @return The instance of the {@link AFCallbackForward}, 997 * or null if any parameter is null. 998 */ 999 public static AFCallbackForward getNewInstance( 1000 Handler handler, CameraProxy camera, CameraAFCallback cb) { 1001 if (handler == null || camera == null || cb == null) { 1002 return null; 1003 } 1004 return new AFCallbackForward(handler, camera, cb); 1005 } 1006 1007 private AFCallbackForward( 1008 Handler h, CameraProxy camera, CameraAFCallback cb) { 1009 mHandler = h; 1010 mCamera = camera; 1011 mCallback = cb; 1012 } 1013 1014 @Override 1015 public void onAutoFocus(final boolean b, Camera camera) { 1016 mHandler.post(new Runnable() { 1017 @Override 1018 public void run() { 1019 mCallback.onAutoFocus(b, mCamera); 1020 } 1021 }); 1022 } 1023 } 1024 1025 /** 1026 * A helper class to forward ErrorCallback to another thread. 1027 */ 1028 private static class ErrorCallbackForward implements Camera.ErrorCallback { 1029 private final Handler mHandler; 1030 private final CameraProxy mCamera; 1031 private final CameraErrorCallback mCallback; 1032 1033 /** 1034 * Returns a new instance of {@link AFCallbackForward}. 1035 * 1036 * @param handler The handler in which the callback will be invoked in. 1037 * @param camera The {@link CameraProxy} which the callback is from. 1038 * @param cb The callback to be invoked. 1039 * @return The instance of the {@link AFCallbackForward}, 1040 * or null if any parameter is null. 1041 */ 1042 public static ErrorCallbackForward getNewInstance( 1043 Handler handler, CameraProxy camera, CameraErrorCallback cb) { 1044 if (handler == null || camera == null || cb == null) { 1045 return null; 1046 } 1047 return new ErrorCallbackForward(handler, camera, cb); 1048 } 1049 1050 private ErrorCallbackForward( 1051 Handler h, CameraProxy camera, CameraErrorCallback cb) { 1052 mHandler = h; 1053 mCamera = camera; 1054 mCallback = cb; 1055 } 1056 1057 @Override 1058 public void onError(final int error, Camera camera) { 1059 mHandler.post(new Runnable() { 1060 @Override 1061 public void run() { 1062 mCallback.onError(error, mCamera); 1063 } 1064 }); 1065 } 1066 } 1067 1068 /** A helper class to forward AutoFocusMoveCallback to another thread. */ 1069 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 1070 private static class AFMoveCallbackForward implements AutoFocusMoveCallback { 1071 private final Handler mHandler; 1072 private final CameraAFMoveCallback mCallback; 1073 private final CameraProxy mCamera; 1074 1075 /** 1076 * Returns a new instance of {@link AFMoveCallbackForward}. 1077 * 1078 * @param handler The handler in which the callback will be invoked in. 1079 * @param camera The {@link CameraProxy} which the callback is from. 1080 * @param cb The callback to be invoked. 1081 * @return The instance of the {@link AFMoveCallbackForward}, 1082 * or null if any parameter is null. 1083 */ 1084 public static AFMoveCallbackForward getNewInstance( 1085 Handler handler, CameraProxy camera, CameraAFMoveCallback cb) { 1086 if (handler == null || camera == null || cb == null) { 1087 return null; 1088 } 1089 return new AFMoveCallbackForward(handler, camera, cb); 1090 } 1091 1092 private AFMoveCallbackForward( 1093 Handler h, CameraProxy camera, CameraAFMoveCallback cb) { 1094 mHandler = h; 1095 mCamera = camera; 1096 mCallback = cb; 1097 } 1098 1099 @Override 1100 public void onAutoFocusMoving( 1101 final boolean moving, android.hardware.Camera camera) { 1102 mHandler.post(new Runnable() { 1103 @Override 1104 public void run() { 1105 mCallback.onAutoFocusMoving(moving, mCamera); 1106 } 1107 }); 1108 } 1109 } 1110 1111 /** 1112 * A helper class to forward ShutterCallback to to another thread. 1113 */ 1114 private static class ShutterCallbackForward implements ShutterCallback { 1115 private final Handler mHandler; 1116 private final CameraShutterCallback mCallback; 1117 private final CameraProxy mCamera; 1118 1119 /** 1120 * Returns a new instance of {@link ShutterCallbackForward}. 1121 * 1122 * @param handler The handler in which the callback will be invoked in. 1123 * @param camera The {@link CameraProxy} which the callback is from. 1124 * @param cb The callback to be invoked. 1125 * @return The instance of the {@link ShutterCallbackForward}, 1126 * or null if any parameter is null. 1127 */ 1128 public static ShutterCallbackForward getNewInstance( 1129 Handler handler, CameraProxy camera, CameraShutterCallback cb) { 1130 if (handler == null || camera == null || cb == null) { 1131 return null; 1132 } 1133 return new ShutterCallbackForward(handler, camera, cb); 1134 } 1135 1136 private ShutterCallbackForward( 1137 Handler h, CameraProxy camera, CameraShutterCallback cb) { 1138 mHandler = h; 1139 mCamera = camera; 1140 mCallback = cb; 1141 } 1142 1143 @Override 1144 public void onShutter() { 1145 mHandler.post(new Runnable() { 1146 @Override 1147 public void run() { 1148 mCallback.onShutter(mCamera); 1149 } 1150 }); 1151 } 1152 } 1153 1154 /** 1155 * A helper class to forward PictureCallback to another thread. 1156 */ 1157 private static class PictureCallbackForward implements PictureCallback { 1158 private final Handler mHandler; 1159 private final CameraPictureCallback mCallback; 1160 private final CameraProxy mCamera; 1161 1162 /** 1163 * Returns a new instance of {@link PictureCallbackForward}. 1164 * 1165 * @param handler The handler in which the callback will be invoked in. 1166 * @param camera The {@link CameraProxy} which the callback is from. 1167 * @param cb The callback to be invoked. 1168 * @return The instance of the {@link PictureCallbackForward}, 1169 * or null if any parameters is null. 1170 */ 1171 public static PictureCallbackForward getNewInstance( 1172 Handler handler, CameraProxy camera, CameraPictureCallback cb) { 1173 if (handler == null || camera == null || cb == null) { 1174 return null; 1175 } 1176 return new PictureCallbackForward(handler, camera, cb); 1177 } 1178 1179 private PictureCallbackForward( 1180 Handler h, CameraProxy camera, CameraPictureCallback cb) { 1181 mHandler = h; 1182 mCamera = camera; 1183 mCallback = cb; 1184 } 1185 1186 @Override 1187 public void onPictureTaken( 1188 final byte[] data, android.hardware.Camera camera) { 1189 mHandler.post(new Runnable() { 1190 @Override 1191 public void run() { 1192 mCallback.onPictureTaken(data, mCamera); 1193 } 1194 }); 1195 } 1196 } 1197 1198 /** 1199 * A helper class to forward PreviewCallback to another thread. 1200 */ 1201 private static class PreviewCallbackForward implements PreviewCallback { 1202 private final Handler mHandler; 1203 private final CameraPreviewDataCallback mCallback; 1204 private final CameraProxy mCamera; 1205 1206 /** 1207 * Returns a new instance of {@link PreviewCallbackForward}. 1208 * 1209 * @param handler The handler in which the callback will be invoked in. 1210 * @param camera The {@link CameraProxy} which the callback is from. 1211 * @param cb The callback to be invoked. 1212 * @return The instance of the {@link PreviewCallbackForward}, 1213 * or null if any parameters is null. 1214 */ 1215 public static PreviewCallbackForward getNewInstance( 1216 Handler handler, CameraProxy camera, CameraPreviewDataCallback cb) { 1217 if (handler == null || camera == null || cb == null) { 1218 return null; 1219 } 1220 return new PreviewCallbackForward(handler, camera, cb); 1221 } 1222 1223 private PreviewCallbackForward( 1224 Handler h, CameraProxy camera, CameraPreviewDataCallback cb) { 1225 mHandler = h; 1226 mCamera = camera; 1227 mCallback = cb; 1228 } 1229 1230 @Override 1231 public void onPreviewFrame( 1232 final byte[] data, android.hardware.Camera camera) { 1233 mHandler.post(new Runnable() { 1234 @Override 1235 public void run() { 1236 mCallback.onPreviewFrame(data, mCamera); 1237 } 1238 }); 1239 } 1240 } 1241 1242 private static class FaceDetectionCallbackForward implements FaceDetectionListener { 1243 private final Handler mHandler; 1244 private final CameraFaceDetectionCallback mCallback; 1245 private final CameraProxy mCamera; 1246 1247 /** 1248 * Returns a new instance of {@link FaceDetectionCallbackForward}. 1249 * 1250 * @param handler The handler in which the callback will be invoked in. 1251 * @param camera The {@link CameraProxy} which the callback is from. 1252 * @param cb The callback to be invoked. 1253 * @return The instance of the {@link FaceDetectionCallbackForward}, 1254 * or null if any parameter is null. 1255 */ 1256 public static FaceDetectionCallbackForward getNewInstance( 1257 Handler handler, CameraProxy camera, CameraFaceDetectionCallback cb) { 1258 if (handler == null || camera == null || cb == null) { 1259 return null; 1260 } 1261 return new FaceDetectionCallbackForward(handler, camera, cb); 1262 } 1263 1264 private FaceDetectionCallbackForward( 1265 Handler h, CameraProxy camera, CameraFaceDetectionCallback cb) { 1266 mHandler = h; 1267 mCamera = camera; 1268 mCallback = cb; 1269 } 1270 1271 @Override 1272 public void onFaceDetection( 1273 final Camera.Face[] faces, Camera camera) { 1274 mHandler.post(new Runnable() { 1275 @Override 1276 public void run() { 1277 mCallback.onFaceDetection(faces, mCamera); 1278 } 1279 }); 1280 } 1281 } 1282} 1283