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 17 package com.android.camera; 18 19 import static com.android.camera.util.CameraUtil.Assert; 20 21 import java.io.IOException; 22 23 import android.annotation.TargetApi; 24 import android.graphics.SurfaceTexture; 25 import android.hardware.Camera; 26 import android.hardware.Camera.AutoFocusCallback; 27 import android.hardware.Camera.AutoFocusMoveCallback; 28 import android.hardware.Camera.ErrorCallback; 29 import android.hardware.Camera.FaceDetectionListener; 30 import android.hardware.Camera.OnZoomChangeListener; 31 import android.hardware.Camera.Parameters; 32 import android.hardware.Camera.PictureCallback; 33 import android.hardware.Camera.PreviewCallback; 34 import android.hardware.Camera.ShutterCallback; 35 import android.os.Build; 36 import android.os.Handler; 37 import android.os.HandlerThread; 38 import android.os.Looper; 39 import android.os.Message; 40 import android.util.Log; 41 import android.view.SurfaceHolder; 42 43 /** 44 * A class to implement {@link CameraManager} of the Android camera framework. 45 */ 46 class AndroidCameraManagerImpl implements CameraManager { 47 private static final String TAG = "CAM_" + 48 AndroidCameraManagerImpl.class.getSimpleName(); 49 50 private Parameters mParameters; 51 private boolean mParametersIsDirty; 52 private IOException mReconnectIOException; 53 54 /* Messages used in CameraHandler. */ 55 // Camera initialization/finalization 56 private static final int OPEN_CAMERA = 1; 57 private static final int RELEASE = 2; 58 private static final int RECONNECT = 3; 59 private static final int UNLOCK = 4; 60 private static final int LOCK = 5; 61 // Preview 62 private static final int SET_PREVIEW_TEXTURE_ASYNC = 101; 63 private static final int START_PREVIEW_ASYNC = 102; 64 private static final int STOP_PREVIEW = 103; 65 private static final int SET_PREVIEW_CALLBACK_WITH_BUFFER = 104; 66 private static final int ADD_CALLBACK_BUFFER = 105; 67 private static final int SET_PREVIEW_DISPLAY_ASYNC = 106; 68 private static final int SET_PREVIEW_CALLBACK = 107; 69 // Parameters 70 private static final int SET_PARAMETERS = 201; 71 private static final int GET_PARAMETERS = 202; 72 private static final int REFRESH_PARAMETERS = 203; 73 // Focus, Zoom 74 private static final int AUTO_FOCUS = 301; 75 private static final int CANCEL_AUTO_FOCUS = 302; 76 private static final int SET_AUTO_FOCUS_MOVE_CALLBACK = 303; 77 private static final int SET_ZOOM_CHANGE_LISTENER = 304; 78 // Face detection 79 private static final int SET_FACE_DETECTION_LISTENER = 461; 80 private static final int START_FACE_DETECTION = 462; 81 private static final int STOP_FACE_DETECTION = 463; 82 private static final int SET_ERROR_CALLBACK = 464; 83 // Presentation 84 private static final int ENABLE_SHUTTER_SOUND = 501; 85 private static final int SET_DISPLAY_ORIENTATION = 502; 86 87 private CameraHandler mCameraHandler; 88 private android.hardware.Camera mCamera; 89 90 // Used to retain a copy of Parameters for setting parameters. 91 private Parameters mParamsToSet; 92 93 AndroidCameraManagerImpl() { 94 HandlerThread ht = new HandlerThread("Camera Handler Thread"); 95 ht.start(); 96 mCameraHandler = new CameraHandler(ht.getLooper()); 97 } 98 99 private class CameraHandler extends Handler { 100 CameraHandler(Looper looper) { 101 super(looper); 102 } 103 104 private void startFaceDetection() { 105 mCamera.startFaceDetection(); 106 } 107 108 private void stopFaceDetection() { 109 mCamera.stopFaceDetection(); 110 } 111 112 private void setFaceDetectionListener(FaceDetectionListener listener) { 113 mCamera.setFaceDetectionListener(listener); 114 } 115 116 private void setPreviewTexture(Object surfaceTexture) { 117 try { 118 mCamera.setPreviewTexture((SurfaceTexture) surfaceTexture); 119 } catch (IOException e) { 120 Log.e(TAG, "Could not set preview texture", e); 121 } 122 } 123 124 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) 125 private void enableShutterSound(boolean enable) { 126 mCamera.enableShutterSound(enable); 127 } 128 129 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 130 private void setAutoFocusMoveCallback( 131 android.hardware.Camera camera, Object cb) { 132 camera.setAutoFocusMoveCallback((AutoFocusMoveCallback) cb); 133 } 134 135 public void requestTakePicture( 136 final ShutterCallback shutter, 137 final PictureCallback raw, 138 final PictureCallback postView, 139 final PictureCallback jpeg) { 140 post(new Runnable() { 141 @Override 142 public void run() { 143 try { 144 mCamera.takePicture(shutter, raw, postView, jpeg); 145 } catch (RuntimeException e) { 146 // TODO: output camera state and focus state for debugging. 147 Log.e(TAG, "take picture failed."); 148 throw e; 149 } 150 } 151 }); 152 } 153 154 /** 155 * Waits for all the {@code Message} and {@code Runnable} currently in the queue 156 * are processed. 157 * 158 * @return {@code false} if the wait was interrupted, {@code true} otherwise. 159 */ 160 public boolean waitDone() { 161 final Object waitDoneLock = new Object(); 162 final Runnable unlockRunnable = new Runnable() { 163 @Override 164 public void run() { 165 synchronized (waitDoneLock) { 166 waitDoneLock.notifyAll(); 167 } 168 } 169 }; 170 171 synchronized (waitDoneLock) { 172 mCameraHandler.post(unlockRunnable); 173 try { 174 waitDoneLock.wait(); 175 } catch (InterruptedException ex) { 176 Log.v(TAG, "waitDone interrupted"); 177 return false; 178 } 179 } 180 return true; 181 } 182 183 /** 184 * This method does not deal with the API level check. Everyone should 185 * check first for supported operations before sending message to this handler. 186 */ 187 @Override 188 public void handleMessage(final Message msg) { 189 try { 190 switch (msg.what) { 191 case OPEN_CAMERA: 192 mCamera = android.hardware.Camera.open(msg.arg1); 193 if (mCamera != null) { 194 mParametersIsDirty = true; 195 196 // Get a instance of Camera.Parameters for later use. 197 if (mParamsToSet == null) { 198 mParamsToSet = mCamera.getParameters(); 199 } 200 } else { 201 if (msg.obj != null) { 202 ((CameraOpenErrorCallback) msg.obj).onDeviceOpenFailure(msg.arg1); 203 } 204 } 205 return; 206 207 case RELEASE: 208 mCamera.release(); 209 mCamera = null; 210 return; 211 212 case RECONNECT: 213 mReconnectIOException = null; 214 try { 215 mCamera.reconnect(); 216 } catch (IOException ex) { 217 mReconnectIOException = ex; 218 } 219 return; 220 221 case UNLOCK: 222 mCamera.unlock(); 223 return; 224 225 case LOCK: 226 mCamera.lock(); 227 return; 228 229 case SET_PREVIEW_TEXTURE_ASYNC: 230 setPreviewTexture(msg.obj); 231 return; 232 233 case SET_PREVIEW_DISPLAY_ASYNC: 234 try { 235 mCamera.setPreviewDisplay((SurfaceHolder) msg.obj); 236 } catch (IOException e) { 237 throw new RuntimeException(e); 238 } 239 return; 240 241 case START_PREVIEW_ASYNC: 242 mCamera.startPreview(); 243 return; 244 245 case STOP_PREVIEW: 246 mCamera.stopPreview(); 247 return; 248 249 case SET_PREVIEW_CALLBACK_WITH_BUFFER: 250 mCamera.setPreviewCallbackWithBuffer( 251 (PreviewCallback) msg.obj); 252 return; 253 254 case ADD_CALLBACK_BUFFER: 255 mCamera.addCallbackBuffer((byte[]) msg.obj); 256 return; 257 258 case AUTO_FOCUS: 259 mCamera.autoFocus((AutoFocusCallback) msg.obj); 260 return; 261 262 case CANCEL_AUTO_FOCUS: 263 mCamera.cancelAutoFocus(); 264 return; 265 266 case SET_AUTO_FOCUS_MOVE_CALLBACK: 267 setAutoFocusMoveCallback(mCamera, msg.obj); 268 return; 269 270 case SET_DISPLAY_ORIENTATION: 271 mCamera.setDisplayOrientation(msg.arg1); 272 return; 273 274 case SET_ZOOM_CHANGE_LISTENER: 275 mCamera.setZoomChangeListener( 276 (OnZoomChangeListener) msg.obj); 277 return; 278 279 case SET_FACE_DETECTION_LISTENER: 280 setFaceDetectionListener((FaceDetectionListener) msg.obj); 281 return; 282 283 case START_FACE_DETECTION: 284 startFaceDetection(); 285 return; 286 287 case STOP_FACE_DETECTION: 288 stopFaceDetection(); 289 return; 290 291 case SET_ERROR_CALLBACK: 292 mCamera.setErrorCallback((ErrorCallback) msg.obj); 293 return; 294 295 case SET_PARAMETERS: 296 mParametersIsDirty = true; 297 mParamsToSet.unflatten((String) msg.obj); 298 mCamera.setParameters(mParamsToSet); 299 return; 300 301 case GET_PARAMETERS: 302 if (mParametersIsDirty) { 303 mParameters = mCamera.getParameters(); 304 mParametersIsDirty = false; 305 } 306 return; 307 308 case SET_PREVIEW_CALLBACK: 309 mCamera.setPreviewCallback((PreviewCallback) msg.obj); 310 return; 311 312 case ENABLE_SHUTTER_SOUND: 313 enableShutterSound((msg.arg1 == 1) ? true : false); 314 return; 315 316 case REFRESH_PARAMETERS: 317 mParametersIsDirty = true; 318 return; 319 320 default: 321 throw new RuntimeException("Invalid CameraProxy message=" + msg.what); 322 } 323 } catch (RuntimeException e) { 324 if (msg.what != RELEASE && mCamera != null) { 325 try { 326 mCamera.release(); 327 } catch (Exception ex) { 328 Log.e(TAG, "Fail to release the camera."); 329 } 330 mCamera = null; 331 } else if (mCamera == null) { 332 if (msg.what == OPEN_CAMERA) { 333 if (msg.obj != null) { 334 ((CameraOpenErrorCallback) msg.obj).onDeviceOpenFailure(msg.arg1); 335 } 336 } else { 337 Log.w(TAG, "Cannot handle message, mCamera is null."); 338 } 339 return; 340 } 341 throw e; 342 } 343 } 344 } 345 346 @Override 347 public CameraManager.CameraProxy cameraOpen( 348 Handler handler, int cameraId, CameraOpenErrorCallback callback) { 349 mCameraHandler.obtainMessage(OPEN_CAMERA, cameraId, 0, 350 CameraOpenErrorCallbackForward.getNewInstance( 351 handler, callback)).sendToTarget(); 352 mCameraHandler.waitDone(); 353 if (mCamera != null) { 354 return new AndroidCameraProxyImpl(); 355 } else { 356 return null; 357 } 358 } 359 360 /** 361 * A class which implements {@link CameraManager.CameraProxy} and 362 * camera handler thread. 363 * TODO: Save the handler for the callback here to avoid passing the same 364 * handler multiple times. 365 */ 366 public class AndroidCameraProxyImpl implements CameraManager.CameraProxy { 367 368 private AndroidCameraProxyImpl() { 369 Assert(mCamera != null); 370 } 371 372 @Override 373 public android.hardware.Camera getCamera() { 374 return mCamera; 375 } 376 377 @Override 378 public void release() { 379 // release() must be synchronous so we know exactly when the camera 380 // is released and can continue on. 381 mCameraHandler.sendEmptyMessage(RELEASE); 382 mCameraHandler.waitDone(); 383 } 384 385 @Override 386 public boolean reconnect(Handler handler, CameraOpenErrorCallback cb) { 387 mCameraHandler.sendEmptyMessage(RECONNECT); 388 mCameraHandler.waitDone(); 389 CameraOpenErrorCallback cbforward = 390 CameraOpenErrorCallbackForward.getNewInstance(handler, cb); 391 if (mReconnectIOException != null) { 392 if (cbforward != null) { 393 cbforward.onReconnectionFailure(AndroidCameraManagerImpl.this); 394 } 395 return false; 396 } 397 return true; 398 } 399 400 @Override 401 public void unlock() { 402 mCameraHandler.sendEmptyMessage(UNLOCK); 403 mCameraHandler.waitDone(); 404 } 405 406 @Override 407 public void lock() { 408 mCameraHandler.sendEmptyMessage(LOCK); 409 } 410 411 @Override 412 public void setPreviewTexture(SurfaceTexture surfaceTexture) { 413 mCameraHandler.obtainMessage(SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture).sendToTarget(); 414 } 415 416 @Override 417 public void setPreviewDisplay(SurfaceHolder surfaceHolder) { 418 mCameraHandler.obtainMessage(SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder).sendToTarget(); 419 } 420 421 @Override 422 public void startPreview() { 423 mCameraHandler.sendEmptyMessage(START_PREVIEW_ASYNC); 424 } 425 426 @Override 427 public void stopPreview() { 428 mCameraHandler.sendEmptyMessage(STOP_PREVIEW); 429 mCameraHandler.waitDone(); 430 } 431 432 @Override 433 public void setPreviewDataCallback( 434 Handler handler, CameraPreviewDataCallback cb) { 435 mCameraHandler.obtainMessage( 436 SET_PREVIEW_CALLBACK, 437 PreviewCallbackForward.getNewInstance(handler, this, cb)).sendToTarget(); 438 } 439 440 @Override 441 public void setPreviewDataCallbackWithBuffer( 442 Handler handler, CameraPreviewDataCallback cb) { 443 mCameraHandler.obtainMessage( 444 SET_PREVIEW_CALLBACK_WITH_BUFFER, 445 PreviewCallbackForward.getNewInstance(handler, this, cb)).sendToTarget(); 446 } 447 448 @Override 449 public void addCallbackBuffer(byte[] callbackBuffer) { 450 mCameraHandler.obtainMessage(ADD_CALLBACK_BUFFER, callbackBuffer).sendToTarget(); 451 } 452 453 @Override 454 public void autoFocus(Handler handler, CameraAFCallback cb) { 455 mCameraHandler.obtainMessage( 456 AUTO_FOCUS, 457 AFCallbackForward.getNewInstance(handler, this, cb)).sendToTarget(); 458 } 459 460 @Override 461 public void cancelAutoFocus() { 462 mCameraHandler.removeMessages(AUTO_FOCUS); 463 mCameraHandler.sendEmptyMessage(CANCEL_AUTO_FOCUS); 464 } 465 466 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 467 @Override 468 public void setAutoFocusMoveCallback( 469 Handler handler, CameraAFMoveCallback cb) { 470 mCameraHandler.obtainMessage( 471 SET_AUTO_FOCUS_MOVE_CALLBACK, 472 AFMoveCallbackForward.getNewInstance(handler, this, cb)).sendToTarget(); 473 } 474 475 @Override 476 public void takePicture( 477 Handler handler, 478 CameraShutterCallback shutter, 479 CameraPictureCallback raw, 480 CameraPictureCallback post, 481 CameraPictureCallback jpeg) { 482 mCameraHandler.requestTakePicture( 483 ShutterCallbackForward.getNewInstance(handler, this, shutter), 484 PictureCallbackForward.getNewInstance(handler, this, raw), 485 PictureCallbackForward.getNewInstance(handler, this, post), 486 PictureCallbackForward.getNewInstance(handler, this, jpeg)); 487 } 488 489 @Override 490 public void setDisplayOrientation(int degrees) { 491 mCameraHandler.obtainMessage(SET_DISPLAY_ORIENTATION, degrees, 0) 492 .sendToTarget(); 493 } 494 495 @Override 496 public void setZoomChangeListener(OnZoomChangeListener listener) { 497 mCameraHandler.obtainMessage(SET_ZOOM_CHANGE_LISTENER, listener).sendToTarget(); 498 } 499 500 public void setFaceDetectionCallback( 501 Handler handler, CameraFaceDetectionCallback cb) { 502 mCameraHandler.obtainMessage( 503 SET_FACE_DETECTION_LISTENER, 504 FaceDetectionCallbackForward.getNewInstance(handler, this, cb)).sendToTarget(); 505 } 506 507 @Override 508 public void startFaceDetection() { 509 mCameraHandler.sendEmptyMessage(START_FACE_DETECTION); 510 } 511 512 @Override 513 public void stopFaceDetection() { 514 mCameraHandler.sendEmptyMessage(STOP_FACE_DETECTION); 515 } 516 517 @Override 518 public void setErrorCallback(ErrorCallback cb) { 519 mCameraHandler.obtainMessage(SET_ERROR_CALLBACK, cb).sendToTarget(); 520 } 521 522 @Override 523 public void setParameters(Parameters params) { 524 if (params == null) { 525 Log.v(TAG, "null parameters in setParameters()"); 526 return; 527 } 528 mCameraHandler.obtainMessage(SET_PARAMETERS, params.flatten()) 529 .sendToTarget(); 530 } 531 532 @Override 533 public Parameters getParameters() { 534 mCameraHandler.sendEmptyMessage(GET_PARAMETERS); 535 mCameraHandler.waitDone(); 536 return mParameters; 537 } 538 539 @Override 540 public void refreshParameters() { 541 mCameraHandler.sendEmptyMessage(REFRESH_PARAMETERS); 542 } 543 544 @Override 545 public void enableShutterSound(boolean enable) { 546 mCameraHandler.obtainMessage( 547 ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0).sendToTarget(); 548 } 549 } 550 551 /** 552 * A helper class to forward AutoFocusCallback to another thread. 553 */ 554 private static class AFCallbackForward implements AutoFocusCallback { 555 private final Handler mHandler; 556 private final CameraProxy mCamera; 557 private final CameraAFCallback mCallback; 558 559 /** 560 * Returns a new instance of {@link AFCallbackForward}. 561 * 562 * @param handler The handler in which the callback will be invoked in. 563 * @param camera The {@link CameraProxy} which the callback is from. 564 * @param cb The callback to be invoked. 565 * @return The instance of the {@link AFCallbackForward}, 566 * or null if any parameter is null. 567 */ 568 public static AFCallbackForward getNewInstance( 569 Handler handler, CameraProxy camera, CameraAFCallback cb) { 570 if (handler == null || camera == null || cb == null) return null; 571 return new AFCallbackForward(handler, camera, cb); 572 } 573 574 private AFCallbackForward( 575 Handler h, CameraProxy camera, CameraAFCallback cb) { 576 mHandler = h; 577 mCamera = camera; 578 mCallback = cb; 579 } 580 581 @Override 582 public void onAutoFocus(final boolean b, Camera camera) { 583 mHandler.post(new Runnable() { 584 @Override 585 public void run() { 586 mCallback.onAutoFocus(b, mCamera); 587 } 588 }); 589 } 590 } 591 592 /** A helper class to forward AutoFocusMoveCallback to another thread. */ 593 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 594 private static class AFMoveCallbackForward implements AutoFocusMoveCallback { 595 private final Handler mHandler; 596 private final CameraAFMoveCallback mCallback; 597 private final CameraProxy mCamera; 598 599 /** 600 * Returns a new instance of {@link AFMoveCallbackForward}. 601 * 602 * @param handler The handler in which the callback will be invoked in. 603 * @param camera The {@link CameraProxy} which the callback is from. 604 * @param cb The callback to be invoked. 605 * @return The instance of the {@link AFMoveCallbackForward}, 606 * or null if any parameter is null. 607 */ 608 public static AFMoveCallbackForward getNewInstance( 609 Handler handler, CameraProxy camera, CameraAFMoveCallback cb) { 610 if (handler == null || camera == null || cb == null) return null; 611 return new AFMoveCallbackForward(handler, camera, cb); 612 } 613 614 private AFMoveCallbackForward( 615 Handler h, CameraProxy camera, CameraAFMoveCallback cb) { 616 mHandler = h; 617 mCamera = camera; 618 mCallback = cb; 619 } 620 621 @Override 622 public void onAutoFocusMoving( 623 final boolean moving, android.hardware.Camera camera) { 624 mHandler.post(new Runnable() { 625 @Override 626 public void run() { 627 mCallback.onAutoFocusMoving(moving, mCamera); 628 } 629 }); 630 } 631 } 632 633 /** 634 * A helper class to forward ShutterCallback to to another thread. 635 */ 636 private static class ShutterCallbackForward implements ShutterCallback { 637 private final Handler mHandler; 638 private final CameraShutterCallback mCallback; 639 private final CameraProxy mCamera; 640 641 /** 642 * Returns a new instance of {@link ShutterCallbackForward}. 643 * 644 * @param handler The handler in which the callback will be invoked in. 645 * @param camera The {@link CameraProxy} which the callback is from. 646 * @param cb The callback to be invoked. 647 * @return The instance of the {@link ShutterCallbackForward}, 648 * or null if any parameter is null. 649 */ 650 public static ShutterCallbackForward getNewInstance( 651 Handler handler, CameraProxy camera, CameraShutterCallback cb) { 652 if (handler == null || camera == null || cb == null) return null; 653 return new ShutterCallbackForward(handler, camera, cb); 654 } 655 656 private ShutterCallbackForward( 657 Handler h, CameraProxy camera, CameraShutterCallback cb) { 658 mHandler = h; 659 mCamera = camera; 660 mCallback = cb; 661 } 662 663 @Override 664 public void onShutter() { 665 mHandler.post(new Runnable() { 666 @Override 667 public void run() { 668 mCallback.onShutter(mCamera); 669 } 670 }); 671 } 672 } 673 674 /** 675 * A helper class to forward PictureCallback to another thread. 676 */ 677 private static class PictureCallbackForward implements PictureCallback { 678 private final Handler mHandler; 679 private final CameraPictureCallback mCallback; 680 private final CameraProxy mCamera; 681 682 /** 683 * Returns a new instance of {@link PictureCallbackForward}. 684 * 685 * @param handler The handler in which the callback will be invoked in. 686 * @param camera The {@link CameraProxy} which the callback is from. 687 * @param cb The callback to be invoked. 688 * @return The instance of the {@link PictureCallbackForward}, 689 * or null if any parameters is null. 690 */ 691 public static PictureCallbackForward getNewInstance( 692 Handler handler, CameraProxy camera, CameraPictureCallback cb) { 693 if (handler == null || camera == null || cb == null) return null; 694 return new PictureCallbackForward(handler, camera, cb); 695 } 696 697 private PictureCallbackForward( 698 Handler h, CameraProxy camera, CameraPictureCallback cb) { 699 mHandler = h; 700 mCamera = camera; 701 mCallback = cb; 702 } 703 704 @Override 705 public void onPictureTaken( 706 final byte[] data, android.hardware.Camera camera) { 707 mHandler.post(new Runnable() { 708 @Override 709 public void run() { 710 mCallback.onPictureTaken(data, mCamera); 711 } 712 }); 713 } 714 } 715 716 /** 717 * A helper class to forward PreviewCallback to another thread. 718 */ 719 private static class PreviewCallbackForward implements PreviewCallback { 720 private final Handler mHandler; 721 private final CameraPreviewDataCallback mCallback; 722 private final CameraProxy mCamera; 723 724 /** 725 * Returns a new instance of {@link PreviewCallbackForward}. 726 * 727 * @param handler The handler in which the callback will be invoked in. 728 * @param camera The {@link CameraProxy} which the callback is from. 729 * @param cb The callback to be invoked. 730 * @return The instance of the {@link PreviewCallbackForward}, 731 * or null if any parameters is null. 732 */ 733 public static PreviewCallbackForward getNewInstance( 734 Handler handler, CameraProxy camera, CameraPreviewDataCallback cb) { 735 if (handler == null || camera == null || cb == null) return null; 736 return new PreviewCallbackForward(handler, camera, cb); 737 } 738 739 private PreviewCallbackForward( 740 Handler h, CameraProxy camera, CameraPreviewDataCallback cb) { 741 mHandler = h; 742 mCamera = camera; 743 mCallback = cb; 744 } 745 746 @Override 747 public void onPreviewFrame( 748 final byte[] data, android.hardware.Camera camera) { 749 mHandler.post(new Runnable() { 750 @Override 751 public void run() { 752 mCallback.onPreviewFrame(data, mCamera); 753 } 754 }); 755 } 756 } 757 758 private static class FaceDetectionCallbackForward implements FaceDetectionListener { 759 private final Handler mHandler; 760 private final CameraFaceDetectionCallback mCallback; 761 private final CameraProxy mCamera; 762 763 /** 764 * Returns a new instance of {@link FaceDetectionCallbackForward}. 765 * 766 * @param handler The handler in which the callback will be invoked in. 767 * @param camera The {@link CameraProxy} which the callback is from. 768 * @param cb The callback to be invoked. 769 * @return The instance of the {@link FaceDetectionCallbackForward}, 770 * or null if any parameter is null. 771 */ 772 public static FaceDetectionCallbackForward getNewInstance( 773 Handler handler, CameraProxy camera, CameraFaceDetectionCallback cb) { 774 if (handler == null || camera == null || cb == null) return null; 775 return new FaceDetectionCallbackForward(handler, camera, cb); 776 } 777 778 private FaceDetectionCallbackForward( 779 Handler h, CameraProxy camera, CameraFaceDetectionCallback cb) { 780 mHandler = h; 781 mCamera = camera; 782 mCallback = cb; 783 } 784 785 @Override 786 public void onFaceDetection( 787 final Camera.Face[] faces, Camera camera) { 788 mHandler.post(new Runnable() { 789 @Override 790 public void run() { 791 mCallback.onFaceDetection(faces, mCamera); 792 } 793 }); 794 } 795 } 796 797 /** 798 * A callback helps to invoke the original callback on another 799 * {@link android.os.Handler}. 800 */ 801 private static class CameraOpenErrorCallbackForward implements CameraOpenErrorCallback { 802 private final Handler mHandler; 803 private final CameraOpenErrorCallback mCallback; 804 805 /** 806 * Returns a new instance of {@link FaceDetectionCallbackForward}. 807 * 808 * @param handler The handler in which the callback will be invoked in. 809 * @param cb The callback to be invoked. 810 * @return The instance of the {@link FaceDetectionCallbackForward}, or 811 * null if any parameter is null. 812 */ 813 public static CameraOpenErrorCallbackForward getNewInstance( 814 Handler handler, CameraOpenErrorCallback cb) { 815 if (handler == null || cb == null) { 816 return null; 817 } 818 return new CameraOpenErrorCallbackForward(handler, cb); 819 } 820 821 private CameraOpenErrorCallbackForward( 822 Handler h, CameraOpenErrorCallback cb) { 823 // Given that we are using the main thread handler, we can create it 824 // here instead of holding onto the PhotoModule objects. In this 825 // way, we can avoid memory leak. 826 mHandler = new Handler(Looper.getMainLooper()); 827 mCallback = cb; 828 } 829 830 @Override 831 public void onCameraDisabled(final int cameraId) { 832 mHandler.post(new Runnable() { 833 @Override 834 public void run() { 835 mCallback.onCameraDisabled(cameraId); 836 } 837 }); 838 } 839 840 @Override 841 public void onDeviceOpenFailure(final int cameraId) { 842 mHandler.post(new Runnable() { 843 @Override 844 public void run() { 845 mCallback.onDeviceOpenFailure(cameraId); 846 } 847 }); 848 } 849 850 @Override 851 public void onReconnectionFailure(final CameraManager mgr) { 852 mHandler.post(new Runnable() { 853 @Override 854 public void run() { 855 mCallback.onReconnectionFailure(mgr); 856 } 857 }); 858 } 859 } 860 } 861