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