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