AndroidCameraAgentImpl.java revision b00b7a67213ee6868eb792b2a63ba0dca888a01f
1bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong/*
2bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * Copyright (C) 2013 The Android Open Source Project
3bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong *
4bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * Licensed under the Apache License, Version 2.0 (the "License");
5bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * you may not use this file except in compliance with the License.
6bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * You may obtain a copy of the License at
7bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong *
8bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong *      http://www.apache.org/licenses/LICENSE-2.0
9bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong *
10bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * Unless required by applicable law or agreed to in writing, software
11bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * distributed under the License is distributed on an "AS IS" BASIS,
12bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * See the License for the specific language governing permissions and
14bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * limitations under the License.
15bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong */
16bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
17bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongpackage com.android.ex.camera2.portability;
18bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
19bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.annotation.TargetApi;
20bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.graphics.SurfaceTexture;
21bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.hardware.Camera;
22bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.hardware.Camera.AutoFocusCallback;
23bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.hardware.Camera.AutoFocusMoveCallback;
24bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.hardware.Camera.ErrorCallback;
25bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.hardware.Camera.FaceDetectionListener;
26bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.hardware.Camera.OnZoomChangeListener;
27bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.hardware.Camera.Parameters;
28bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.hardware.Camera.PictureCallback;
29bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.hardware.Camera.PreviewCallback;
30bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.hardware.Camera.ShutterCallback;
31bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.os.Build;
32bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.os.Handler;
33bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.os.HandlerThread;
34bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.os.Looper;
35bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.os.Message;
36bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.os.SystemClock;
37bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport android.view.SurfaceHolder;
38bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
39bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport com.android.ex.camera2.portability.debug.Log;
40bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
41bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport java.io.IOException;
42bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport java.util.LinkedList;
43bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongimport java.util.Queue;
44bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
45bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong/**
46bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * A class to implement {@link CameraManager} of the Android camera framework.
47bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong */
48bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongclass AndroidCameraManagerImpl implements CameraManager {
49bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final Log.Tag TAG = new Log.Tag("AndroidCamMgrImpl");
50bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final long CAMERA_OPERATION_TIMEOUT_MS = 2500;
51bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final long MAX_MESSAGE_QUEUE_LENGTH = 256;
52b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong    private static final int MAX_HISTORY_SIZE = 400;
53bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
54bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private Parameters mParameters;
55bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private boolean mParametersIsDirty;
56bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
57bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    /* Messages used in CameraHandler. */
58bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    // Camera initialization/finalization
59bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int OPEN_CAMERA = 1;
60bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int RELEASE =     2;
61bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int RECONNECT =   3;
62bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int UNLOCK =      4;
63bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int LOCK =        5;
64bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    // Preview
65bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int SET_PREVIEW_TEXTURE_ASYNC =        101;
66bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int START_PREVIEW_ASYNC =              102;
67bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int STOP_PREVIEW =                     103;
68bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int SET_PREVIEW_CALLBACK_WITH_BUFFER = 104;
69bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int ADD_CALLBACK_BUFFER =              105;
70bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int SET_PREVIEW_DISPLAY_ASYNC =        106;
71bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int SET_PREVIEW_CALLBACK =             107;
72bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int SET_ONE_SHOT_PREVIEW_CALLBACK =    108;
73bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    // Parameters
74bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int SET_PARAMETERS =     201;
75bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int GET_PARAMETERS =     202;
76bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int REFRESH_PARAMETERS = 203;
77bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    // Focus, Zoom
78bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int AUTO_FOCUS =                   301;
79bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int CANCEL_AUTO_FOCUS =            302;
80bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int SET_AUTO_FOCUS_MOVE_CALLBACK = 303;
81bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int SET_ZOOM_CHANGE_LISTENER =     304;
82bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    // Face detection
83bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int SET_FACE_DETECTION_LISTENER = 461;
84bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int START_FACE_DETECTION =        462;
85bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int STOP_FACE_DETECTION =         463;
86bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int SET_ERROR_CALLBACK =          464;
87bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    // Presentation
88bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int ENABLE_SHUTTER_SOUND =    501;
89bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int SET_DISPLAY_ORIENTATION = 502;
90bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    // Capture
91bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int CAPTURE_PHOTO = 601;
92bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
93bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    /** Camera states **/
94bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    // These states are defined bitwise so we can easily to specify a set of
95bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    // states together.
96bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int CAMERA_UNOPENED = 1;
97bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int CAMERA_IDLE = 1 << 1;
98bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int CAMERA_UNLOCKED = 1 << 2;
99bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int CAMERA_CAPTURING = 1 << 3;
100bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static final int CAMERA_FOCUSING = 1 << 4;
101bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
102bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private final CameraHandler mCameraHandler;
103bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private final HandlerThread mCameraHandlerThread;
104bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private final CameraStateHolder mCameraState;
105bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private final DispatchThread mDispatchThread;
106bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
107bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    // Used to retain a copy of Parameters for setting parameters.
108bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private Parameters mParamsToSet;
109bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
110bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private Handler mCameraExceptionCallbackHandler;
111bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private CameraExceptionCallback mCameraExceptionCallback =
112bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        new CameraExceptionCallback() {
113bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            @Override
114bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            public void onCameraException(RuntimeException e) {
115bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                throw e;
116bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
117bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        };
118bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
119bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    AndroidCameraManagerImpl() {
120bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        mCameraHandlerThread = new HandlerThread("Camera Handler Thread");
121bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        mCameraHandlerThread.start();
122bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        mCameraHandler = new CameraHandler(mCameraHandlerThread.getLooper());
123bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        mCameraExceptionCallbackHandler = mCameraHandler;
124bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        mCameraState = new CameraStateHolder();
125bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        mDispatchThread = new DispatchThread();
126bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        mDispatchThread.start();
127bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
128bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
129bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    @Override
130bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    public void setCameraDefaultExceptionCallback(CameraExceptionCallback callback,
131bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            Handler handler) {
132bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        synchronized (mCameraExceptionCallback) {
133bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCameraExceptionCallback = callback;
134bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCameraExceptionCallbackHandler = handler;
135bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
136bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
137bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
138bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    /**
139bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     * Recycles the resources used by this instance. CameraManager will be in
140bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     * an unusable state after calling this.
141bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     */
142bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    public void recycle() {
143bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        mDispatchThread.end();
144bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
145bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
146bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static class CameraStateHolder {
147bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private int mState;
148bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
149bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public CameraStateHolder() {
150bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            setState(CAMERA_UNOPENED);
151bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
152bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
153bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public CameraStateHolder(int state) {
154bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            setState(state);
155bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
156bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
157bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public synchronized void setState(int state) {
158bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mState = state;
159bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            this.notifyAll();
160bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
161bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
162bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public synchronized int getState() {
163bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return mState;
164bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
165bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
166bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private interface ConditionChecker {
167bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            /**
168bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong             * @return Whether the condition holds.
169bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong             */
170bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            boolean success();
171bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
172bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
173bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
174bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * A helper method used by {@link #waitToAvoidStates(int)} and
175bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * {@link #waitForStates(int)}. This method will wait until the
176bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * condition is successful.
177bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *
178bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param stateChecker The state checker to be used.
179bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param timeoutMs The timeout limit in milliseconds.
180bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @return {@code false} if the wait is interrupted or timeout limit is
181bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *         reached.
182bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
183bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private boolean waitForCondition(ConditionChecker stateChecker,
184bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                long timeoutMs) {
185bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            long timeBound = SystemClock.uptimeMillis() + timeoutMs;
186bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            synchronized (this) {
187bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                while (!stateChecker.success()) {
188bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    try {
189bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        this.wait(timeoutMs);
190bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    } catch (InterruptedException ex) {
191bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        if (SystemClock.uptimeMillis() > timeBound) {
192bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            // Timeout.
193bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            Log.w(TAG, "Timeout waiting.");
194bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        }
195bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        return false;
196bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
197bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
198bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
199bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return true;
200bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
201bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
202bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
203bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * Block the current thread until the state becomes one of the
204bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * specified.
205bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *
206bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param states Expected states.
207bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @return {@code false} if the wait is interrupted or timeout limit is
208bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *         reached.
209bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
210bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public boolean waitForStates(final int states) {
211bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return waitForCondition(new ConditionChecker() {
212bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
213bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public boolean success() {
214bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    return (states | mState) == states;
215bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
216bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }, CAMERA_OPERATION_TIMEOUT_MS);
217bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
218bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
219bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
220bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * Block the current thread until the state becomes NOT one of the
221bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * specified.
222bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *
223bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param states States to avoid.
224bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @return {@code false} if the wait is interrupted or timeout limit is
225bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *         reached.
226bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
227bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public boolean waitToAvoidStates(final int states) {
228bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return waitForCondition(new ConditionChecker() {
229bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
230bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public boolean success() {
231bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    return (states & mState) == 0;
232bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
233bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }, CAMERA_OPERATION_TIMEOUT_MS);
234bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
235bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
236bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
237bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    /**
238bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     * The handler on which the actual camera operations happen.
239bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     */
240bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private class CameraHandler extends Handler {
241b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong
242bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private Camera mCamera;
243bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
244b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong        private LinkedList<Integer> mMsgHistory;
245b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong
246bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private class CaptureCallbacks {
247bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            public final ShutterCallback mShutter;
248bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            public final PictureCallback mRaw;
249bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            public final PictureCallback mPostView;
250bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            public final PictureCallback mJpeg;
251bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
252bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            CaptureCallbacks(ShutterCallback shutter, PictureCallback raw, PictureCallback postView,
253bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    PictureCallback jpeg) {
254bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                mShutter = shutter;
255bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                mRaw = raw;
256bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                mPostView = postView;
257bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                mJpeg = jpeg;
258bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
259bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
260bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
261bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        CameraHandler(Looper looper) {
262bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            super(looper);
263b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong            mMsgHistory = new LinkedList<Integer>();
264b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong            // We add a -1 at the beginning to mark the very beginning of the
265b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong            // history.
266b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong            mMsgHistory.offerLast(-1);
267b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong        }
268b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong
269b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong        private String generateHistoryString(int cameraId) {
270b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong            String info = new String("HIST");
271b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong            info += "_ID" + cameraId;
272b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong            for (Integer msg : mMsgHistory) {
273b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong                info = info + '_' + msg.toString();
274b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong            }
275b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong            info += "_HEND";
276b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong            return info;
277bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
278bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
279bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private void startFaceDetection() {
280bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCamera.startFaceDetection();
281bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
282bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
283bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private void stopFaceDetection() {
284bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCamera.stopFaceDetection();
285bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
286bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
287bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private void setFaceDetectionListener(FaceDetectionListener listener) {
288bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCamera.setFaceDetectionListener(listener);
289bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
290bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
291bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private void setPreviewTexture(Object surfaceTexture) {
292bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            try {
293bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                mCamera.setPreviewTexture((SurfaceTexture) surfaceTexture);
294bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            } catch (IOException e) {
295bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Log.e(TAG, "Could not set preview texture", e);
296bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
297bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
298bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
299bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
300bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private void enableShutterSound(boolean enable) {
301bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCamera.enableShutterSound(enable);
302bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
303bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
304bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
305bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private void setAutoFocusMoveCallback(
306bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                android.hardware.Camera camera, Object cb) {
307bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            try {
308bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                camera.setAutoFocusMoveCallback((AutoFocusMoveCallback) cb);
309bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            } catch (RuntimeException ex) {
310bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Log.w(TAG, ex.getMessage());
311bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
312bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
313bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
314bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private void capture(final CaptureCallbacks cb) {
315bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            try {
316bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                mCamera.takePicture(cb.mShutter, cb.mRaw, cb.mPostView, cb.mJpeg);
317bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            } catch (RuntimeException e) {
318bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                // TODO: output camera state and focus state for debugging.
319bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Log.e(TAG, "take picture failed.");
320bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                throw e;
321bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
322bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
323bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
324bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void requestTakePicture(
325bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final ShutterCallback shutter,
326bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final PictureCallback raw,
327bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final PictureCallback postView,
328bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final PictureCallback jpeg) {
329bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            final CaptureCallbacks callbacks = new CaptureCallbacks(shutter, raw, postView, jpeg);
330bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            obtainMessage(CAPTURE_PHOTO, callbacks).sendToTarget();
331bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
332bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
333bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
334bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * This method does not deal with the API level check.  Everyone should
335bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * check first for supported operations before sending message to this handler.
336bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
337bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
338bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void handleMessage(final Message msg) {
339b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong            mMsgHistory.offerLast(msg.what);
340b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong            while (mMsgHistory.size() > MAX_HISTORY_SIZE) {
341b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong                mMsgHistory.pollFirst();
342b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong            }
343bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            try {
344bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                switch (msg.what) {
345bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case OPEN_CAMERA: {
346bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        final CameraOpenCallback openCallback = (CameraOpenCallback) msg.obj;
347bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        final int cameraId = msg.arg1;
348bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        if (mCameraState.getState() != CAMERA_UNOPENED) {
349bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            openCallback.onDeviceOpenedAlready(cameraId);
350bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            break;
351bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        }
352bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
353bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera = android.hardware.Camera.open(cameraId);
354bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        if (mCamera != null) {
355bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            mParametersIsDirty = true;
356bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
357bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            // Get a instance of Camera.Parameters for later use.
358bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            if (mParamsToSet == null) {
359bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                                mParamsToSet = mCamera.getParameters();
360bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            }
361bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
362bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            mCameraState.setState(CAMERA_IDLE);
363bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            if (openCallback != null) {
364bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                                openCallback.onCameraOpened(
365bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                                        new AndroidCameraProxyImpl(cameraId, mCamera));
366bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            }
367bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        } else {
368bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            if (openCallback != null) {
369b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong                                openCallback.onDeviceOpenFailure(cameraId, generateHistoryString(cameraId));
370bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            }
371bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        }
372bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
373bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
374bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
375bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case RELEASE: {
376bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.release();
377bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCameraState.setState(CAMERA_UNOPENED);
378bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera = null;
379bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
380bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
381bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
382bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case RECONNECT: {
383bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        final CameraOpenCallbackForward cbForward =
384bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                                (CameraOpenCallbackForward) msg.obj;
385bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        final int cameraId = msg.arg1;
386bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        try {
387bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            mCamera.reconnect();
388bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        } catch (IOException ex) {
389bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            if (cbForward != null) {
390bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                                cbForward.onReconnectionFailure(AndroidCameraManagerImpl.this);
391bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            }
392bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            break;
393bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        }
394bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
395bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCameraState.setState(CAMERA_IDLE);
396bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        if (cbForward != null) {
397bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            cbForward.onCameraOpened(new AndroidCameraProxyImpl(cameraId, mCamera));
398bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        }
399bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
400bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
401bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
402bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case UNLOCK: {
403bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.unlock();
404bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCameraState.setState(CAMERA_UNLOCKED);
405bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
406bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
407bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
408bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case LOCK: {
409bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.lock();
410bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCameraState.setState(CAMERA_IDLE);
411bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
412bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
413bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
414bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case SET_PREVIEW_TEXTURE_ASYNC: {
415bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        setPreviewTexture(msg.obj);
416bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
417bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
418bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
419bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case SET_PREVIEW_DISPLAY_ASYNC: {
420bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        try {
421bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            mCamera.setPreviewDisplay((SurfaceHolder) msg.obj);
422bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        } catch (IOException e) {
423bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            throw new RuntimeException(e);
424bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        }
425bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
426bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
427bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
428bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case START_PREVIEW_ASYNC: {
429bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        final CameraStartPreviewCallbackForward cbForward =
430bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            (CameraStartPreviewCallbackForward) msg.obj;
431bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.startPreview();
432bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        if (cbForward != null) {
433bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            cbForward.onPreviewStarted();
434bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        }
435bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
436bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
437bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
438bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case STOP_PREVIEW: {
439bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.stopPreview();
440bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
441bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
442bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
443bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case SET_PREVIEW_CALLBACK_WITH_BUFFER: {
444bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.setPreviewCallbackWithBuffer((PreviewCallback) msg.obj);
445bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
446bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
447bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
448bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case SET_ONE_SHOT_PREVIEW_CALLBACK: {
449bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.setOneShotPreviewCallback((PreviewCallback) msg.obj);
450bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
451bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
452bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
453bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case ADD_CALLBACK_BUFFER: {
454bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.addCallbackBuffer((byte[]) msg.obj);
455bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
456bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
457bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
458bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case AUTO_FOCUS: {
459bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCameraState.setState(CAMERA_FOCUSING);
460bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.autoFocus((AutoFocusCallback) msg.obj);
461bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
462bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
463bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
464bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case CANCEL_AUTO_FOCUS: {
465bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.cancelAutoFocus();
466bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCameraState.setState(CAMERA_IDLE);
467bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
468bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
469bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
470bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case SET_AUTO_FOCUS_MOVE_CALLBACK: {
471bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        setAutoFocusMoveCallback(mCamera, msg.obj);
472bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
473bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
474bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
475bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case SET_DISPLAY_ORIENTATION: {
476bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.setDisplayOrientation(msg.arg1);
477bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
478bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
479bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
480bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case SET_ZOOM_CHANGE_LISTENER: {
481bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.setZoomChangeListener((OnZoomChangeListener) msg.obj);
482bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
483bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
484bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
485bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case SET_FACE_DETECTION_LISTENER: {
486bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        setFaceDetectionListener((FaceDetectionListener) msg.obj);
487bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
488bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
489bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
490bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case START_FACE_DETECTION: {
491bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        startFaceDetection();
492bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
493bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
494bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
495bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case STOP_FACE_DETECTION: {
496bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        stopFaceDetection();
497bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
498bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
499bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
500bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case SET_ERROR_CALLBACK: {
501bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.setErrorCallback((ErrorCallback) msg.obj);
502bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
503bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
504bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
505bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case SET_PARAMETERS: {
506bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mParametersIsDirty = true;
507bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mParamsToSet.unflatten((String) msg.obj);
508bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.setParameters(mParamsToSet);
509bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
510bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
511bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
512bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case GET_PARAMETERS: {
513bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        if (mParametersIsDirty) {
514bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            mParameters = mCamera.getParameters();
515bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            mParametersIsDirty = false;
516bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        }
517bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
518bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
519bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
520bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case SET_PREVIEW_CALLBACK: {
521bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.setPreviewCallback((PreviewCallback) msg.obj);
522bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
523bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
524bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
525bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case ENABLE_SHUTTER_SOUND: {
526bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        enableShutterSound((msg.arg1 == 1) ? true : false);
527bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
528bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
529bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
530bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case REFRESH_PARAMETERS: {
531bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mParametersIsDirty = true;
532bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
533bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
534bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
535bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    case CAPTURE_PHOTO: {
536bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCameraState.setState(CAMERA_CAPTURING);
537bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        capture((CaptureCallbacks) msg.obj);
538bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
539bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
540bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
541bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    default: {
542bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        throw new RuntimeException("Invalid CameraProxy message=" + msg.what);
543bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
544bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
545bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            } catch (final RuntimeException e) {
546bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                if (msg.what != RELEASE && mCamera != null) {
547bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    try {
548bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCamera.release();
549bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCameraState.setState(CAMERA_UNOPENED);
550bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    } catch (Exception ex) {
551bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        Log.e(TAG, "Fail to release the camera.");
552bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
553bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCamera = null;
554bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                } else {
555bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    if (mCamera == null) {
556bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        if (msg.what == OPEN_CAMERA) {
557b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong                            final int cameraId = msg.arg1;
558bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            if (msg.obj != null) {
559b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong                                ((CameraOpenCallback) msg.obj).onDeviceOpenFailure(
560b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong                                        msg.arg1, generateHistoryString(cameraId));
561bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            }
562bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        } else {
563bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            Log.w(TAG, "Cannot handle message " + msg.what + ", mCamera is null.");
564bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        }
565bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        return;
566bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
567bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
568bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                synchronized (mCameraExceptionCallback) {
569bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraExceptionCallbackHandler.post(new Runnable() {
570bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        @Override
571bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        public void run() {
572bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                                mCameraExceptionCallback.onCameraException(e);
573bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            }
574bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        });
575bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
576bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
577bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
578bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
579bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
580bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private class DispatchThread extends Thread {
581bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
582bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final Queue<Runnable> mJobQueue;
583bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private Boolean mIsEnded;
584bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
585bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public DispatchThread() {
586bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            super("Camera Job Dispatch Thread");
587bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mJobQueue = new LinkedList<Runnable>();
588bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mIsEnded = new Boolean(false);
589bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
590bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
591bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
592bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * Queues up the job.
593bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *
594bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param job The job to run.
595bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
596bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void runJob(Runnable job) {
597bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            if (isEnded()) {
598bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                throw new IllegalStateException(
599bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        "Trying to run job on interrupted dispatcher thread");
600bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
601bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            synchronized (mJobQueue) {
602bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                if (mJobQueue.size() == MAX_MESSAGE_QUEUE_LENGTH) {
603bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    throw new RuntimeException("Camera master thread job queue full");
604bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
605bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
606bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                mJobQueue.add(job);
607bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                mJobQueue.notifyAll();
608bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
609bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
610bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
611bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
612bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * Queues up the job and wait for it to be done.
613bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *
614bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param job The job to run.
615bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param timeoutMs Timeout limit in milliseconds.
616bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param jobMsg The message to log when the job runs timeout.
617bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @return Whether the job finishes before timeout.
618bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
619bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public boolean runJobSync(final Runnable job, Object waitLock, long timeoutMs, String jobMsg) {
620bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            synchronized (waitLock) {
621bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                long timeoutBound = SystemClock.uptimeMillis() + timeoutMs;
622bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                try {
623bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    runJob(job);
624bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    waitLock.wait();
625bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                } catch (InterruptedException ex) {
626bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    Log.v(TAG, "Job interrupted");
627bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    if (SystemClock.uptimeMillis() > timeoutBound) {
628bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        // Timeout.
629bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        Log.w(TAG, "Timeout waiting camera operation:" + jobMsg);
630bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
631bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    return false;
632bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
633bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
634bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return true;
635bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
636bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
637bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
638bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * Gracefully ends this thread. Will stop after all jobs are processed.
639bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
640bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void end() {
641bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            synchronized (mIsEnded) {
642bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                mIsEnded = true;
643bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
644bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            synchronized(mJobQueue) {
645bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                mJobQueue.notifyAll();
646bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
647bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
648bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
649bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private boolean isEnded() {
650bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            synchronized (mIsEnded) {
651bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                return mIsEnded;
652bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
653bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
654bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
655bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
656bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void run() {
657bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            while(true) {
658bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Runnable job = null;
659bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                synchronized (mJobQueue) {
660bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    while (mJobQueue.size() == 0 && !isEnded()) {
661bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        try {
662bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            mJobQueue.wait();
663bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        } catch (InterruptedException ex) {
664bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            Log.v(TAG, "Dispatcher thread wait() interrupted, exiting");
665bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            break;
666bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        }
667bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
668bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
669bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    job = mJobQueue.poll();
670bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
671bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
672bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                if (job == null) {
673bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    // mJobQueue.poll() returning null means wait() is
674bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    // interrupted and the queue is empty.
675bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    if (isEnded()) {
676bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        break;
677bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
678bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    continue;
679bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
680bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
681bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                job.run();
682bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
683bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                synchronized (DispatchThread.this) {
684bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.post(new Runnable() {
685bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        @Override
686bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        public void run() {
687bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            synchronized (DispatchThread.this) {
688bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                                DispatchThread.this.notifyAll();
689bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            }
690bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        }
691bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    });
692bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    try {
693bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        DispatchThread.this.wait();
694bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    } catch (InterruptedException ex) {
695bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        // TODO: do something here.
696bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
697bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
698bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
699bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCameraHandlerThread.quitSafely();
700bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
701bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
702bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
703bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    @Override
704bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    public void cameraOpen(final Handler handler, final int cameraId,
705bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            final CameraOpenCallback callback) {
706bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        mDispatchThread.runJob(new Runnable() {
707bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            @Override
708bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            public void run() {
709bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                mCameraHandler.obtainMessage(OPEN_CAMERA, cameraId, 0,
710bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        CameraOpenCallbackForward.getNewInstance(handler, callback)).sendToTarget();
711bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
712bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        });
713bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
714bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
715bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    /**
716bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     * A class which implements {@link CameraManager.CameraProxy} and
717bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     * camera handler thread.
718bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     */
719bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private class AndroidCameraProxyImpl implements CameraManager.CameraProxy {
720bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final int mCameraId;
721bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /* TODO: remove this Camera instance. */
722bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final Camera mCamera;
723bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
724bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private AndroidCameraProxyImpl(int cameraId, Camera camera) {
725bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCamera = camera;
726bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCameraId = cameraId;
727bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
728bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
729bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
730bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public android.hardware.Camera getCamera() {
731bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return mCamera;
732bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
733bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
734bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
735bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public int getCameraId() {
736bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return mCameraId;
737bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
738bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
739bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        // TODO: Make this package private.
740bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
741bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void release(boolean sync) {
742bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            Log.v(TAG, "camera manager release");
743bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            if (sync) {
744bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final WaitDoneBundle bundle = new WaitDoneBundle();
745bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
746bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                mDispatchThread.runJobSync(new Runnable() {
747bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    @Override
748bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    public void run() {
749bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCameraHandler.sendEmptyMessage(RELEASE);
750bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCameraHandler.post(bundle.mUnlockRunnable);
751bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
752bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "camera release");
753bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            } else {
754bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                mDispatchThread.runJob(new Runnable() {
755bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    @Override
756bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    public void run() {
757bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCameraHandler.removeCallbacksAndMessages(null);
758bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCameraHandler.sendEmptyMessage(RELEASE);
759bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
760bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                });
761bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
762bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
763bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
764bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
765bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void reconnect(final Handler handler, final CameraOpenCallback cb) {
766bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
767bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
768bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
769bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(RECONNECT, mCameraId, 0,
770bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            CameraOpenCallbackForward.getNewInstance(handler, cb)).sendToTarget();
771bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
772bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
773bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
774bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
775bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
776bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void unlock() {
777bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            final WaitDoneBundle bundle = new WaitDoneBundle();
778bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJobSync(new Runnable() {
779bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
780bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
781bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.sendEmptyMessage(UNLOCK);
782bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.post(bundle.mUnlockRunnable);
783bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
784bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "camera unlock");
785bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
786bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
787bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
788bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void lock() {
789bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
790bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
791bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
792bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.sendEmptyMessage(LOCK);
793bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
794bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
795bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
796bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
797bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
798bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void setPreviewTexture(final SurfaceTexture surfaceTexture) {
799bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
800bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
801bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
802bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture)
803bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            .sendToTarget();
804bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
805bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
806bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
807bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
808bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
809bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void setPreviewTextureSync(final SurfaceTexture surfaceTexture) {
810bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            final WaitDoneBundle bundle = new WaitDoneBundle();
811bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJobSync(new Runnable() {
812bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
813bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
814bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture)
815bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            .sendToTarget();
816bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.post(bundle.mUnlockRunnable);
817bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
818bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "set preview texture");
819bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
820bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
821bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
822bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void setPreviewDisplay(final SurfaceHolder surfaceHolder) {
823bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
824bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
825bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
826bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder)
827bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            .sendToTarget();
828bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
829bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
830bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
831bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
832bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
833bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void startPreview() {
834bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
835bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
836bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
837bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(START_PREVIEW_ASYNC, null).sendToTarget();
838bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
839bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
840bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
841bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
842bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
843bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void startPreviewWithCallback(final Handler handler,
844bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final CameraStartPreviewCallback cb) {
845bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
846bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
847bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
848bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(START_PREVIEW_ASYNC,
849bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        CameraStartPreviewCallbackForward.getNewInstance(handler, cb)).sendToTarget();
850bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
851bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
852bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
853bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
854bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
855bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void stopPreview() {
856bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            final WaitDoneBundle bundle = new WaitDoneBundle();
857bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJobSync(new Runnable() {
858bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
859bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
860bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.sendEmptyMessage(STOP_PREVIEW);
861bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.post(bundle.mUnlockRunnable);
862bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
863bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "stop preview");
864bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
865bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
866bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
867bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void setPreviewDataCallback(
868bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final Handler handler, final CameraPreviewDataCallback cb) {
869bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
870bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
871bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
872bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(SET_PREVIEW_CALLBACK, PreviewCallbackForward
873bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            .getNewInstance(handler, AndroidCameraProxyImpl.this, cb))
874bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            .sendToTarget();
875bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
876bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
877bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
878bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
879bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void setOneShotPreviewCallback(final Handler handler,
880bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final CameraPreviewDataCallback cb) {
881bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
882bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
883bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
884bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(SET_ONE_SHOT_PREVIEW_CALLBACK,
885bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            PreviewCallbackForward
886bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                                    .getNewInstance(handler, AndroidCameraProxyImpl.this, cb))
887bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            .sendToTarget();
888bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
889bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
890bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
891bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
892bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
893bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void setPreviewDataCallbackWithBuffer(
894bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final Handler handler, final CameraPreviewDataCallback cb) {
895bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
896bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
897bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
898bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(SET_PREVIEW_CALLBACK_WITH_BUFFER,
899bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            PreviewCallbackForward
900bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                                    .getNewInstance(handler, AndroidCameraProxyImpl.this, cb))
901bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            .sendToTarget();
902bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
903bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
904bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
905bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
906bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
907bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void addCallbackBuffer(final byte[] callbackBuffer) {
908bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
909bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
910bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
911bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(ADD_CALLBACK_BUFFER, callbackBuffer)
912bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            .sendToTarget();
913bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
914bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
915bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
916bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
917bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
918bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void autoFocus(final Handler handler, final CameraAFCallback cb) {
919bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            final AutoFocusCallback afCallback = new AutoFocusCallback() {
920bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
921bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void onAutoFocus(final boolean b, Camera camera) {
922bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    if (mCameraState.getState() != CAMERA_FOCUSING) {
923bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        Log.w(TAG, "onAutoFocus callback returning when not focusing");
924bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    } else {
925bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCameraState.setState(CAMERA_IDLE);
926bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
927bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    handler.post(new Runnable() {
928bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        @Override
929bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        public void run() {
930bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            cb.onAutoFocus(b, AndroidCameraProxyImpl.this);
931bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        }
932bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    });
933bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
934bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            };
935bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
936bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
937bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
938bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraState.waitForStates(CAMERA_IDLE);
939bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(AUTO_FOCUS, afCallback).sendToTarget();
940bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
941bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
942bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
943bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
944bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
945bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void cancelAutoFocus() {
946bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
947bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
948bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
949bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.removeMessages(AUTO_FOCUS);
950bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.sendEmptyMessage(CANCEL_AUTO_FOCUS);
951bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
952bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
953bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
954bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
955bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
956bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
957bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void setAutoFocusMoveCallback(
958bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final Handler handler, final CameraAFMoveCallback cb) {
959bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
960bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
961bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
962bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(SET_AUTO_FOCUS_MOVE_CALLBACK, AFMoveCallbackForward
963bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            .getNewInstance(handler, AndroidCameraProxyImpl.this, cb))
964bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            .sendToTarget();
965bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
966bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
967bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
968bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
969bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
970bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void takePicture(
971bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final Handler handler, final CameraShutterCallback shutter,
972bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final CameraPictureCallback raw, final CameraPictureCallback post,
973bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final CameraPictureCallback jpeg) {
974bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            final PictureCallback jpegCallback = new PictureCallback() {
975bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
976bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void onPictureTaken(final byte[] data, Camera camera) {
977bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    if (mCameraState.getState() != CAMERA_CAPTURING) {
978bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        Log.v(TAG, "picture callback returning when not capturing");
979bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    } else {
980bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mCameraState.setState(CAMERA_IDLE);
981bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
982bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    handler.post(new Runnable() {
983bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        @Override
984bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        public void run() {
985bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            jpeg.onPictureTaken(data, AndroidCameraProxyImpl.this);
986bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        }
987bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    });
988bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
989bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            };
990bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
991bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
992bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
993bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
994d3865a20b022f6d54fe7ac052768a7ff0710017fDoris Liu                    mCameraState.waitForStates(CAMERA_IDLE | CAMERA_UNLOCKED);
995bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.requestTakePicture(ShutterCallbackForward
996bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            .getNewInstance(handler, AndroidCameraProxyImpl.this, shutter),
997bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            PictureCallbackForward
998bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                                    .getNewInstance(handler, AndroidCameraProxyImpl.this, raw),
999bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            PictureCallbackForward
1000bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                                    .getNewInstance(handler, AndroidCameraProxyImpl.this, post),
1001bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            jpegCallback);
1002bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1003bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1004bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1005bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1006bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1007bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void setDisplayOrientation(final int degrees) {
1008bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
1009bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1010bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1011bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(SET_DISPLAY_ORIENTATION, degrees, 0)
1012bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            .sendToTarget();
1013bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1014bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1015bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1016bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1017bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1018bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void setZoomChangeListener(final OnZoomChangeListener listener) {
1019bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
1020bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1021bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1022bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(SET_ZOOM_CHANGE_LISTENER, listener).sendToTarget();
1023bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1024bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1025bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1026bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1027bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1028bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void setFaceDetectionCallback(final Handler handler,
1029bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final CameraFaceDetectionCallback cb) {
1030bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
1031bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1032bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1033bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(SET_FACE_DETECTION_LISTENER,
1034bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            FaceDetectionCallbackForward
1035bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                                    .getNewInstance(handler, AndroidCameraProxyImpl.this, cb))
1036bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            .sendToTarget();
1037bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1038bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1039bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1040bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1041bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1042bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void startFaceDetection() {
1043bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
1044bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1045bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1046bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.sendEmptyMessage(START_FACE_DETECTION);
1047bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1048bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1049bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1050bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1051bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1052bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void stopFaceDetection() {
1053bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
1054bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1055bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1056bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.sendEmptyMessage(STOP_FACE_DETECTION);
1057bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1058bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1059bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1060bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1061bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1062bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void setErrorCallback(final Handler handler, final CameraErrorCallback cb) {
1063bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
1064bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1065bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1066bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(SET_ERROR_CALLBACK, ErrorCallbackForward
1067bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                                    .getNewInstance(handler, AndroidCameraProxyImpl.this, cb)
1068bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    ).sendToTarget();
1069bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1070bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1071bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1072bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1073bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1074bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void setParameters(final Parameters params) {
1075bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            if (params == null) {
1076bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Log.v(TAG, "null parameters in setParameters()");
1077bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                return;
1078bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
1079bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            final String flattenedParameters = params.flatten();
1080bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
1081bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1082bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1083bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraState.waitForStates(CAMERA_IDLE | CAMERA_UNLOCKED);
1084bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(SET_PARAMETERS, flattenedParameters).sendToTarget();
1085bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1086bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1087bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1088bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1089bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1090bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public Parameters getParameters() {
1091bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            final WaitDoneBundle bundle = new WaitDoneBundle();
1092bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJobSync(new Runnable() {
1093bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1094bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1095bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.sendEmptyMessage(GET_PARAMETERS);
1096bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.post(bundle.mUnlockRunnable);
1097bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1098bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "get parameters");
1099bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return mParameters;
1100bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1101bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1102bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1103bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void refreshParameters() {
1104bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
1105bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1106bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1107bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.sendEmptyMessage(REFRESH_PARAMETERS);
1108bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1109bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1110bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1111bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1112bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1113bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void enableShutterSound(final boolean enable) {
1114bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mDispatchThread.runJob(new Runnable() {
1115bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1116bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1117bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCameraHandler.obtainMessage(ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0)
1118bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                            .sendToTarget();
1119bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1120bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1121bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1122bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1123bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
1124bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1125bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static class WaitDoneBundle {
1126bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public Runnable mUnlockRunnable;
1127bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final Object mWaitLock;
1128bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1129bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        WaitDoneBundle() {
1130bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mWaitLock = new Object();
1131bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mUnlockRunnable = new Runnable() {
1132bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1133bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1134bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    synchronized (mWaitLock) {
1135bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                        mWaitLock.notifyAll();
1136bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    }
1137bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1138bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            };
1139bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1140bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
1141bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1142bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    /**
1143bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     * A helper class to forward AutoFocusCallback to another thread.
1144bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     */
1145bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static class AFCallbackForward implements AutoFocusCallback {
1146bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final Handler mHandler;
1147bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraProxy mCamera;
1148bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraAFCallback mCallback;
1149bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1150bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
1151bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * Returns a new instance of {@link AFCallbackForward}.
1152bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *
1153bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param handler The handler in which the callback will be invoked in.
1154bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param camera  The {@link CameraProxy} which the callback is from.
1155bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param cb      The callback to be invoked.
1156bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @return        The instance of the {@link AFCallbackForward},
1157bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *                or null if any parameter is null.
1158bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
1159bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public static AFCallbackForward getNewInstance(
1160bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler handler, CameraProxy camera, CameraAFCallback cb) {
1161bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            if (handler == null || camera == null || cb == null) {
1162bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                return null;
1163bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
1164bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return new AFCallbackForward(handler, camera, cb);
1165bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1166bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1167bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private AFCallbackForward(
1168bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler h, CameraProxy camera, CameraAFCallback cb) {
1169bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler = h;
1170bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCamera = camera;
1171bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCallback = cb;
1172bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1173bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1174bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1175bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void onAutoFocus(final boolean b, Camera camera) {
1176bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler.post(new Runnable() {
1177bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1178bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1179bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCallback.onAutoFocus(b, mCamera);
1180bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1181bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1182bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1183bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
1184bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1185bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    /**
1186bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     * A helper class to forward ErrorCallback to another thread.
1187bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     */
1188bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static class ErrorCallbackForward implements Camera.ErrorCallback {
1189bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final Handler mHandler;
1190bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraProxy mCamera;
1191bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraErrorCallback mCallback;
1192bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1193bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
1194bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * Returns a new instance of {@link AFCallbackForward}.
1195bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *
1196bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param handler The handler in which the callback will be invoked in.
1197bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param camera  The {@link CameraProxy} which the callback is from.
1198bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param cb      The callback to be invoked.
1199bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @return        The instance of the {@link AFCallbackForward},
1200bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *                or null if any parameter is null.
1201bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
1202bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public static ErrorCallbackForward getNewInstance(
1203bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler handler, CameraProxy camera, CameraErrorCallback cb) {
1204bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            if (handler == null || camera == null || cb == null) {
1205bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                return null;
1206bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
1207bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return new ErrorCallbackForward(handler, camera, cb);
1208bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1209bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1210bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private ErrorCallbackForward(
1211bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler h, CameraProxy camera, CameraErrorCallback cb) {
1212bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler = h;
1213bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCamera = camera;
1214bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCallback = cb;
1215bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1216bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1217bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1218bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void onError(final int error, Camera camera) {
1219bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler.post(new Runnable() {
1220bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1221bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1222bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCallback.onError(error, mCamera);
1223bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1224bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1225bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1226bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
1227bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1228bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    /** A helper class to forward AutoFocusMoveCallback to another thread. */
1229bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
1230bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static class AFMoveCallbackForward implements AutoFocusMoveCallback {
1231bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final Handler mHandler;
1232bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraAFMoveCallback mCallback;
1233bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraProxy mCamera;
1234bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1235bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
1236bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * Returns a new instance of {@link AFMoveCallbackForward}.
1237bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *
1238bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param handler The handler in which the callback will be invoked in.
1239bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param camera  The {@link CameraProxy} which the callback is from.
1240bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param cb      The callback to be invoked.
1241bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @return        The instance of the {@link AFMoveCallbackForward},
1242bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *                or null if any parameter is null.
1243bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
1244bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public static AFMoveCallbackForward getNewInstance(
1245bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler handler, CameraProxy camera, CameraAFMoveCallback cb) {
1246bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            if (handler == null || camera == null || cb == null) {
1247bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                return null;
1248bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
1249bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return new AFMoveCallbackForward(handler, camera, cb);
1250bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1251bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1252bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private AFMoveCallbackForward(
1253bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler h, CameraProxy camera, CameraAFMoveCallback cb) {
1254bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler = h;
1255bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCamera = camera;
1256bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCallback = cb;
1257bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1258bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1259bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1260bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void onAutoFocusMoving(
1261bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final boolean moving, android.hardware.Camera camera) {
1262bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler.post(new Runnable() {
1263bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1264bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1265bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCallback.onAutoFocusMoving(moving, mCamera);
1266bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1267bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1268bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1269bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
1270bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1271bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    /**
1272bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     * A helper class to forward ShutterCallback to to another thread.
1273bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     */
1274bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static class ShutterCallbackForward implements ShutterCallback {
1275bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final Handler mHandler;
1276bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraShutterCallback mCallback;
1277bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraProxy mCamera;
1278bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1279bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
1280bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * Returns a new instance of {@link ShutterCallbackForward}.
1281bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *
1282bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param handler The handler in which the callback will be invoked in.
1283bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param camera  The {@link CameraProxy} which the callback is from.
1284bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param cb      The callback to be invoked.
1285bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @return        The instance of the {@link ShutterCallbackForward},
1286bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *                or null if any parameter is null.
1287bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
1288bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public static ShutterCallbackForward getNewInstance(
1289bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler handler, CameraProxy camera, CameraShutterCallback cb) {
1290bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            if (handler == null || camera == null || cb == null) {
1291bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                return null;
1292bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
1293bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return new ShutterCallbackForward(handler, camera, cb);
1294bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1295bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1296bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private ShutterCallbackForward(
1297bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler h, CameraProxy camera, CameraShutterCallback cb) {
1298bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler = h;
1299bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCamera = camera;
1300bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCallback = cb;
1301bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1302bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1303bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1304bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void onShutter() {
1305bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler.post(new Runnable() {
1306bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1307bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1308bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCallback.onShutter(mCamera);
1309bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1310bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1311bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1312bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
1313bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1314bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    /**
1315bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     * A helper class to forward PictureCallback to another thread.
1316bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     */
1317bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static class PictureCallbackForward implements PictureCallback {
1318bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final Handler mHandler;
1319bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraPictureCallback mCallback;
1320bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraProxy mCamera;
1321bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1322bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
1323bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * Returns a new instance of {@link PictureCallbackForward}.
1324bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *
1325bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param handler The handler in which the callback will be invoked in.
1326bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param camera  The {@link CameraProxy} which the callback is from.
1327bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param cb      The callback to be invoked.
1328bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @return        The instance of the {@link PictureCallbackForward},
1329bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *                or null if any parameters is null.
1330bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
1331bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public static PictureCallbackForward getNewInstance(
1332bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler handler, CameraProxy camera, CameraPictureCallback cb) {
1333bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            if (handler == null || camera == null || cb == null) {
1334bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                return null;
1335bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
1336bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return new PictureCallbackForward(handler, camera, cb);
1337bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1338bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1339bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private PictureCallbackForward(
1340bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler h, CameraProxy camera, CameraPictureCallback cb) {
1341bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler = h;
1342bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCamera = camera;
1343bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCallback = cb;
1344bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1345bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1346bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1347bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void onPictureTaken(
1348bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final byte[] data, android.hardware.Camera camera) {
1349bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler.post(new Runnable() {
1350bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1351bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1352bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCallback.onPictureTaken(data, mCamera);
1353bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1354bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1355bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1356bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
1357bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1358bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    /**
1359bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     * A helper class to forward PreviewCallback to another thread.
1360bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     */
1361bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static class PreviewCallbackForward implements PreviewCallback {
1362bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final Handler mHandler;
1363bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraPreviewDataCallback mCallback;
1364bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraProxy mCamera;
1365bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1366bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
1367bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * Returns a new instance of {@link PreviewCallbackForward}.
1368bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *
1369bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param handler The handler in which the callback will be invoked in.
1370bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param camera  The {@link CameraProxy} which the callback is from.
1371bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param cb      The callback to be invoked.
1372bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @return        The instance of the {@link PreviewCallbackForward},
1373bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *                or null if any parameters is null.
1374bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
1375bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public static PreviewCallbackForward getNewInstance(
1376bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler handler, CameraProxy camera, CameraPreviewDataCallback cb) {
1377bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            if (handler == null || camera == null || cb == null) {
1378bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                return null;
1379bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
1380bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return new PreviewCallbackForward(handler, camera, cb);
1381bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1382bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1383bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private PreviewCallbackForward(
1384bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler h, CameraProxy camera, CameraPreviewDataCallback cb) {
1385bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler = h;
1386bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCamera = camera;
1387bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCallback = cb;
1388bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1389bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1390bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1391bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void onPreviewFrame(
1392bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final byte[] data, android.hardware.Camera camera) {
1393bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler.post(new Runnable() {
1394bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1395bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1396bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCallback.onPreviewFrame(data, mCamera);
1397bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1398bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1399bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1400bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
1401bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1402bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static class FaceDetectionCallbackForward implements FaceDetectionListener {
1403bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final Handler mHandler;
1404bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraFaceDetectionCallback mCallback;
1405bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraProxy mCamera;
1406bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1407bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
1408bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * Returns a new instance of {@link FaceDetectionCallbackForward}.
1409bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *
1410bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param handler The handler in which the callback will be invoked in.
1411bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param camera  The {@link CameraProxy} which the callback is from.
1412bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param cb      The callback to be invoked.
1413bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @return        The instance of the {@link FaceDetectionCallbackForward},
1414bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *                or null if any parameter is null.
1415bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
1416bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public static FaceDetectionCallbackForward getNewInstance(
1417bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler handler, CameraProxy camera, CameraFaceDetectionCallback cb) {
1418bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            if (handler == null || camera == null || cb == null) {
1419bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                return null;
1420bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
1421bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return new FaceDetectionCallbackForward(handler, camera, cb);
1422bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1423bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1424bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private FaceDetectionCallbackForward(
1425bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler h, CameraProxy camera, CameraFaceDetectionCallback cb) {
1426bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler = h;
1427bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCamera = camera;
1428bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCallback = cb;
1429bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1430bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1431bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1432bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void onFaceDetection(
1433bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                final Camera.Face[] faces, Camera camera) {
1434bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler.post(new Runnable() {
1435bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1436bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1437bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCallback.onFaceDetection(faces, mCamera);
1438bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1439bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1440bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1441bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
1442bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1443bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    /**
1444bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     * A callback helps to invoke the original callback on another
1445bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     * {@link android.os.Handler}.
1446bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong     */
1447bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static class CameraOpenCallbackForward implements CameraOpenCallback {
1448bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final Handler mHandler;
1449bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraOpenCallback mCallback;
1450bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1451bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        /**
1452bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * Returns a new instance of {@link FaceDetectionCallbackForward}.
1453bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *
1454bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param handler The handler in which the callback will be invoked in.
1455bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @param cb The callback to be invoked.
1456bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         * @return The instance of the {@link FaceDetectionCallbackForward}, or
1457bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         *         null if any parameter is null.
1458bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong         */
1459bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public static CameraOpenCallbackForward getNewInstance(
1460bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler handler, CameraOpenCallback cb) {
1461bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            if (handler == null || cb == null) {
1462bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                return null;
1463bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
1464bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return new CameraOpenCallbackForward(handler, cb);
1465bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1466bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1467bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private CameraOpenCallbackForward(Handler h, CameraOpenCallback cb) {
1468bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            // Given that we are using the main thread handler, we can create it
1469bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            // here instead of holding onto the PhotoModule objects. In this
1470bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            // way, we can avoid memory leak.
1471bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler = new Handler(Looper.getMainLooper());
1472bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCallback = cb;
1473bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1474bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1475bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1476bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void onCameraOpened(final CameraProxy camera) {
1477bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler.post(new Runnable() {
1478bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1479bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1480bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCallback.onCameraOpened(camera);
1481bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1482bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1483bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1484bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1485bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1486bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void onCameraDisabled(final int cameraId) {
1487bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler.post(new Runnable() {
1488bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1489bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1490bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCallback.onCameraDisabled(cameraId);
1491bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1492bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1493bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1494bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1495bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1496b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong        public void onDeviceOpenFailure(final int cameraId, final String info) {
1497bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler.post(new Runnable() {
1498bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1499bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1500b00b7a67213ee6868eb792b2a63ba0dca888a01fAngus Kong                    mCallback.onDeviceOpenFailure(cameraId, info);
1501bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1502bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1503bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1504bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1505bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1506bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void onDeviceOpenedAlready(final int cameraId) {
1507bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler.post(new Runnable() {
1508bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1509bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1510bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCallback.onDeviceOpenedAlready(cameraId);
1511bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1512bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1513bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1514bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1515bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1516bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void onReconnectionFailure(final CameraManager mgr) {
1517bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler.post(new Runnable() {
1518bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1519bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1520bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCallback.onReconnectionFailure(mgr);
1521bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1522bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1523bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1524bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
1525bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1526bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    private static class CameraStartPreviewCallbackForward
1527bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            implements CameraStartPreviewCallback {
1528bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final Handler mHandler;
1529bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private final CameraStartPreviewCallback mCallback;
1530bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1531bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public static CameraStartPreviewCallbackForward getNewInstance(
1532bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                Handler handler, CameraStartPreviewCallback cb) {
1533bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            if (handler == null || cb == null) {
1534bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                return null;
1535bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            }
1536bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            return new CameraStartPreviewCallbackForward(handler, cb);
1537bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1538bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1539bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        private CameraStartPreviewCallbackForward(Handler h,
1540bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                CameraStartPreviewCallback cb) {
1541bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler = h;
1542bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mCallback = cb;
1543bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1544bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong
1545bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        @Override
1546bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        public void onPreviewStarted() {
1547bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            mHandler.post(new Runnable() {
1548bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                @Override
1549bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                public void run() {
1550bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                    mCallback.onPreviewStarted();
1551bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong                }
1552bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong            });
1553bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong        }
1554bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong    }
1555bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong}
1556