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.graphics.SurfaceTexture;
     22 import android.hardware.Camera.AutoFocusCallback;
     23 import android.hardware.Camera.AutoFocusMoveCallback;
     24 import android.hardware.Camera.ErrorCallback;
     25 import android.hardware.Camera.FaceDetectionListener;
     26 import android.hardware.Camera.OnZoomChangeListener;
     27 import android.hardware.Camera.Parameters;
     28 import android.hardware.Camera.PictureCallback;
     29 import android.hardware.Camera.PreviewCallback;
     30 import android.hardware.Camera.ShutterCallback;
     31 import android.os.ConditionVariable;
     32 import android.os.Handler;
     33 import android.os.HandlerThread;
     34 import android.os.Looper;
     35 import android.os.Message;
     36 import android.util.Log;
     37 
     38 import java.io.IOException;
     39 
     40 public class CameraManager {
     41     private static final String TAG = "CameraManager";
     42     private static CameraManager sCameraManager = new CameraManager();
     43 
     44     // Thread progress signals
     45     private ConditionVariable mSig = new ConditionVariable();
     46 
     47     private Parameters mParameters;
     48     private IOException mReconnectException;
     49 
     50     private static final int RELEASE = 1;
     51     private static final int RECONNECT = 2;
     52     private static final int UNLOCK = 3;
     53     private static final int LOCK = 4;
     54     private static final int SET_PREVIEW_TEXTURE_ASYNC = 5;
     55     private static final int START_PREVIEW_ASYNC = 6;
     56     private static final int STOP_PREVIEW = 7;
     57     private static final int SET_PREVIEW_CALLBACK_WITH_BUFFER = 8;
     58     private static final int ADD_CALLBACK_BUFFER = 9;
     59     private static final int AUTO_FOCUS = 10;
     60     private static final int CANCEL_AUTO_FOCUS = 11;
     61     private static final int SET_AUTO_FOCUS_MOVE_CALLBACK = 12;
     62     private static final int SET_DISPLAY_ORIENTATION = 13;
     63     private static final int SET_ZOOM_CHANGE_LISTENER = 14;
     64     private static final int SET_FACE_DETECTION_LISTENER = 15;
     65     private static final int START_FACE_DETECTION = 16;
     66     private static final int STOP_FACE_DETECTION = 17;
     67     private static final int SET_ERROR_CALLBACK = 18;
     68     private static final int SET_PARAMETERS = 19;
     69     private static final int GET_PARAMETERS = 20;
     70     private static final int SET_PARAMETERS_ASYNC = 21;
     71     private static final int WAIT_FOR_IDLE = 22;
     72 
     73     private Handler mCameraHandler;
     74     private CameraProxy mCameraProxy;
     75     private android.hardware.Camera mCamera;
     76 
     77     public static CameraManager instance() {
     78         return sCameraManager;
     79     }
     80 
     81     private CameraManager() {
     82         HandlerThread ht = new HandlerThread("Camera Handler Thread");
     83         ht.start();
     84         mCameraHandler = new CameraHandler(ht.getLooper());
     85     }
     86 
     87     private class CameraHandler extends Handler {
     88         CameraHandler(Looper looper) {
     89             super(looper);
     90         }
     91 
     92         @Override
     93         public void handleMessage(final Message msg) {
     94             try {
     95                 switch (msg.what) {
     96                     case RELEASE:
     97                         mCamera.release();
     98                         mCamera = null;
     99                         mCameraProxy = null;
    100                         break;
    101 
    102                     case RECONNECT:
    103                         mReconnectException = null;
    104                         try {
    105                             mCamera.reconnect();
    106                         } catch (IOException ex) {
    107                             mReconnectException = ex;
    108                         }
    109                         break;
    110 
    111                     case UNLOCK:
    112                         mCamera.unlock();
    113                         break;
    114 
    115                     case LOCK:
    116                         mCamera.lock();
    117                         break;
    118 
    119                     case SET_PREVIEW_TEXTURE_ASYNC:
    120                         try {
    121                             mCamera.setPreviewTexture((SurfaceTexture) msg.obj);
    122                         } catch(IOException e) {
    123                             throw new RuntimeException(e);
    124                         }
    125                         return;  // no need to call mSig.open()
    126 
    127                     case START_PREVIEW_ASYNC:
    128                         mCamera.startPreview();
    129                         return;  // no need to call mSig.open()
    130 
    131                     case STOP_PREVIEW:
    132                         mCamera.stopPreview();
    133                         break;
    134 
    135                     case SET_PREVIEW_CALLBACK_WITH_BUFFER:
    136                         mCamera.setPreviewCallbackWithBuffer(
    137                             (PreviewCallback) msg.obj);
    138                         break;
    139 
    140                     case ADD_CALLBACK_BUFFER:
    141                         mCamera.addCallbackBuffer((byte[]) msg.obj);
    142                         break;
    143 
    144                     case AUTO_FOCUS:
    145                         mCamera.autoFocus((AutoFocusCallback) msg.obj);
    146                         break;
    147 
    148                     case CANCEL_AUTO_FOCUS:
    149                         mCamera.cancelAutoFocus();
    150                         break;
    151 
    152                     case SET_AUTO_FOCUS_MOVE_CALLBACK:
    153                         mCamera.setAutoFocusMoveCallback(
    154                             (AutoFocusMoveCallback) msg.obj);
    155                         break;
    156 
    157                     case SET_DISPLAY_ORIENTATION:
    158                         mCamera.setDisplayOrientation(msg.arg1);
    159                         break;
    160 
    161                     case SET_ZOOM_CHANGE_LISTENER:
    162                         mCamera.setZoomChangeListener(
    163                             (OnZoomChangeListener) msg.obj);
    164                         break;
    165 
    166                     case SET_FACE_DETECTION_LISTENER:
    167                         mCamera.setFaceDetectionListener(
    168                             (FaceDetectionListener) msg.obj);
    169                         break;
    170 
    171                     case START_FACE_DETECTION:
    172                         mCamera.startFaceDetection();
    173                         break;
    174 
    175                     case STOP_FACE_DETECTION:
    176                         mCamera.stopFaceDetection();
    177                         break;
    178 
    179                     case SET_ERROR_CALLBACK:
    180                         mCamera.setErrorCallback((ErrorCallback) msg.obj);
    181                         break;
    182 
    183                     case SET_PARAMETERS:
    184                         mCamera.setParameters((Parameters) msg.obj);
    185                         break;
    186 
    187                     case GET_PARAMETERS:
    188                         mParameters = mCamera.getParameters();
    189                         break;
    190 
    191                     case SET_PARAMETERS_ASYNC:
    192                         mCamera.setParameters((Parameters) msg.obj);
    193                         return;  // no need to call mSig.open()
    194 
    195                     case WAIT_FOR_IDLE:
    196                         // do nothing
    197                         break;
    198                 }
    199             } catch (RuntimeException e) {
    200                 if (msg.what != RELEASE && mCamera != null) {
    201                     try {
    202                         mCamera.release();
    203                     } catch (Exception ex) {
    204                         Log.e(TAG, "Fail to release the camera.");
    205                     }
    206                     mCamera = null;
    207                     mCameraProxy = null;
    208                 }
    209                 throw e;
    210             }
    211             mSig.open();
    212         }
    213     }
    214 
    215     // Open camera synchronously. This method is invoked in the context of a
    216     // background thread.
    217     CameraProxy cameraOpen(int cameraId) {
    218         // Cannot open camera in mCameraHandler, otherwise all camera events
    219         // will be routed to mCameraHandler looper, which in turn will call
    220         // event handler like Camera.onFaceDetection, which in turn will modify
    221         // UI and cause exception like this:
    222         // CalledFromWrongThreadException: Only the original thread that created
    223         // a view hierarchy can touch its views.
    224         mCamera = android.hardware.Camera.open(cameraId);
    225         if (mCamera != null) {
    226             mCameraProxy = new CameraProxy();
    227             return mCameraProxy;
    228         } else {
    229             return null;
    230         }
    231     }
    232 
    233     public class CameraProxy {
    234         private CameraProxy() {
    235             Assert(mCamera != null);
    236         }
    237 
    238         public android.hardware.Camera getCamera() {
    239             return mCamera;
    240         }
    241 
    242         public void release() {
    243             mSig.close();
    244             mCameraHandler.sendEmptyMessage(RELEASE);
    245             mSig.block();
    246         }
    247 
    248         public void reconnect() throws IOException {
    249             mSig.close();
    250             mCameraHandler.sendEmptyMessage(RECONNECT);
    251             mSig.block();
    252             if (mReconnectException != null) {
    253                 throw mReconnectException;
    254             }
    255         }
    256 
    257         public void unlock() {
    258             mSig.close();
    259             mCameraHandler.sendEmptyMessage(UNLOCK);
    260             mSig.block();
    261         }
    262 
    263         public void lock() {
    264             mSig.close();
    265             mCameraHandler.sendEmptyMessage(LOCK);
    266             mSig.block();
    267         }
    268 
    269         public void setPreviewTextureAsync(final SurfaceTexture surfaceTexture) {
    270             mCameraHandler.obtainMessage(SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture).sendToTarget();
    271         }
    272 
    273         public void startPreviewAsync() {
    274             mCameraHandler.sendEmptyMessage(START_PREVIEW_ASYNC);
    275         }
    276 
    277         public void stopPreview() {
    278             mSig.close();
    279             mCameraHandler.sendEmptyMessage(STOP_PREVIEW);
    280             mSig.block();
    281         }
    282 
    283         public void setPreviewCallbackWithBuffer(final PreviewCallback cb) {
    284             mSig.close();
    285             mCameraHandler.obtainMessage(SET_PREVIEW_CALLBACK_WITH_BUFFER, cb).sendToTarget();
    286             mSig.block();
    287         }
    288 
    289         public void addCallbackBuffer(byte[] callbackBuffer) {
    290             mSig.close();
    291             mCameraHandler.obtainMessage(ADD_CALLBACK_BUFFER, callbackBuffer).sendToTarget();
    292             mSig.block();
    293         }
    294 
    295         public void autoFocus(AutoFocusCallback cb) {
    296             mSig.close();
    297             mCameraHandler.obtainMessage(AUTO_FOCUS, cb).sendToTarget();
    298             mSig.block();
    299         }
    300 
    301         public void cancelAutoFocus() {
    302             mSig.close();
    303             mCameraHandler.sendEmptyMessage(CANCEL_AUTO_FOCUS);
    304             mSig.block();
    305         }
    306 
    307         public void setAutoFocusMoveCallback(AutoFocusMoveCallback cb) {
    308             mSig.close();
    309             mCameraHandler.obtainMessage(SET_AUTO_FOCUS_MOVE_CALLBACK, cb).sendToTarget();
    310             mSig.block();
    311         }
    312 
    313         public void takePicture(final ShutterCallback shutter, final PictureCallback raw,
    314                 final PictureCallback postview, final PictureCallback jpeg) {
    315             mSig.close();
    316             // Too many parameters, so use post for simplicity
    317             mCameraHandler.post(new Runnable() {
    318                 @Override
    319                 public void run() {
    320                     mCamera.takePicture(shutter, raw, postview, jpeg);
    321                     mSig.open();
    322                 }
    323             });
    324             mSig.block();
    325         }
    326 
    327         public void setDisplayOrientation(int degrees) {
    328             mSig.close();
    329             mCameraHandler.obtainMessage(SET_DISPLAY_ORIENTATION, degrees, 0)
    330                     .sendToTarget();
    331             mSig.block();
    332         }
    333 
    334         public void setZoomChangeListener(OnZoomChangeListener listener) {
    335             mSig.close();
    336             mCameraHandler.obtainMessage(SET_ZOOM_CHANGE_LISTENER, listener).sendToTarget();
    337             mSig.block();
    338         }
    339 
    340         public void setFaceDetectionListener(FaceDetectionListener listener) {
    341             mSig.close();
    342             mCameraHandler.obtainMessage(SET_FACE_DETECTION_LISTENER, listener).sendToTarget();
    343             mSig.block();
    344         }
    345 
    346         public void startFaceDetection() {
    347             mSig.close();
    348             mCameraHandler.sendEmptyMessage(START_FACE_DETECTION);
    349             mSig.block();
    350         }
    351 
    352         public void stopFaceDetection() {
    353             mSig.close();
    354             mCameraHandler.sendEmptyMessage(STOP_FACE_DETECTION);
    355             mSig.block();
    356         }
    357 
    358         public void setErrorCallback(ErrorCallback cb) {
    359             mSig.close();
    360             mCameraHandler.obtainMessage(SET_ERROR_CALLBACK, cb).sendToTarget();
    361             mSig.block();
    362         }
    363 
    364         public void setParameters(Parameters params) {
    365             mSig.close();
    366             mCameraHandler.obtainMessage(SET_PARAMETERS, params).sendToTarget();
    367             mSig.block();
    368         }
    369 
    370         public void setParametersAsync(Parameters params) {
    371             mCameraHandler.removeMessages(SET_PARAMETERS_ASYNC);
    372             mCameraHandler.obtainMessage(SET_PARAMETERS_ASYNC, params).sendToTarget();
    373         }
    374 
    375         public Parameters getParameters() {
    376             mSig.close();
    377             mCameraHandler.sendEmptyMessage(GET_PARAMETERS);
    378             mSig.block();
    379             return mParameters;
    380         }
    381 
    382         public void waitForIdle() {
    383             mSig.close();
    384             mCameraHandler.sendEmptyMessage(WAIT_FOR_IDLE);
    385             mSig.block();
    386         }
    387     }
    388 }
    389