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