CameraAgent.java revision 9d8668449376fa47bc6528c7a61b04d6a0f691b3
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         * @param surfaceTexture The {@link SurfaceTexture} for preview.
440         */
441        public void setPreviewTexture(final SurfaceTexture surfaceTexture) {
442            getDispatchThread().runJob(new Runnable() {
443                @Override
444                public void run() {
445                    getCameraHandler()
446                            .obtainMessage(CameraActions.SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture)
447                            .sendToTarget();
448                }});
449        }
450
451        /**
452         * Blocks until a {@link android.graphics.SurfaceTexture} has been set
453         * for preview.
454         *
455         * @param surfaceTexture The {@link SurfaceTexture} for preview.
456         */
457        public void setPreviewTextureSync(final SurfaceTexture surfaceTexture) {
458            final WaitDoneBundle bundle = new WaitDoneBundle();
459            getDispatchThread().runJobSync(new Runnable() {
460                @Override
461                public void run() {
462                    getCameraHandler()
463                            .obtainMessage(CameraActions.SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture)
464                            .sendToTarget();
465                    getCameraHandler().post(bundle.mUnlockRunnable);
466                }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "set preview texture");
467        }
468
469        /**
470         * Sets the {@link android.view.SurfaceHolder} for preview.
471         *
472         * @param surfaceHolder The {@link SurfaceHolder} for preview.
473         */
474        public void setPreviewDisplay(final SurfaceHolder surfaceHolder) {
475            getDispatchThread().runJob(new Runnable() {
476                @Override
477                public void run() {
478                    getCameraHandler()
479                            .obtainMessage(CameraActions.SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder)
480                            .sendToTarget();
481                }});
482        }
483
484        /**
485         * Starts the camera preview.
486         */
487        public void startPreview() {
488            getDispatchThread().runJob(new Runnable() {
489                @Override
490                public void run() {
491                    getCameraHandler()
492                            .obtainMessage(CameraActions.START_PREVIEW_ASYNC, null).sendToTarget();
493                }});
494        }
495
496        /**
497         * Starts the camera preview and executes a callback on a handler once
498         * the preview starts.
499         */
500        public void startPreviewWithCallback(final Handler h, final CameraStartPreviewCallback cb) {
501            getDispatchThread().runJob(new Runnable() {
502                @Override
503                public void run() {
504                    getCameraHandler().obtainMessage(CameraActions.START_PREVIEW_ASYNC,
505                            CameraStartPreviewCallbackForward.getNewInstance(h, cb))
506                                    .sendToTarget();
507                }});
508        }
509
510        /**
511         * Stops the camera preview synchronously.
512         * {@code stopPreview()} must be synchronous to ensure that the caller can
513         * continues to release resources related to camera preview.
514         */
515        public void stopPreview() {
516            final WaitDoneBundle bundle = new WaitDoneBundle();
517            getDispatchThread().runJobSync(new Runnable() {
518                @Override
519                public void run() {
520                    getCameraHandler().sendEmptyMessage(CameraActions.STOP_PREVIEW);
521                    getCameraHandler().post(bundle.mUnlockRunnable);
522                }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "stop preview");
523        }
524
525        /**
526         * Sets the callback for preview data.
527         *
528         * @param handler    The {@link android.os.Handler} in which the callback was handled.
529         * @param cb         The callback to be invoked when the preview data is available.
530         * @see  android.hardware.Camera#setPreviewCallback(android.hardware.Camera.PreviewCallback)
531         */
532        public abstract void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb);
533
534        /**
535         * Sets the one-time callback for preview data.
536         *
537         * @param handler    The {@link android.os.Handler} in which the callback was handled.
538         * @param cb         The callback to be invoked when the preview data for
539         *                   next frame is available.
540         * @see  android.hardware.Camera#setPreviewCallback(android.hardware.Camera.PreviewCallback)
541         */
542        public abstract void setOneShotPreviewCallback(Handler handler,
543                                                       CameraPreviewDataCallback cb);
544
545        /**
546         * Sets the callback for preview data.
547         *
548         * @param handler The handler in which the callback will be invoked.
549         * @param cb      The callback to be invoked when the preview data is available.
550         * @see android.hardware.Camera#setPreviewCallbackWithBuffer(android.hardware.Camera.PreviewCallback)
551         */
552        public abstract void setPreviewDataCallbackWithBuffer(Handler handler,
553                                                              CameraPreviewDataCallback cb);
554
555        /**
556         * Adds buffer for the preview callback.
557         *
558         * @param callbackBuffer The buffer allocated for the preview data.
559         */
560        public void addCallbackBuffer(final byte[] callbackBuffer) {
561            getDispatchThread().runJob(new Runnable() {
562                @Override
563                public void run() {
564                    getCameraHandler()
565                            .obtainMessage(CameraActions.ADD_CALLBACK_BUFFER, callbackBuffer)
566                            .sendToTarget();
567                }
568            });
569        }
570
571        /**
572         * Starts the auto-focus process. The result will be returned through the callback.
573         *
574         * @param handler The handler in which the callback will be invoked.
575         * @param cb      The auto-focus callback.
576         */
577        public abstract void autoFocus(Handler handler, CameraAFCallback cb);
578
579        /**
580         * Cancels the auto-focus process.
581         */
582        public void cancelAutoFocus() {
583            getDispatchThread().runJob(new Runnable() {
584                @Override
585                public void run() {
586                    getCameraHandler().removeMessages(CameraActions.AUTO_FOCUS);
587                    getCameraHandler().sendEmptyMessage(CameraActions.CANCEL_AUTO_FOCUS);
588                }});
589        }
590
591        /**
592         * Sets the auto-focus callback
593         *
594         * @param handler The handler in which the callback will be invoked.
595         * @param cb      The callback to be invoked when the preview data is available.
596         */
597        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
598        public abstract void setAutoFocusMoveCallback(Handler handler, CameraAFMoveCallback cb);
599
600        /**
601         * Instrument the camera to take a picture.
602         *
603         * @param handler   The handler in which the callback will be invoked.
604         * @param shutter   The callback for shutter action, may be null.
605         * @param raw       The callback for uncompressed data, may be null.
606         * @param postview  The callback for postview image data, may be null.
607         * @param jpeg      The callback for jpeg image data, may be null.
608         * @see android.hardware.Camera#takePicture(
609         *         android.hardware.Camera.ShutterCallback,
610         *         android.hardware.Camera.PictureCallback,
611         *         android.hardware.Camera.PictureCallback)
612         */
613        public abstract void takePicture(
614                Handler handler,
615                CameraShutterCallback shutter,
616                CameraPictureCallback raw,
617                CameraPictureCallback postview,
618                CameraPictureCallback jpeg);
619
620        /**
621         * Sets the display orientation for camera to adjust the preview and JPEG orientation.
622         *
623         * @param degrees The counterclockwise rotation in degrees, relative to the device's natural
624         *                orientation. Should be 0, 90, 180 or 270.
625         */
626        public void setDisplayOrientation(final int degrees) {
627            setDisplayOrientation(degrees, true);
628        }
629
630        /**
631         * Sets the display orientation for camera to adjust the preview—and, optionally,
632         * JPEG—orientations.
633         * <p>If capture rotation is not requested, future captures will be returned in the sensor's
634         * physical rotation, which does not necessarily match the device's natural orientation.</p>
635         *
636         * @param degrees The counterclockwise rotation in degrees, relative to the device's natural
637         *                orientation. Should be 0, 90, 180 or 270.
638         * @param capture Whether to adjust the JPEG capture orientation as well as the preview one.
639         */
640        public void setDisplayOrientation(final int degrees, final boolean capture) {
641            getDispatchThread().runJob(new Runnable() {
642                @Override
643                public void run() {
644                    getCameraHandler()
645                            .obtainMessage(CameraActions.SET_DISPLAY_ORIENTATION, degrees,
646                                    capture ? 1 : 0)
647                            .sendToTarget();
648                }});
649        }
650
651        /**
652         * Sets the listener for zoom change.
653         *
654         * @param listener The listener.
655         */
656        public abstract void setZoomChangeListener(OnZoomChangeListener listener);
657
658        /**
659         * Sets the face detection listener.
660         *
661         * @param handler  The handler in which the callback will be invoked.
662         * @param callback The callback for face detection results.
663         */
664        public abstract void setFaceDetectionCallback(Handler handler,
665                                                      CameraFaceDetectionCallback callback);
666
667        /**
668         * Starts the face detection.
669         */
670        public void startFaceDetection() {
671            getDispatchThread().runJob(new Runnable() {
672                @Override
673                public void run() {
674                    getCameraHandler().sendEmptyMessage(CameraActions.START_FACE_DETECTION);
675                }});
676        }
677
678        /**
679         * Stops the face detection.
680         */
681        public void stopFaceDetection() {
682            getDispatchThread().runJob(new Runnable() {
683                @Override
684                public void run() {
685                    getCameraHandler().sendEmptyMessage(CameraActions.STOP_FACE_DETECTION);
686                }});
687        }
688
689        /**
690         * Registers an error callback.
691         *
692         * @param handler  The handler on which the callback will be invoked.
693         * @param cb The error callback.
694         * @see android.hardware.Camera#setErrorCallback(android.hardware.Camera.ErrorCallback)
695         */
696        public abstract void setErrorCallback(Handler handler, CameraErrorCallback cb);
697
698        /**
699         * Sets the camera parameters.
700         *
701         * @param params The camera parameters to use.
702         */
703        @Deprecated
704        public abstract void setParameters(Camera.Parameters params);
705
706        /**
707         * Gets the current camera parameters synchronously. This method is
708         * synchronous since the caller has to wait for the camera to return
709         * the parameters. If the parameters are already cached, it returns
710         * immediately.
711         */
712        @Deprecated
713        public abstract Camera.Parameters getParameters();
714
715        /**
716         * Gets the current camera settings synchronously.
717         * <p>This method is synchronous since the caller has to wait for the
718         * camera to return the parameters. If the parameters are already
719         * cached, it returns immediately.</p>
720         */
721        public abstract CameraSettings getSettings();
722
723        /**
724         * Default implementation of {@link #applySettings(CameraSettings)}
725         * that is only missing the set of states it needs to wait for
726         * before applying the settings.
727         *
728         * @param settings The settings to use on the device.
729         * @param statesToAwait Bitwise OR of the required camera states.
730         * @return Whether the settings can be applied.
731         */
732        protected boolean applySettingsHelper(CameraSettings settings,
733                                              final int statesToAwait) {
734            if (settings == null) {
735                Log.v(TAG, "null argument in applySettings()");
736                return false;
737            }
738            if (!getCapabilities().supports(settings)) {
739                Log.w(TAG, "Unsupported settings in applySettings()");
740                return false;
741            }
742
743            final CameraSettings copyOfSettings = settings.copy();
744            getDispatchThread().runJob(new Runnable() {
745                @Override
746                public void run() {
747                    getCameraState().waitForStates(statesToAwait);
748                    getCameraHandler().obtainMessage(CameraActions.APPLY_SETTINGS, copyOfSettings)
749                            .sendToTarget();
750                }});
751            return true;
752        }
753
754        /**
755         * Applies the settings to the camera device.
756         *
757         * @param settings The settings to use on the device.
758         * @return Whether the settings can be applied.
759         */
760        public abstract boolean applySettings(CameraSettings settings);
761
762        /**
763         * Forces {@code CameraProxy} to update the cached version of the camera
764         * settings regardless of the dirty bit.
765         */
766        public void refreshSettings() {
767            getDispatchThread().runJob(new Runnable() {
768                @Override
769                public void run() {
770                    getCameraHandler().sendEmptyMessage(CameraActions.REFRESH_PARAMETERS);
771                }});
772        }
773
774        /**
775         * Enables/Disables the camera shutter sound.
776         *
777         * @param enable   {@code true} to enable the shutter sound,
778         *                 {@code false} to disable it.
779         */
780        public void enableShutterSound(final boolean enable) {
781            getDispatchThread().runJob(new Runnable() {
782                @Override
783                public void run() {
784                    getCameraHandler()
785                            .obtainMessage(CameraActions.ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0)
786                            .sendToTarget();
787                }});
788        }
789
790        /**
791         * Dumps the current settings of the camera device.
792         *
793         * <p>The content varies based on the underlying camera API settings
794         * implementation.</p>
795         *
796         * @return The content of the device settings represented by a string.
797         */
798        public abstract String dumpDeviceSettings();
799
800        /**
801         * @return The handler to which camera tasks should be posted.
802         */
803        public abstract Handler getCameraHandler();
804
805        /**
806         * @return The thread used on which client callbacks are served.
807         */
808        public abstract DispatchThread getDispatchThread();
809
810        /**
811         * @return The state machine tracking the camera API's current mode.
812         */
813        public abstract CameraStateHolder getCameraState();
814    }
815
816    public static class WaitDoneBundle {
817        public final Runnable mUnlockRunnable;
818        public final Object mWaitLock;
819
820        WaitDoneBundle() {
821            mWaitLock = new Object();
822            mUnlockRunnable = new Runnable() {
823                @Override
824                public void run() {
825                    synchronized (mWaitLock) {
826                        mWaitLock.notifyAll();
827                    }
828                }};
829        }
830    }
831}
832