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