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 Log.w(TAG, "Cannot handle message, mCamera is null."); 333 return; 334 } 335 throw e; 336 } 337 } 338 } 339 340 @Override 341 public CameraManager.CameraProxy cameraOpen( 342 Handler handler, int cameraId, CameraOpenErrorCallback callback) { 343 mCameraHandler.obtainMessage(OPEN_CAMERA, cameraId, 0, 344 CameraOpenErrorCallbackForward.getNewInstance( 345 handler, callback)).sendToTarget(); 346 mCameraHandler.waitDone(); 347 if (mCamera != null) { 348 return new AndroidCameraProxyImpl(); 349 } else { 350 return null; 351 } 352 } 353 354 /** 355 * A class which implements {@link CameraManager.CameraProxy} and 356 * camera handler thread. 357 * TODO: Save the handler for the callback here to avoid passing the same 358 * handler multiple times. 359 */ 360 public class AndroidCameraProxyImpl implements CameraManager.CameraProxy { 361 362 private AndroidCameraProxyImpl() { 363 Assert(mCamera != null); 364 } 365 366 @Override 367 public android.hardware.Camera getCamera() { 368 return mCamera; 369 } 370 371 @Override 372 public void release() { 373 // release() must be synchronous so we know exactly when the camera 374 // is released and can continue on. 375 mCameraHandler.sendEmptyMessage(RELEASE); 376 mCameraHandler.waitDone(); 377 } 378 379 @Override 380 public boolean reconnect(Handler handler, CameraOpenErrorCallback cb) { 381 mCameraHandler.sendEmptyMessage(RECONNECT); 382 mCameraHandler.waitDone(); 383 CameraOpenErrorCallback cbforward = 384 CameraOpenErrorCallbackForward.getNewInstance(handler, cb); 385 if (mReconnectIOException != null) { 386 if (cbforward != null) { 387 cbforward.onReconnectionFailure(AndroidCameraManagerImpl.this); 388 } 389 return false; 390 } 391 return true; 392 } 393 394 @Override 395 public void unlock() { 396 mCameraHandler.sendEmptyMessage(UNLOCK); 397 mCameraHandler.waitDone(); 398 } 399 400 @Override 401 public void lock() { 402 mCameraHandler.sendEmptyMessage(LOCK); 403 } 404 405 @Override 406 public void setPreviewTexture(SurfaceTexture surfaceTexture) { 407 mCameraHandler.obtainMessage(SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture).sendToTarget(); 408 } 409 410 @Override 411 public void setPreviewDisplay(SurfaceHolder surfaceHolder) { 412 mCameraHandler.obtainMessage(SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder).sendToTarget(); 413 } 414 415 @Override 416 public void startPreview() { 417 mCameraHandler.sendEmptyMessage(START_PREVIEW_ASYNC); 418 } 419 420 @Override 421 public void stopPreview() { 422 mCameraHandler.sendEmptyMessage(STOP_PREVIEW); 423 mCameraHandler.waitDone(); 424 } 425 426 @Override 427 public void setPreviewDataCallback( 428 Handler handler, CameraPreviewDataCallback cb) { 429 mCameraHandler.obtainMessage( 430 SET_PREVIEW_CALLBACK, 431 PreviewCallbackForward.getNewInstance(handler, this, cb)).sendToTarget(); 432 } 433 434 @Override 435 public void setPreviewDataCallbackWithBuffer( 436 Handler handler, CameraPreviewDataCallback cb) { 437 mCameraHandler.obtainMessage( 438 SET_PREVIEW_CALLBACK_WITH_BUFFER, 439 PreviewCallbackForward.getNewInstance(handler, this, cb)).sendToTarget(); 440 } 441 442 @Override 443 public void addCallbackBuffer(byte[] callbackBuffer) { 444 mCameraHandler.obtainMessage(ADD_CALLBACK_BUFFER, callbackBuffer).sendToTarget(); 445 } 446 447 @Override 448 public void autoFocus(Handler handler, CameraAFCallback cb) { 449 mCameraHandler.obtainMessage( 450 AUTO_FOCUS, 451 AFCallbackForward.getNewInstance(handler, this, cb)).sendToTarget(); 452 } 453 454 @Override 455 public void cancelAutoFocus() { 456 mCameraHandler.removeMessages(AUTO_FOCUS); 457 mCameraHandler.sendEmptyMessage(CANCEL_AUTO_FOCUS); 458 } 459 460 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 461 @Override 462 public void setAutoFocusMoveCallback( 463 Handler handler, CameraAFMoveCallback cb) { 464 mCameraHandler.obtainMessage( 465 SET_AUTO_FOCUS_MOVE_CALLBACK, 466 AFMoveCallbackForward.getNewInstance(handler, this, cb)).sendToTarget(); 467 } 468 469 @Override 470 public void takePicture( 471 Handler handler, 472 CameraShutterCallback shutter, 473 CameraPictureCallback raw, 474 CameraPictureCallback post, 475 CameraPictureCallback jpeg) { 476 mCameraHandler.requestTakePicture( 477 ShutterCallbackForward.getNewInstance(handler, this, shutter), 478 PictureCallbackForward.getNewInstance(handler, this, raw), 479 PictureCallbackForward.getNewInstance(handler, this, post), 480 PictureCallbackForward.getNewInstance(handler, this, jpeg)); 481 } 482 483 @Override 484 public void setDisplayOrientation(int degrees) { 485 mCameraHandler.obtainMessage(SET_DISPLAY_ORIENTATION, degrees, 0) 486 .sendToTarget(); 487 } 488 489 @Override 490 public void setZoomChangeListener(OnZoomChangeListener listener) { 491 mCameraHandler.obtainMessage(SET_ZOOM_CHANGE_LISTENER, listener).sendToTarget(); 492 } 493 494 public void setFaceDetectionCallback( 495 Handler handler, CameraFaceDetectionCallback cb) { 496 mCameraHandler.obtainMessage( 497 SET_FACE_DETECTION_LISTENER, 498 FaceDetectionCallbackForward.getNewInstance(handler, this, cb)).sendToTarget(); 499 } 500 501 @Override 502 public void startFaceDetection() { 503 mCameraHandler.sendEmptyMessage(START_FACE_DETECTION); 504 } 505 506 @Override 507 public void stopFaceDetection() { 508 mCameraHandler.sendEmptyMessage(STOP_FACE_DETECTION); 509 } 510 511 @Override 512 public void setErrorCallback(ErrorCallback cb) { 513 mCameraHandler.obtainMessage(SET_ERROR_CALLBACK, cb).sendToTarget(); 514 } 515 516 @Override 517 public void setParameters(Parameters params) { 518 if (params == null) { 519 Log.v(TAG, "null parameters in setParameters()"); 520 return; 521 } 522 mCameraHandler.obtainMessage(SET_PARAMETERS, params.flatten()) 523 .sendToTarget(); 524 } 525 526 @Override 527 public Parameters getParameters() { 528 mCameraHandler.sendEmptyMessage(GET_PARAMETERS); 529 mCameraHandler.waitDone(); 530 return mParameters; 531 } 532 533 @Override 534 public void refreshParameters() { 535 mCameraHandler.sendEmptyMessage(REFRESH_PARAMETERS); 536 } 537 538 @Override 539 public void enableShutterSound(boolean enable) { 540 mCameraHandler.obtainMessage( 541 ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0).sendToTarget(); 542 } 543 } 544 545 /** 546 * A helper class to forward AutoFocusCallback to another thread. 547 */ 548 private static class AFCallbackForward implements AutoFocusCallback { 549 private final Handler mHandler; 550 private final CameraProxy mCamera; 551 private final CameraAFCallback mCallback; 552 553 /** 554 * Returns a new instance of {@link AFCallbackForward}. 555 * 556 * @param handler The handler in which the callback will be invoked in. 557 * @param camera The {@link CameraProxy} which the callback is from. 558 * @param cb The callback to be invoked. 559 * @return The instance of the {@link AFCallbackForward}, 560 * or null if any parameter is null. 561 */ 562 public static AFCallbackForward getNewInstance( 563 Handler handler, CameraProxy camera, CameraAFCallback cb) { 564 if (handler == null || camera == null || cb == null) return null; 565 return new AFCallbackForward(handler, camera, cb); 566 } 567 568 private AFCallbackForward( 569 Handler h, CameraProxy camera, CameraAFCallback cb) { 570 mHandler = h; 571 mCamera = camera; 572 mCallback = cb; 573 } 574 575 @Override 576 public void onAutoFocus(final boolean b, Camera camera) { 577 mHandler.post(new Runnable() { 578 @Override 579 public void run() { 580 mCallback.onAutoFocus(b, mCamera); 581 } 582 }); 583 } 584 } 585 586 /** A helper class to forward AutoFocusMoveCallback to another thread. */ 587 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 588 private static class AFMoveCallbackForward implements AutoFocusMoveCallback { 589 private final Handler mHandler; 590 private final CameraAFMoveCallback mCallback; 591 private final CameraProxy mCamera; 592 593 /** 594 * Returns a new instance of {@link AFMoveCallbackForward}. 595 * 596 * @param handler The handler in which the callback will be invoked in. 597 * @param camera The {@link CameraProxy} which the callback is from. 598 * @param cb The callback to be invoked. 599 * @return The instance of the {@link AFMoveCallbackForward}, 600 * or null if any parameter is null. 601 */ 602 public static AFMoveCallbackForward getNewInstance( 603 Handler handler, CameraProxy camera, CameraAFMoveCallback cb) { 604 if (handler == null || camera == null || cb == null) return null; 605 return new AFMoveCallbackForward(handler, camera, cb); 606 } 607 608 private AFMoveCallbackForward( 609 Handler h, CameraProxy camera, CameraAFMoveCallback cb) { 610 mHandler = h; 611 mCamera = camera; 612 mCallback = cb; 613 } 614 615 @Override 616 public void onAutoFocusMoving( 617 final boolean moving, android.hardware.Camera camera) { 618 mHandler.post(new Runnable() { 619 @Override 620 public void run() { 621 mCallback.onAutoFocusMoving(moving, mCamera); 622 } 623 }); 624 } 625 } 626 627 /** 628 * A helper class to forward ShutterCallback to to another thread. 629 */ 630 private static class ShutterCallbackForward implements ShutterCallback { 631 private final Handler mHandler; 632 private final CameraShutterCallback mCallback; 633 private final CameraProxy mCamera; 634 635 /** 636 * Returns a new instance of {@link ShutterCallbackForward}. 637 * 638 * @param handler The handler in which the callback will be invoked in. 639 * @param camera The {@link CameraProxy} which the callback is from. 640 * @param cb The callback to be invoked. 641 * @return The instance of the {@link ShutterCallbackForward}, 642 * or null if any parameter is null. 643 */ 644 public static ShutterCallbackForward getNewInstance( 645 Handler handler, CameraProxy camera, CameraShutterCallback cb) { 646 if (handler == null || camera == null || cb == null) return null; 647 return new ShutterCallbackForward(handler, camera, cb); 648 } 649 650 private ShutterCallbackForward( 651 Handler h, CameraProxy camera, CameraShutterCallback cb) { 652 mHandler = h; 653 mCamera = camera; 654 mCallback = cb; 655 } 656 657 @Override 658 public void onShutter() { 659 mHandler.post(new Runnable() { 660 @Override 661 public void run() { 662 mCallback.onShutter(mCamera); 663 } 664 }); 665 } 666 } 667 668 /** 669 * A helper class to forward PictureCallback to another thread. 670 */ 671 private static class PictureCallbackForward implements PictureCallback { 672 private final Handler mHandler; 673 private final CameraPictureCallback mCallback; 674 private final CameraProxy mCamera; 675 676 /** 677 * Returns a new instance of {@link PictureCallbackForward}. 678 * 679 * @param handler The handler in which the callback will be invoked in. 680 * @param camera The {@link CameraProxy} which the callback is from. 681 * @param cb The callback to be invoked. 682 * @return The instance of the {@link PictureCallbackForward}, 683 * or null if any parameters is null. 684 */ 685 public static PictureCallbackForward getNewInstance( 686 Handler handler, CameraProxy camera, CameraPictureCallback cb) { 687 if (handler == null || camera == null || cb == null) return null; 688 return new PictureCallbackForward(handler, camera, cb); 689 } 690 691 private PictureCallbackForward( 692 Handler h, CameraProxy camera, CameraPictureCallback cb) { 693 mHandler = h; 694 mCamera = camera; 695 mCallback = cb; 696 } 697 698 @Override 699 public void onPictureTaken( 700 final byte[] data, android.hardware.Camera camera) { 701 mHandler.post(new Runnable() { 702 @Override 703 public void run() { 704 mCallback.onPictureTaken(data, mCamera); 705 } 706 }); 707 } 708 } 709 710 /** 711 * A helper class to forward PreviewCallback to another thread. 712 */ 713 private static class PreviewCallbackForward implements PreviewCallback { 714 private final Handler mHandler; 715 private final CameraPreviewDataCallback mCallback; 716 private final CameraProxy mCamera; 717 718 /** 719 * Returns a new instance of {@link PreviewCallbackForward}. 720 * 721 * @param handler The handler in which the callback will be invoked in. 722 * @param camera The {@link CameraProxy} which the callback is from. 723 * @param cb The callback to be invoked. 724 * @return The instance of the {@link PreviewCallbackForward}, 725 * or null if any parameters is null. 726 */ 727 public static PreviewCallbackForward getNewInstance( 728 Handler handler, CameraProxy camera, CameraPreviewDataCallback cb) { 729 if (handler == null || camera == null || cb == null) return null; 730 return new PreviewCallbackForward(handler, camera, cb); 731 } 732 733 private PreviewCallbackForward( 734 Handler h, CameraProxy camera, CameraPreviewDataCallback cb) { 735 mHandler = h; 736 mCamera = camera; 737 mCallback = cb; 738 } 739 740 @Override 741 public void onPreviewFrame( 742 final byte[] data, android.hardware.Camera camera) { 743 mHandler.post(new Runnable() { 744 @Override 745 public void run() { 746 mCallback.onPreviewFrame(data, mCamera); 747 } 748 }); 749 } 750 } 751 752 private static class FaceDetectionCallbackForward implements FaceDetectionListener { 753 private final Handler mHandler; 754 private final CameraFaceDetectionCallback mCallback; 755 private final CameraProxy mCamera; 756 757 /** 758 * Returns a new instance of {@link FaceDetectionCallbackForward}. 759 * 760 * @param handler The handler in which the callback will be invoked in. 761 * @param camera The {@link CameraProxy} which the callback is from. 762 * @param cb The callback to be invoked. 763 * @return The instance of the {@link FaceDetectionCallbackForward}, 764 * or null if any parameter is null. 765 */ 766 public static FaceDetectionCallbackForward getNewInstance( 767 Handler handler, CameraProxy camera, CameraFaceDetectionCallback cb) { 768 if (handler == null || camera == null || cb == null) return null; 769 return new FaceDetectionCallbackForward(handler, camera, cb); 770 } 771 772 private FaceDetectionCallbackForward( 773 Handler h, CameraProxy camera, CameraFaceDetectionCallback cb) { 774 mHandler = h; 775 mCamera = camera; 776 mCallback = cb; 777 } 778 779 @Override 780 public void onFaceDetection( 781 final Camera.Face[] faces, Camera camera) { 782 mHandler.post(new Runnable() { 783 @Override 784 public void run() { 785 mCallback.onFaceDetection(faces, mCamera); 786 } 787 }); 788 } 789 } 790 791 /** 792 * A callback helps to invoke the original callback on another 793 * {@link android.os.Handler}. 794 */ 795 private static class CameraOpenErrorCallbackForward implements CameraOpenErrorCallback { 796 private final Handler mHandler; 797 private final CameraOpenErrorCallback mCallback; 798 799 /** 800 * Returns a new instance of {@link FaceDetectionCallbackForward}. 801 * 802 * @param handler The handler in which the callback will be invoked in. 803 * @param cb The callback to be invoked. 804 * @return The instance of the {@link FaceDetectionCallbackForward}, or 805 * null if any parameter is null. 806 */ 807 public static CameraOpenErrorCallbackForward getNewInstance( 808 Handler handler, CameraOpenErrorCallback cb) { 809 if (handler == null || cb == null) { 810 return null; 811 } 812 return new CameraOpenErrorCallbackForward(handler, cb); 813 } 814 815 private CameraOpenErrorCallbackForward( 816 Handler h, CameraOpenErrorCallback cb) { 817 mHandler = h; 818 mCallback = cb; 819 } 820 821 @Override 822 public void onCameraDisabled(final int cameraId) { 823 mHandler.post(new Runnable() { 824 @Override 825 public void run() { 826 mCallback.onCameraDisabled(cameraId); 827 } 828 }); 829 } 830 831 @Override 832 public void onDeviceOpenFailure(final int cameraId) { 833 mHandler.post(new Runnable() { 834 @Override 835 public void run() { 836 mCallback.onDeviceOpenFailure(cameraId); 837 } 838 }); 839 } 840 841 @Override 842 public void onReconnectionFailure(final CameraManager mgr) { 843 mHandler.post(new Runnable() { 844 @Override 845 public void run() { 846 mCallback.onReconnectionFailure(mgr); 847 } 848 }); 849 } 850 } 851 } 852