Home | History | Annotate | Download | only in camera
      1 /*
      2  * Copyright (C) 2012 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.Assert;
     20 
     21 import android.annotation.TargetApi;
     22 import android.graphics.SurfaceTexture;
     23 import android.hardware.Camera.AutoFocusCallback;
     24 import android.hardware.Camera.AutoFocusMoveCallback;
     25 import android.hardware.Camera.ErrorCallback;
     26 import android.hardware.Camera.FaceDetectionListener;
     27 import android.hardware.Camera.OnZoomChangeListener;
     28 import android.hardware.Camera.Parameters;
     29 import android.hardware.Camera.PictureCallback;
     30 import android.hardware.Camera.PreviewCallback;
     31 import android.hardware.Camera.ShutterCallback;
     32 import android.os.ConditionVariable;
     33 import android.os.Handler;
     34 import android.os.HandlerThread;
     35 import android.os.Looper;
     36 import android.os.Message;
     37 import android.view.SurfaceHolder;
     38 import android.util.Log;
     39 
     40 import com.android.gallery3d.common.ApiHelper;
     41 
     42 import java.io.IOException;
     43 
     44 public class CameraManager {
     45     private static final String TAG = "CameraManager";
     46     private static CameraManager sCameraManager = new CameraManager();
     47 
     48     // Thread progress signals
     49     private ConditionVariable mSig = new ConditionVariable();
     50 
     51     private Parameters mParameters;
     52     private IOException mReconnectException;
     53 
     54     private static final int RELEASE = 1;
     55     private static final int RECONNECT = 2;
     56     private static final int UNLOCK = 3;
     57     private static final int LOCK = 4;
     58     private static final int SET_PREVIEW_TEXTURE_ASYNC = 5;
     59     private static final int START_PREVIEW_ASYNC = 6;
     60     private static final int STOP_PREVIEW = 7;
     61     private static final int SET_PREVIEW_CALLBACK_WITH_BUFFER = 8;
     62     private static final int ADD_CALLBACK_BUFFER = 9;
     63     private static final int AUTO_FOCUS = 10;
     64     private static final int CANCEL_AUTO_FOCUS = 11;
     65     private static final int SET_AUTO_FOCUS_MOVE_CALLBACK = 12;
     66     private static final int SET_DISPLAY_ORIENTATION = 13;
     67     private static final int SET_ZOOM_CHANGE_LISTENER = 14;
     68     private static final int SET_FACE_DETECTION_LISTENER = 15;
     69     private static final int START_FACE_DETECTION = 16;
     70     private static final int STOP_FACE_DETECTION = 17;
     71     private static final int SET_ERROR_CALLBACK = 18;
     72     private static final int SET_PARAMETERS = 19;
     73     private static final int GET_PARAMETERS = 20;
     74     private static final int SET_PARAMETERS_ASYNC = 21;
     75     private static final int WAIT_FOR_IDLE = 22;
     76     private static final int SET_PREVIEW_DISPLAY_ASYNC = 23;
     77     private static final int SET_PREVIEW_CALLBACK = 24;
     78     private static final int ENABLE_SHUTTER_SOUND = 25;
     79 
     80     private Handler mCameraHandler;
     81     private CameraProxy mCameraProxy;
     82     private android.hardware.Camera mCamera;
     83 
     84     public static CameraManager instance() {
     85         return sCameraManager;
     86     }
     87 
     88     private CameraManager() {
     89         HandlerThread ht = new HandlerThread("Camera Handler Thread");
     90         ht.start();
     91         mCameraHandler = new CameraHandler(ht.getLooper());
     92     }
     93 
     94     private class CameraHandler extends Handler {
     95         CameraHandler(Looper looper) {
     96             super(looper);
     97         }
     98 
     99         @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
    100         private void startFaceDetection() {
    101             mCamera.startFaceDetection();
    102         }
    103 
    104         @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
    105         private void stopFaceDetection() {
    106             mCamera.stopFaceDetection();
    107         }
    108 
    109         @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
    110         private void setFaceDetectionListener(FaceDetectionListener listener) {
    111             mCamera.setFaceDetectionListener(listener);
    112         }
    113 
    114         @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
    115         private void setPreviewTexture(Object surfaceTexture) {
    116             try {
    117                 mCamera.setPreviewTexture((SurfaceTexture) surfaceTexture);
    118             } catch(IOException e) {
    119                 throw new RuntimeException(e);
    120             }
    121         }
    122 
    123         @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN_MR1)
    124         private void enableShutterSound(boolean enable) {
    125             mCamera.enableShutterSound(enable);
    126         }
    127 
    128         /*
    129          * This method does not deal with the build version check.  Everyone should
    130          * check first before sending message to this handler.
    131          */
    132         @Override
    133         public void handleMessage(final Message msg) {
    134             try {
    135                 switch (msg.what) {
    136                     case RELEASE:
    137                         mCamera.release();
    138                         mCamera = null;
    139                         mCameraProxy = null;
    140                         break;
    141 
    142                     case RECONNECT:
    143                         mReconnectException = null;
    144                         try {
    145                             mCamera.reconnect();
    146                         } catch (IOException ex) {
    147                             mReconnectException = ex;
    148                         }
    149                         break;
    150 
    151                     case UNLOCK:
    152                         mCamera.unlock();
    153                         break;
    154 
    155                     case LOCK:
    156                         mCamera.lock();
    157                         break;
    158 
    159                     case SET_PREVIEW_TEXTURE_ASYNC:
    160                         setPreviewTexture(msg.obj);
    161                         return;  // no need to call mSig.open()
    162 
    163                     case SET_PREVIEW_DISPLAY_ASYNC:
    164                         try {
    165                             mCamera.setPreviewDisplay((SurfaceHolder) msg.obj);
    166                         } catch(IOException e) {
    167                             throw new RuntimeException(e);
    168                         }
    169                         return;  // no need to call mSig.open()
    170 
    171                     case START_PREVIEW_ASYNC:
    172                         mCamera.startPreview();
    173                         return;  // no need to call mSig.open()
    174 
    175                     case STOP_PREVIEW:
    176                         mCamera.stopPreview();
    177                         break;
    178 
    179                     case SET_PREVIEW_CALLBACK_WITH_BUFFER:
    180                         mCamera.setPreviewCallbackWithBuffer(
    181                             (PreviewCallback) msg.obj);
    182                         break;
    183 
    184                     case ADD_CALLBACK_BUFFER:
    185                         mCamera.addCallbackBuffer((byte[]) msg.obj);
    186                         break;
    187 
    188                     case AUTO_FOCUS:
    189                         mCamera.autoFocus((AutoFocusCallback) msg.obj);
    190                         break;
    191 
    192                     case CANCEL_AUTO_FOCUS:
    193                         mCamera.cancelAutoFocus();
    194                         break;
    195 
    196                     case SET_AUTO_FOCUS_MOVE_CALLBACK:
    197                         setAutoFocusMoveCallback(mCamera, msg.obj);
    198                         break;
    199 
    200                     case SET_DISPLAY_ORIENTATION:
    201                         mCamera.setDisplayOrientation(msg.arg1);
    202                         break;
    203 
    204                     case SET_ZOOM_CHANGE_LISTENER:
    205                         mCamera.setZoomChangeListener(
    206                             (OnZoomChangeListener) msg.obj);
    207                         break;
    208 
    209                     case SET_FACE_DETECTION_LISTENER:
    210                         setFaceDetectionListener((FaceDetectionListener) msg.obj);
    211                         break;
    212 
    213                     case START_FACE_DETECTION:
    214                         startFaceDetection();
    215                         break;
    216 
    217                     case STOP_FACE_DETECTION:
    218                         stopFaceDetection();
    219                         break;
    220 
    221                     case SET_ERROR_CALLBACK:
    222                         mCamera.setErrorCallback((ErrorCallback) msg.obj);
    223                         break;
    224 
    225                     case SET_PARAMETERS:
    226                         mCamera.setParameters((Parameters) msg.obj);
    227                         break;
    228 
    229                     case GET_PARAMETERS:
    230                         mParameters = mCamera.getParameters();
    231                         break;
    232 
    233                     case SET_PARAMETERS_ASYNC:
    234                         mCamera.setParameters((Parameters) msg.obj);
    235                         return;  // no need to call mSig.open()
    236 
    237                     case SET_PREVIEW_CALLBACK:
    238                         mCamera.setPreviewCallback((PreviewCallback) msg.obj);
    239                         break;
    240 
    241                     case ENABLE_SHUTTER_SOUND:
    242                         enableShutterSound((msg.arg1 == 1) ? true : false);
    243                         break;
    244 
    245                     case WAIT_FOR_IDLE:
    246                         // do nothing
    247                         break;
    248 
    249                     default:
    250                         throw new RuntimeException("Invalid CameraProxy message=" + msg.what);
    251                 }
    252             } catch (RuntimeException e) {
    253                 if (msg.what != RELEASE && mCamera != null) {
    254                     try {
    255                         mCamera.release();
    256                     } catch (Exception ex) {
    257                         Log.e(TAG, "Fail to release the camera.");
    258                     }
    259                     mCamera = null;
    260                     mCameraProxy = null;
    261                 }
    262                 throw e;
    263             }
    264             mSig.open();
    265         }
    266     }
    267 
    268     @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
    269     private void setAutoFocusMoveCallback(android.hardware.Camera camera,
    270             Object cb) {
    271         camera.setAutoFocusMoveCallback((AutoFocusMoveCallback) cb);
    272     }
    273 
    274     // Open camera synchronously. This method is invoked in the context of a
    275     // background thread.
    276     CameraProxy cameraOpen(int cameraId) {
    277         // Cannot open camera in mCameraHandler, otherwise all camera events
    278         // will be routed to mCameraHandler looper, which in turn will call
    279         // event handler like Camera.onFaceDetection, which in turn will modify
    280         // UI and cause exception like this:
    281         // CalledFromWrongThreadException: Only the original thread that created
    282         // a view hierarchy can touch its views.
    283         mCamera = android.hardware.Camera.open(cameraId);
    284         if (mCamera != null) {
    285             mCameraProxy = new CameraProxy();
    286             return mCameraProxy;
    287         } else {
    288             return null;
    289         }
    290     }
    291 
    292     public class CameraProxy {
    293         private CameraProxy() {
    294             Assert(mCamera != null);
    295         }
    296 
    297         public android.hardware.Camera getCamera() {
    298             return mCamera;
    299         }
    300 
    301         public void release() {
    302             mSig.close();
    303             mCameraHandler.sendEmptyMessage(RELEASE);
    304             mSig.block();
    305         }
    306 
    307         public void reconnect() throws IOException {
    308             mSig.close();
    309             mCameraHandler.sendEmptyMessage(RECONNECT);
    310             mSig.block();
    311             if (mReconnectException != null) {
    312                 throw mReconnectException;
    313             }
    314         }
    315 
    316         public void unlock() {
    317             mSig.close();
    318             mCameraHandler.sendEmptyMessage(UNLOCK);
    319             mSig.block();
    320         }
    321 
    322         public void lock() {
    323             mSig.close();
    324             mCameraHandler.sendEmptyMessage(LOCK);
    325             mSig.block();
    326         }
    327 
    328         @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
    329         public void setPreviewTextureAsync(final SurfaceTexture surfaceTexture) {
    330             mCameraHandler.obtainMessage(SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture).sendToTarget();
    331         }
    332 
    333         public void setPreviewDisplayAsync(final SurfaceHolder surfaceHolder) {
    334             mCameraHandler.obtainMessage(SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder).sendToTarget();
    335         }
    336 
    337         public void startPreviewAsync() {
    338             mCameraHandler.sendEmptyMessage(START_PREVIEW_ASYNC);
    339         }
    340 
    341         public void stopPreview() {
    342             mSig.close();
    343             mCameraHandler.sendEmptyMessage(STOP_PREVIEW);
    344             mSig.block();
    345         }
    346 
    347         public void setPreviewCallback(final PreviewCallback cb) {
    348             mSig.close();
    349             mCameraHandler.obtainMessage(SET_PREVIEW_CALLBACK, cb).sendToTarget();
    350             mSig.block();
    351         }
    352 
    353         public void setPreviewCallbackWithBuffer(final PreviewCallback cb) {
    354             mSig.close();
    355             mCameraHandler.obtainMessage(SET_PREVIEW_CALLBACK_WITH_BUFFER, cb).sendToTarget();
    356             mSig.block();
    357         }
    358 
    359         public void addCallbackBuffer(byte[] callbackBuffer) {
    360             mSig.close();
    361             mCameraHandler.obtainMessage(ADD_CALLBACK_BUFFER, callbackBuffer).sendToTarget();
    362             mSig.block();
    363         }
    364 
    365         public void autoFocus(AutoFocusCallback cb) {
    366             mSig.close();
    367             mCameraHandler.obtainMessage(AUTO_FOCUS, cb).sendToTarget();
    368             mSig.block();
    369         }
    370 
    371         public void cancelAutoFocus() {
    372             mSig.close();
    373             mCameraHandler.sendEmptyMessage(CANCEL_AUTO_FOCUS);
    374             mSig.block();
    375         }
    376 
    377         @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
    378         public void setAutoFocusMoveCallback(AutoFocusMoveCallback cb) {
    379             mSig.close();
    380             mCameraHandler.obtainMessage(SET_AUTO_FOCUS_MOVE_CALLBACK, cb).sendToTarget();
    381             mSig.block();
    382         }
    383 
    384         public void takePicture(final ShutterCallback shutter, final PictureCallback raw,
    385                 final PictureCallback postview, final PictureCallback jpeg) {
    386             mSig.close();
    387             // Too many parameters, so use post for simplicity
    388             mCameraHandler.post(new Runnable() {
    389                 @Override
    390                 public void run() {
    391                     mCamera.takePicture(shutter, raw, postview, jpeg);
    392                     mSig.open();
    393                 }
    394             });
    395             mSig.block();
    396         }
    397 
    398         public void takePicture2(final ShutterCallback shutter, final PictureCallback raw,
    399                 final PictureCallback postview, final PictureCallback jpeg,
    400                 final int cameraState, final int focusState) {
    401             mSig.close();
    402             // Too many parameters, so use post for simplicity
    403             mCameraHandler.post(new Runnable() {
    404                 @Override
    405                 public void run() {
    406                     try {
    407                         mCamera.takePicture(shutter, raw, postview, jpeg);
    408                     } catch (RuntimeException e) {
    409                         Log.w(TAG, "take picture failed; cameraState:" + cameraState
    410                             + ", focusState:" + focusState);
    411                         throw e;
    412                     }
    413                     mSig.open();
    414                 }
    415             });
    416             mSig.block();
    417         }
    418 
    419         public void setDisplayOrientation(int degrees) {
    420             mSig.close();
    421             mCameraHandler.obtainMessage(SET_DISPLAY_ORIENTATION, degrees, 0)
    422                     .sendToTarget();
    423             mSig.block();
    424         }
    425 
    426         public void setZoomChangeListener(OnZoomChangeListener listener) {
    427             mSig.close();
    428             mCameraHandler.obtainMessage(SET_ZOOM_CHANGE_LISTENER, listener).sendToTarget();
    429             mSig.block();
    430         }
    431 
    432         @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
    433         public void setFaceDetectionListener(FaceDetectionListener listener) {
    434             mSig.close();
    435             mCameraHandler.obtainMessage(SET_FACE_DETECTION_LISTENER, listener).sendToTarget();
    436             mSig.block();
    437         }
    438 
    439         public void startFaceDetection() {
    440             mSig.close();
    441             mCameraHandler.sendEmptyMessage(START_FACE_DETECTION);
    442             mSig.block();
    443         }
    444 
    445         public void stopFaceDetection() {
    446             mSig.close();
    447             mCameraHandler.sendEmptyMessage(STOP_FACE_DETECTION);
    448             mSig.block();
    449         }
    450 
    451         public void setErrorCallback(ErrorCallback cb) {
    452             mSig.close();
    453             mCameraHandler.obtainMessage(SET_ERROR_CALLBACK, cb).sendToTarget();
    454             mSig.block();
    455         }
    456 
    457         public void setParameters(Parameters params) {
    458             mSig.close();
    459             mCameraHandler.obtainMessage(SET_PARAMETERS, params).sendToTarget();
    460             mSig.block();
    461         }
    462 
    463         public void setParametersAsync(Parameters params) {
    464             mCameraHandler.removeMessages(SET_PARAMETERS_ASYNC);
    465             mCameraHandler.obtainMessage(SET_PARAMETERS_ASYNC, params).sendToTarget();
    466         }
    467 
    468         public Parameters getParameters() {
    469             mSig.close();
    470             mCameraHandler.sendEmptyMessage(GET_PARAMETERS);
    471             mSig.block();
    472             Parameters parameters = mParameters;
    473             mParameters = null;
    474             return parameters;
    475         }
    476 
    477         public void enableShutterSound(boolean enable) {
    478             mSig.close();
    479             mCameraHandler.obtainMessage(
    480                     ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0).sendToTarget();
    481             mSig.block();
    482         }
    483 
    484         public void waitForIdle() {
    485             mSig.close();
    486             mCameraHandler.sendEmptyMessage(WAIT_FOR_IDLE);
    487             mSig.block();
    488         }
    489     }
    490 }
    491