CameraAgent.java revision 25ee73acd2dbd6f60deef5306994fbf3a7997936
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.ex.camera2.portability;
18
19import android.annotation.TargetApi;
20import android.graphics.SurfaceTexture;
21import android.hardware.Camera;
22import android.hardware.Camera.OnZoomChangeListener;
23import android.os.Build;
24import android.os.Handler;
25import android.os.Looper;
26import android.view.SurfaceHolder;
27
28import com.android.ex.camera2.portability.debug.Log;
29
30/**
31 * An interface which provides possible camera device operations.
32 *
33 * The client should call {@code CameraAgent.openCamera} to get an instance
34 * of {@link CameraAgent.CameraProxy} to control the camera. Classes
35 * implementing this interface should have its own one unique {@code Thread}
36 * other than the main thread for camera operations. Camera device callbacks
37 * are wrapped since the client should not deal with
38 * {@code android.hardware.Camera} directly.
39 *
40 * TODO: provide callback interfaces for:
41 * {@code android.hardware.Camera.ErrorCallback},
42 * {@code android.hardware.Camera.OnZoomChangeListener}, and
43 */
44public abstract class CameraAgent {
45    public static final long CAMERA_OPERATION_TIMEOUT_MS = 2500;
46
47    private static final Log.Tag TAG = new Log.Tag("CamAgnt");
48
49    public static class CameraStartPreviewCallbackForward
50            implements CameraStartPreviewCallback {
51        private final Handler mHandler;
52        private final CameraStartPreviewCallback mCallback;
53
54        public static CameraStartPreviewCallbackForward getNewInstance(
55                Handler handler, CameraStartPreviewCallback cb) {
56            if (handler == null || cb == null) {
57                return null;
58            }
59            return new CameraStartPreviewCallbackForward(handler, cb);
60        }
61
62        private CameraStartPreviewCallbackForward(Handler h,
63                CameraStartPreviewCallback cb) {
64            mHandler = h;
65            mCallback = cb;
66        }
67
68        @Override
69        public void onPreviewStarted() {
70            mHandler.post(new Runnable() {
71                @Override
72                public void run() {
73                    mCallback.onPreviewStarted();
74                }});
75        }
76    }
77
78    /**
79     * A callback helps to invoke the original callback on another
80     * {@link android.os.Handler}.
81     */
82    public static class CameraOpenCallbackForward implements CameraOpenCallback {
83        private final Handler mHandler;
84        private final CameraOpenCallback mCallback;
85
86        /**
87         * Returns a new instance of {@link FaceDetectionCallbackForward}.
88         *
89         * @param handler The handler in which the callback will be invoked in.
90         * @param cb The callback to be invoked.
91         * @return The instance of the {@link FaceDetectionCallbackForward}, or
92         *         null if any parameter is null.
93         */
94        public static CameraOpenCallbackForward getNewInstance(
95                Handler handler, CameraOpenCallback cb) {
96            if (handler == null || cb == null) {
97                return null;
98            }
99            return new CameraOpenCallbackForward(handler, cb);
100        }
101
102        private CameraOpenCallbackForward(Handler h, CameraOpenCallback cb) {
103            // Given that we are using the main thread handler, we can create it
104            // here instead of holding onto the PhotoModule objects. In this
105            // way, we can avoid memory leak.
106            mHandler = new Handler(Looper.getMainLooper());
107            mCallback = cb;
108        }
109
110        @Override
111        public void onCameraOpened(final CameraProxy camera) {
112            mHandler.post(new Runnable() {
113                @Override
114                public void run() {
115                    mCallback.onCameraOpened(camera);
116                }});
117        }
118
119        @Override
120        public void onCameraDisabled(final int cameraId) {
121            mHandler.post(new Runnable() {
122                @Override
123                public void run() {
124                    mCallback.onCameraDisabled(cameraId);
125                }});
126        }
127
128        @Override
129        public void onDeviceOpenFailure(final int cameraId, final String info) {
130            mHandler.post(new Runnable() {
131                @Override
132                public void run() {
133                    mCallback.onDeviceOpenFailure(cameraId, info);
134                }});
135        }
136
137        @Override
138        public void onDeviceOpenedAlready(final int cameraId, final String info) {
139            mHandler.post(new Runnable() {
140                @Override
141                public void run() {
142                    mCallback.onDeviceOpenedAlready(cameraId, info);
143                }});
144        }
145
146        @Override
147        public void onReconnectionFailure(final CameraAgent mgr, final String info) {
148            mHandler.post(new Runnable() {
149                @Override
150                public void run() {
151                    mCallback.onReconnectionFailure(mgr, info);
152                }});
153        }
154    }
155
156    /**
157     * A handler for all camera api runtime exceptions.
158     * The default behavior is to throw the runtime exception.
159     */
160    public static interface CameraExceptionCallback {
161        public void onCameraException(RuntimeException e);
162    }
163
164    /**
165     * An interface which wraps
166     * {@link android.hardware.Camera.ErrorCallback}
167     */
168    public static interface CameraErrorCallback {
169        public void onError(int error, CameraProxy camera);
170    }
171
172    /**
173     * An interface which wraps
174     * {@link android.hardware.Camera.AutoFocusCallback}.
175     */
176    public static interface CameraAFCallback {
177        public void onAutoFocus(boolean focused, CameraProxy camera);
178    }
179
180    /**
181     * An interface which wraps
182     * {@link android.hardware.Camera.AutoFocusMoveCallback}.
183     */
184    public static interface CameraAFMoveCallback {
185        public void onAutoFocusMoving(boolean moving, CameraProxy camera);
186    }
187
188    /**
189     * An interface which wraps
190     * {@link android.hardware.Camera.ShutterCallback}.
191     */
192    public static interface CameraShutterCallback {
193        public void onShutter(CameraProxy camera);
194    }
195
196    /**
197     * An interface which wraps
198     * {@link android.hardware.Camera.PictureCallback}.
199     */
200    public static interface CameraPictureCallback {
201        public void onPictureTaken(byte[] data, CameraProxy camera);
202    }
203
204    /**
205     * An interface which wraps
206     * {@link android.hardware.Camera.PreviewCallback}.
207     */
208    public static interface CameraPreviewDataCallback {
209        public void onPreviewFrame(byte[] data, CameraProxy camera);
210    }
211
212    /**
213     * An interface which wraps
214     * {@link android.hardware.Camera.FaceDetectionListener}.
215     */
216    public static interface CameraFaceDetectionCallback {
217        /**
218         * Callback for face detection.
219         *
220         * @param faces   Recognized face in the preview.
221         * @param camera  The camera which the preview image comes from.
222         */
223        public void onFaceDetection(Camera.Face[] faces, CameraProxy camera);
224    }
225
226    /**
227     * An interface to be called when the camera preview has started.
228     */
229    public static interface CameraStartPreviewCallback {
230        /**
231         * Callback when the preview starts.
232         */
233        public void onPreviewStarted();
234    }
235
236    /**
237     * An interface to be called for any events when opening or closing the
238     * camera device. This error callback is different from the one defined
239     * in the framework, {@link android.hardware.Camera.ErrorCallback}, which
240     * is used after the camera is opened.
241     */
242    public static interface CameraOpenCallback {
243        /**
244         * Callback when camera open succeeds.
245         */
246        public void onCameraOpened(CameraProxy camera);
247
248        /**
249         * Callback when {@link com.android.camera.CameraDisabledException} is
250         * caught.
251         *
252         * @param cameraId The disabled camera.
253         */
254        public void onCameraDisabled(int cameraId);
255
256        /**
257         * Callback when {@link com.android.camera.CameraHardwareException} is
258         * caught.
259         *
260         * @param cameraId The camera with the hardware failure.
261         * @param info The extra info regarding this failure.
262         */
263        public void onDeviceOpenFailure(int cameraId, String info);
264
265        /**
266         * Callback when trying to open the camera which is already opened.
267         *
268         * @param cameraId The camera which is causing the open error.
269         */
270        public void onDeviceOpenedAlready(int cameraId, String info);
271
272        /**
273         * Callback when {@link java.io.IOException} is caught during
274         * {@link android.hardware.Camera#reconnect()}.
275         *
276         * @param mgr The {@link CameraAgent}
277         *            with the reconnect failure.
278         */
279        public void onReconnectionFailure(CameraAgent mgr, String info);
280    }
281
282    /**
283     * Opens the camera of the specified ID asynchronously. The camera device
284     * will be opened in the camera handler thread and will be returned through
285     * the {@link CameraAgent.CameraOpenCallback#
286     * onCameraOpened(com.android.camera.cameradevice.CameraAgent.CameraProxy)}.
287     *
288     * @param handler The {@link android.os.Handler} in which the callback
289     *                was handled.
290     * @param callback The callback for the result.
291     * @param cameraId The camera ID to open.
292     */
293    public void openCamera(final Handler handler, final int cameraId,
294                           final CameraOpenCallback callback) {
295        getDispatchThread().runJob(new Runnable() {
296            @Override
297            public void run() {
298                getCameraHandler().obtainMessage(CameraActions.OPEN_CAMERA, cameraId, 0,
299                        CameraOpenCallbackForward.getNewInstance(handler, callback)).sendToTarget();
300            }});
301    }
302
303    /**
304     * Closes the camera device.
305     *
306     * @param camera The camera to close. {@code null} means all.
307     * @param synced Whether this call should be synchronous.
308     */
309    public void closeCamera(CameraProxy camera, boolean synced) {
310        if (synced) {
311            final WaitDoneBundle bundle = new WaitDoneBundle();
312
313            getDispatchThread().runJobSync(new Runnable() {
314                @Override
315                public void run() {
316                    getCameraHandler().obtainMessage(CameraActions.RELEASE).sendToTarget();
317                    getCameraHandler().post(bundle.mUnlockRunnable);
318                }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "camera release");
319        } else {
320            getDispatchThread().runJob(new Runnable() {
321                @Override
322                public void run() {
323                    getCameraHandler().removeCallbacksAndMessages(null);
324                    getCameraHandler().obtainMessage(CameraActions.RELEASE).sendToTarget();
325                }});
326        }
327    }
328
329    /**
330     * Sets a callback for handling camera api runtime exceptions on
331     * a handler.
332     */
333    public abstract void setCameraDefaultExceptionCallback(CameraExceptionCallback callback,
334            Handler handler);
335
336    /**
337     * Recycles the resources used by this instance. CameraAgent will be in
338     * an unusable state after calling this.
339     */
340    public abstract void recycle();
341
342    /**
343     * @return The camera devices info.
344     */
345    public abstract CameraDeviceInfo getCameraDeviceInfo();
346
347    /**
348     * @return The handler to which camera tasks should be posted.
349     */
350    protected abstract Handler getCameraHandler();
351
352    /**
353     * @return The thread used on which client callbacks are served.
354     */
355    protected abstract DispatchThread getDispatchThread();
356
357    /**
358     * An interface that takes camera operation requests and post messages to the
359     * camera handler thread. All camera operations made through this interface is
360     * asynchronous by default except those mentioned specifically.
361     */
362    public static abstract class CameraProxy {
363
364        /**
365         * Returns the underlying {@link android.hardware.Camera} object used
366         * by this proxy. This method should only be used when handing the
367         * camera device over to {@link android.media.MediaRecorder} for
368         * recording.
369         */
370        @Deprecated
371        public abstract android.hardware.Camera getCamera();
372
373        /**
374         * @return The camera ID associated to by this
375         * {@link CameraAgent.CameraProxy}.
376         */
377        public abstract int getCameraId();
378
379        /**
380         * @return The camera characteristics.
381         */
382        public abstract CameraDeviceInfo.Characteristics getCharacteristics();
383
384        /**
385         * @return The camera capabilities.
386         */
387        public abstract CameraCapabilities getCapabilities();
388
389        /**
390         * Reconnects to the camera device. On success, the camera device will
391         * be returned through {@link CameraAgent
392         * .CameraOpenCallback#onCameraOpened(com.android.camera.cameradevice.CameraAgent
393         * .CameraProxy)}.
394         * @see android.hardware.Camera#reconnect()
395         *
396         * @param handler The {@link android.os.Handler} in which the callback
397         *                was handled.
398         * @param cb The callback when any error happens.
399         */
400        public void reconnect(final Handler handler, final CameraOpenCallback cb) {
401            getDispatchThread().runJob(new Runnable() {
402                @Override
403                public void run() {
404                    getCameraHandler().obtainMessage(CameraActions.RECONNECT, getCameraId(), 0,
405                            CameraOpenCallbackForward.getNewInstance(handler, cb)).sendToTarget();
406                }});
407        }
408
409        /**
410         * Unlocks the camera device.
411         *
412         * @see android.hardware.Camera#unlock()
413         */
414        public void unlock() {
415            final WaitDoneBundle bundle = new WaitDoneBundle();
416            getDispatchThread().runJobSync(new Runnable() {
417                @Override
418                public void run() {
419                    getCameraHandler().sendEmptyMessage(CameraActions.UNLOCK);
420                    getCameraHandler().post(bundle.mUnlockRunnable);
421                }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "camera unlock");
422        }
423
424        /**
425         * Locks the camera device.
426         * @see android.hardware.Camera#lock()
427         */
428        public void lock() {
429            getDispatchThread().runJob(new Runnable() {
430                @Override
431                public void run() {
432                    getCameraHandler().sendEmptyMessage(CameraActions.LOCK);
433                }});
434        }
435
436        /**
437         * Sets the {@link android.graphics.SurfaceTexture} for preview.
438         *
439         * <p>Note that, once this operation has been performed, it is no longer
440         * possible to change the preview or photo sizes in the
441         * {@link CameraSettings} instance for this camera, and the mutators for
442         * these fields are allowed to ignore all further invocations until the
443         * preview is stopped with {@link #stopPreview}.</p>
444         *
445         * @param surfaceTexture The {@link SurfaceTexture} for preview.
446         *
447         * @see CameraSettings#setPhotoSize
448         * @see CameraSettings#setPreviewSize
449         */
450        // XXX: Despite the above documentation about locking the sizes, the API
451        // 1 implementation doesn't currently enforce this at all, although the
452        // Camera class warns that preview sizes shouldn't be changed while a
453        // preview is running. Furthermore, the API 2 implementation doesn't yet
454        // unlock the sizes when stopPreview() is invoked (see related FIXME on
455        // the STOP_PREVIEW case in its handler; in the meantime, changing API 2
456        // sizes would require closing and reopening the camera.
457        public void setPreviewTexture(final SurfaceTexture surfaceTexture) {
458            getDispatchThread().runJob(new Runnable() {
459                @Override
460                public void run() {
461                    getCameraHandler()
462                            .obtainMessage(CameraActions.SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture)
463                            .sendToTarget();
464                }});
465        }
466
467        /**
468         * Blocks until a {@link android.graphics.SurfaceTexture} has been set
469         * for preview.
470         *
471         * <p>Note that, once this operation has been performed, it is no longer
472         * possible to change the preview or photo sizes in the
473         * {@link CameraSettings} instance for this camera, and the mutators for
474         * these fields are allowed to ignore all further invocations.</p>
475         *
476         * @param surfaceTexture The {@link SurfaceTexture} for preview.
477         *
478         * @see CameraSettings#setPhotoSize
479         * @see CameraSettings#setPreviewSize
480         */
481        public void setPreviewTextureSync(final SurfaceTexture surfaceTexture) {
482            final WaitDoneBundle bundle = new WaitDoneBundle();
483            getDispatchThread().runJobSync(new Runnable() {
484                @Override
485                public void run() {
486                    getCameraHandler()
487                            .obtainMessage(CameraActions.SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture)
488                            .sendToTarget();
489                    getCameraHandler().post(bundle.mUnlockRunnable);
490                }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "set preview texture");
491        }
492
493        /**
494         * Sets the {@link android.view.SurfaceHolder} for preview.
495         *
496         * @param surfaceHolder The {@link SurfaceHolder} for preview.
497         */
498        public void setPreviewDisplay(final SurfaceHolder surfaceHolder) {
499            getDispatchThread().runJob(new Runnable() {
500                @Override
501                public void run() {
502                    getCameraHandler()
503                            .obtainMessage(CameraActions.SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder)
504                            .sendToTarget();
505                }});
506        }
507
508        /**
509         * Starts the camera preview.
510         */
511        public void startPreview() {
512            getDispatchThread().runJob(new Runnable() {
513                @Override
514                public void run() {
515                    getCameraHandler()
516                            .obtainMessage(CameraActions.START_PREVIEW_ASYNC, null).sendToTarget();
517                }});
518        }
519
520        /**
521         * Starts the camera preview and executes a callback on a handler once
522         * the preview starts.
523         */
524        public void startPreviewWithCallback(final Handler h, final CameraStartPreviewCallback cb) {
525            getDispatchThread().runJob(new Runnable() {
526                @Override
527                public void run() {
528                    getCameraHandler().obtainMessage(CameraActions.START_PREVIEW_ASYNC,
529                            CameraStartPreviewCallbackForward.getNewInstance(h, cb))
530                                    .sendToTarget();
531                }});
532        }
533
534        /**
535         * Stops the camera preview synchronously.
536         * {@code stopPreview()} must be synchronous to ensure that the caller can
537         * continues to release resources related to camera preview.
538         */
539        public void stopPreview() {
540            final WaitDoneBundle bundle = new WaitDoneBundle();
541            getDispatchThread().runJobSync(new Runnable() {
542                @Override
543                public void run() {
544                    getCameraHandler().sendEmptyMessage(CameraActions.STOP_PREVIEW);
545                    getCameraHandler().post(bundle.mUnlockRunnable);
546                }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "stop preview");
547        }
548
549        /**
550         * Sets the callback for preview data.
551         *
552         * @param handler    The {@link android.os.Handler} in which the callback was handled.
553         * @param cb         The callback to be invoked when the preview data is available.
554         * @see  android.hardware.Camera#setPreviewCallback(android.hardware.Camera.PreviewCallback)
555         */
556        public abstract void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb);
557
558        /**
559         * Sets the one-time callback for preview data.
560         *
561         * @param handler    The {@link android.os.Handler} in which the callback was handled.
562         * @param cb         The callback to be invoked when the preview data for
563         *                   next frame is available.
564         * @see  android.hardware.Camera#setPreviewCallback(android.hardware.Camera.PreviewCallback)
565         */
566        public abstract void setOneShotPreviewCallback(Handler handler,
567                                                       CameraPreviewDataCallback cb);
568
569        /**
570         * Sets the callback for preview data.
571         *
572         * @param handler The handler in which the callback will be invoked.
573         * @param cb      The callback to be invoked when the preview data is available.
574         * @see android.hardware.Camera#setPreviewCallbackWithBuffer(android.hardware.Camera.PreviewCallback)
575         */
576        public abstract void setPreviewDataCallbackWithBuffer(Handler handler,
577                                                              CameraPreviewDataCallback cb);
578
579        /**
580         * Adds buffer for the preview callback.
581         *
582         * @param callbackBuffer The buffer allocated for the preview data.
583         */
584        public void addCallbackBuffer(final byte[] callbackBuffer) {
585            getDispatchThread().runJob(new Runnable() {
586                @Override
587                public void run() {
588                    getCameraHandler()
589                            .obtainMessage(CameraActions.ADD_CALLBACK_BUFFER, callbackBuffer)
590                            .sendToTarget();
591                }
592            });
593        }
594
595        /**
596         * Starts the auto-focus process. The result will be returned through the callback.
597         *
598         * @param handler The handler in which the callback will be invoked.
599         * @param cb      The auto-focus callback.
600         */
601        public abstract void autoFocus(Handler handler, CameraAFCallback cb);
602
603        /**
604         * Cancels the auto-focus process.
605         */
606        public void cancelAutoFocus() {
607            getDispatchThread().runJob(new Runnable() {
608                @Override
609                public void run() {
610                    getCameraHandler().removeMessages(CameraActions.AUTO_FOCUS);
611                    getCameraHandler().sendEmptyMessage(CameraActions.CANCEL_AUTO_FOCUS);
612                }});
613        }
614
615        /**
616         * Sets the auto-focus callback
617         *
618         * @param handler The handler in which the callback will be invoked.
619         * @param cb      The callback to be invoked when the preview data is available.
620         */
621        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
622        public abstract void setAutoFocusMoveCallback(Handler handler, CameraAFMoveCallback cb);
623
624        /**
625         * Instrument the camera to take a picture.
626         *
627         * @param handler   The handler in which the callback will be invoked.
628         * @param shutter   The callback for shutter action, may be null.
629         * @param raw       The callback for uncompressed data, may be null.
630         * @param postview  The callback for postview image data, may be null.
631         * @param jpeg      The callback for jpeg image data, may be null.
632         * @see android.hardware.Camera#takePicture(
633         *         android.hardware.Camera.ShutterCallback,
634         *         android.hardware.Camera.PictureCallback,
635         *         android.hardware.Camera.PictureCallback)
636         */
637        public abstract void takePicture(
638                Handler handler,
639                CameraShutterCallback shutter,
640                CameraPictureCallback raw,
641                CameraPictureCallback postview,
642                CameraPictureCallback jpeg);
643
644        /**
645         * Sets the display orientation for camera to adjust the preview and JPEG orientation.
646         *
647         * @param degrees The counterclockwise rotation in degrees, relative to the device's natural
648         *                orientation. Should be 0, 90, 180 or 270.
649         */
650        public void setDisplayOrientation(final int degrees) {
651            setDisplayOrientation(degrees, true);
652        }
653
654        /**
655         * Sets the display orientation for camera to adjust the preview&mdash;and, optionally,
656         * JPEG&mdash;orientations.
657         * <p>If capture rotation is not requested, future captures will be returned in the sensor's
658         * physical rotation, which does not necessarily match the device's natural orientation.</p>
659         *
660         * @param degrees The counterclockwise rotation in degrees, relative to the device's natural
661         *                orientation. Should be 0, 90, 180 or 270.
662         * @param capture Whether to adjust the JPEG capture orientation as well as the preview one.
663         */
664        public void setDisplayOrientation(final int degrees, final boolean capture) {
665            getDispatchThread().runJob(new Runnable() {
666                @Override
667                public void run() {
668                    getCameraHandler()
669                            .obtainMessage(CameraActions.SET_DISPLAY_ORIENTATION, degrees,
670                                    capture ? 1 : 0)
671                            .sendToTarget();
672                }});
673        }
674
675        public void setJpegOrientation(final int degrees) {
676            getDispatchThread().runJob(new Runnable() {
677                @Override
678                public void run() {
679                    getCameraHandler()
680                            .obtainMessage(CameraActions.SET_JPEG_ORIENTATION, degrees, 0)
681                            .sendToTarget();
682                }});
683        }
684
685        /**
686         * Sets the listener for zoom change.
687         *
688         * @param listener The listener.
689         */
690        public abstract void setZoomChangeListener(OnZoomChangeListener listener);
691
692        /**
693         * Sets the face detection listener.
694         *
695         * @param handler  The handler in which the callback will be invoked.
696         * @param callback The callback for face detection results.
697         */
698        public abstract void setFaceDetectionCallback(Handler handler,
699                                                      CameraFaceDetectionCallback callback);
700
701        /**
702         * Starts the face detection.
703         */
704        public void startFaceDetection() {
705            getDispatchThread().runJob(new Runnable() {
706                @Override
707                public void run() {
708                    getCameraHandler().sendEmptyMessage(CameraActions.START_FACE_DETECTION);
709                }});
710        }
711
712        /**
713         * Stops the face detection.
714         */
715        public void stopFaceDetection() {
716            getDispatchThread().runJob(new Runnable() {
717                @Override
718                public void run() {
719                    getCameraHandler().sendEmptyMessage(CameraActions.STOP_FACE_DETECTION);
720                }});
721        }
722
723        /**
724         * Registers an error callback.
725         *
726         * @param handler  The handler on which the callback will be invoked.
727         * @param cb The error callback.
728         * @see android.hardware.Camera#setErrorCallback(android.hardware.Camera.ErrorCallback)
729         */
730        public abstract void setErrorCallback(Handler handler, CameraErrorCallback cb);
731
732        /**
733         * Sets the camera parameters.
734         *
735         * @param params The camera parameters to use.
736         */
737        @Deprecated
738        public abstract void setParameters(Camera.Parameters params);
739
740        /**
741         * Gets the current camera parameters synchronously. This method is
742         * synchronous since the caller has to wait for the camera to return
743         * the parameters. If the parameters are already cached, it returns
744         * immediately.
745         */
746        @Deprecated
747        public abstract Camera.Parameters getParameters();
748
749        /**
750         * Gets the current camera settings synchronously.
751         * <p>This method is synchronous since the caller has to wait for the
752         * camera to return the parameters. If the parameters are already
753         * cached, it returns immediately.</p>
754         */
755        public abstract CameraSettings getSettings();
756
757        /**
758         * Default implementation of {@link #applySettings(CameraSettings)}
759         * that is only missing the set of states it needs to wait for
760         * before applying the settings.
761         *
762         * @param settings The settings to use on the device.
763         * @param statesToAwait Bitwise OR of the required camera states.
764         * @return Whether the settings can be applied.
765         */
766        protected boolean applySettingsHelper(CameraSettings settings,
767                                              final int statesToAwait) {
768            if (settings == null) {
769                Log.v(TAG, "null argument in applySettings()");
770                return false;
771            }
772            if (!getCapabilities().supports(settings)) {
773                Log.w(TAG, "Unsupported settings in applySettings()");
774                return false;
775            }
776
777            final CameraSettings copyOfSettings = settings.copy();
778            getDispatchThread().runJob(new Runnable() {
779                @Override
780                public void run() {
781                    getCameraState().waitForStates(statesToAwait);
782                    getCameraHandler().obtainMessage(CameraActions.APPLY_SETTINGS, copyOfSettings)
783                            .sendToTarget();
784                }});
785            return true;
786        }
787
788        /**
789         * Applies the settings to the camera device.
790         *
791         * @param settings The settings to use on the device.
792         * @return Whether the settings can be applied.
793         */
794        public abstract boolean applySettings(CameraSettings settings);
795
796        /**
797         * Forces {@code CameraProxy} to update the cached version of the camera
798         * settings regardless of the dirty bit.
799         */
800        public void refreshSettings() {
801            getDispatchThread().runJob(new Runnable() {
802                @Override
803                public void run() {
804                    getCameraHandler().sendEmptyMessage(CameraActions.REFRESH_PARAMETERS);
805                }});
806        }
807
808        /**
809         * Enables/Disables the camera shutter sound.
810         *
811         * @param enable   {@code true} to enable the shutter sound,
812         *                 {@code false} to disable it.
813         */
814        public void enableShutterSound(final boolean enable) {
815            getDispatchThread().runJob(new Runnable() {
816                @Override
817                public void run() {
818                    getCameraHandler()
819                            .obtainMessage(CameraActions.ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0)
820                            .sendToTarget();
821                }});
822        }
823
824        /**
825         * Dumps the current settings of the camera device.
826         *
827         * <p>The content varies based on the underlying camera API settings
828         * implementation.</p>
829         *
830         * @return The content of the device settings represented by a string.
831         */
832        public abstract String dumpDeviceSettings();
833
834        /**
835         * @return The handler to which camera tasks should be posted.
836         */
837        public abstract Handler getCameraHandler();
838
839        /**
840         * @return The thread used on which client callbacks are served.
841         */
842        public abstract DispatchThread getDispatchThread();
843
844        /**
845         * @return The state machine tracking the camera API's current mode.
846         */
847        public abstract CameraStateHolder getCameraState();
848    }
849
850    public static class WaitDoneBundle {
851        public final Runnable mUnlockRunnable;
852        public final Object mWaitLock;
853
854        WaitDoneBundle() {
855            mWaitLock = new Object();
856            mUnlockRunnable = new Runnable() {
857                @Override
858                public void run() {
859                    synchronized (mWaitLock) {
860                        mWaitLock.notifyAll();
861                    }
862                }};
863        }
864    }
865}
866