Home | History | Annotate | Download | only in camera
      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