• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
instance()77     public static CameraManager instance() {
78         return sCameraManager;
79     }
80 
CameraManager()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 {
CameraHandler(Looper looper)88         CameraHandler(Looper looper) {
89             super(looper);
90         }
91 
92         @Override
handleMessage(final Message msg)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.
cameraOpen(int cameraId)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 {
CameraProxy()234         private CameraProxy() {
235             Assert(mCamera != null);
236         }
237 
getCamera()238         public android.hardware.Camera getCamera() {
239             return mCamera;
240         }
241 
release()242         public void release() {
243             mSig.close();
244             mCameraHandler.sendEmptyMessage(RELEASE);
245             mSig.block();
246         }
247 
reconnect()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 
unlock()257         public void unlock() {
258             mSig.close();
259             mCameraHandler.sendEmptyMessage(UNLOCK);
260             mSig.block();
261         }
262 
lock()263         public void lock() {
264             mSig.close();
265             mCameraHandler.sendEmptyMessage(LOCK);
266             mSig.block();
267         }
268 
setPreviewTextureAsync(final SurfaceTexture surfaceTexture)269         public void setPreviewTextureAsync(final SurfaceTexture surfaceTexture) {
270             mCameraHandler.obtainMessage(SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture).sendToTarget();
271         }
272 
startPreviewAsync()273         public void startPreviewAsync() {
274             mCameraHandler.sendEmptyMessage(START_PREVIEW_ASYNC);
275         }
276 
stopPreview()277         public void stopPreview() {
278             mSig.close();
279             mCameraHandler.sendEmptyMessage(STOP_PREVIEW);
280             mSig.block();
281         }
282 
setPreviewCallbackWithBuffer(final PreviewCallback cb)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 
addCallbackBuffer(byte[] callbackBuffer)289         public void addCallbackBuffer(byte[] callbackBuffer) {
290             mSig.close();
291             mCameraHandler.obtainMessage(ADD_CALLBACK_BUFFER, callbackBuffer).sendToTarget();
292             mSig.block();
293         }
294 
autoFocus(AutoFocusCallback cb)295         public void autoFocus(AutoFocusCallback cb) {
296             mSig.close();
297             mCameraHandler.obtainMessage(AUTO_FOCUS, cb).sendToTarget();
298             mSig.block();
299         }
300 
cancelAutoFocus()301         public void cancelAutoFocus() {
302             mSig.close();
303             mCameraHandler.sendEmptyMessage(CANCEL_AUTO_FOCUS);
304             mSig.block();
305         }
306 
setAutoFocusMoveCallback(AutoFocusMoveCallback cb)307         public void setAutoFocusMoveCallback(AutoFocusMoveCallback cb) {
308             mSig.close();
309             mCameraHandler.obtainMessage(SET_AUTO_FOCUS_MOVE_CALLBACK, cb).sendToTarget();
310             mSig.block();
311         }
312 
takePicture(final ShutterCallback shutter, final PictureCallback raw, final PictureCallback postview, final PictureCallback jpeg)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 
setDisplayOrientation(int degrees)327         public void setDisplayOrientation(int degrees) {
328             mSig.close();
329             mCameraHandler.obtainMessage(SET_DISPLAY_ORIENTATION, degrees, 0)
330                     .sendToTarget();
331             mSig.block();
332         }
333 
setZoomChangeListener(OnZoomChangeListener listener)334         public void setZoomChangeListener(OnZoomChangeListener listener) {
335             mSig.close();
336             mCameraHandler.obtainMessage(SET_ZOOM_CHANGE_LISTENER, listener).sendToTarget();
337             mSig.block();
338         }
339 
setFaceDetectionListener(FaceDetectionListener listener)340         public void setFaceDetectionListener(FaceDetectionListener listener) {
341             mSig.close();
342             mCameraHandler.obtainMessage(SET_FACE_DETECTION_LISTENER, listener).sendToTarget();
343             mSig.block();
344         }
345 
startFaceDetection()346         public void startFaceDetection() {
347             mSig.close();
348             mCameraHandler.sendEmptyMessage(START_FACE_DETECTION);
349             mSig.block();
350         }
351 
stopFaceDetection()352         public void stopFaceDetection() {
353             mSig.close();
354             mCameraHandler.sendEmptyMessage(STOP_FACE_DETECTION);
355             mSig.block();
356         }
357 
setErrorCallback(ErrorCallback cb)358         public void setErrorCallback(ErrorCallback cb) {
359             mSig.close();
360             mCameraHandler.obtainMessage(SET_ERROR_CALLBACK, cb).sendToTarget();
361             mSig.block();
362         }
363 
setParameters(Parameters params)364         public void setParameters(Parameters params) {
365             mSig.close();
366             mCameraHandler.obtainMessage(SET_PARAMETERS, params).sendToTarget();
367             mSig.block();
368         }
369 
setParametersAsync(Parameters params)370         public void setParametersAsync(Parameters params) {
371             mCameraHandler.removeMessages(SET_PARAMETERS_ASYNC);
372             mCameraHandler.obtainMessage(SET_PARAMETERS_ASYNC, params).sendToTarget();
373         }
374 
getParameters()375         public Parameters getParameters() {
376             mSig.close();
377             mCameraHandler.sendEmptyMessage(GET_PARAMETERS);
378             mSig.block();
379             return mParameters;
380         }
381 
waitForIdle()382         public void waitForIdle() {
383             mSig.close();
384             mCameraHandler.sendEmptyMessage(WAIT_FOR_IDLE);
385             mSig.block();
386         }
387     }
388 }
389