AutoFocusStateMachine.java revision a47d6986cb4aa66e277c61df79a3947bbecd5de8
1/*
2 * Copyright 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.ex.camera2.pos;
17
18import android.hardware.camera2.CameraDevice;
19import android.hardware.camera2.CaptureRequest;
20import android.hardware.camera2.CaptureResult;
21import android.util.Log;
22
23/**
24 * Manage the auto focus state machine for CameraDevice.
25 *
26 * <p>Requests are created only when the AF needs to be manipulated from the user,
27 * but automatic camera-caused AF state changes are broadcasted from any new result.</p>
28 */
29public class AutoFocusStateMachine {
30
31    public interface AutoFocusStateListener {
32        /**
33         * The camera is currently focused (either active or passive).
34         *
35         * @param locked True if the lens has been locked from moving, false otherwise.
36         */
37        void onAutoFocusSuccess(CaptureResult result, boolean locked);
38
39        /**
40         * The camera is currently not focused (either active or passive).
41         *
42         * @param locked False if the AF is still scanning, true if needs a restart.
43         */
44        void onAutoFocusFail(CaptureResult result, boolean locked);
45
46        /**
47         * The camera is currently scanning (either active or passive)
48         * and has not yet converged.
49         *
50         * <p>This is not called for results where the AF either succeeds or fails.</p>
51         */
52        void onAutoFocusScan(CaptureResult result);
53
54        /**
55         * The camera is currently not doing anything with the autofocus.
56         *
57         * <p>Autofocus could be off, or this could be an intermediate state transition as
58         * scanning restarts.</p>
59         */
60        void onAutoFocusInactive(CaptureResult result);
61    }
62
63    private static final String TAG = "AutoFocusStateMachine";
64    private static final boolean DEBUG_LOGGING = Log.isLoggable(TAG, Log.DEBUG);
65    private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE);
66    private static final int AF_UNINITIALIZED = -1;
67
68    private final AutoFocusStateListener mListener;
69    private int mLastAfState = AF_UNINITIALIZED;
70    private int mLastAfMode = AF_UNINITIALIZED;
71    private int mCurrentAfMode = AF_UNINITIALIZED;
72    private int mCurrentAfTrigger = AF_UNINITIALIZED;
73
74    public AutoFocusStateMachine(AutoFocusStateListener listener) {
75        if (listener == null) {
76            throw new IllegalArgumentException("listener should not be null");
77        }
78        mListener = listener;
79    }
80
81    /**
82     * Invoke every time we get a new CaptureResult via
83     * {@link CameraDevice.CaptureListener#onCaptureCompleted}.
84     *
85     * <p>This function is responsible for dispatching updates via the
86     * {@link AutoFocusStateListener} so without calling this on a regular basis, no
87     * AF changes will be observed.</p>
88     *
89     * @param result CaptureResult
90     */
91    public synchronized void onCaptureCompleted(CaptureResult result) {
92
93        int afState = result.get(CaptureResult.CONTROL_AF_STATE);
94        int afMode = result.get(CaptureResult.CONTROL_AF_MODE);
95
96        if (DEBUG_LOGGING) Log.d(TAG, "onCaptureCompleted - new AF mode = " + afMode +
97                " new AF state = " + afState);
98
99        if (mLastAfState == afState && afMode == mLastAfMode) {
100            // Same AF state as last time, nothing else needs to be done.
101            return;
102        }
103
104        if (VERBOSE_LOGGING) Log.v(TAG, "onCaptureCompleted - new AF mode = " + afMode +
105                " new AF state = " + afState);
106
107        mLastAfState = afState;
108        mLastAfMode = afMode;
109
110        switch (afState) {
111            case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED:
112                mListener.onAutoFocusSuccess(result, /*locked*/true);
113                break;
114            case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
115                mListener.onAutoFocusFail(result, /*locked*/true);
116                break;
117            case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED:
118                mListener.onAutoFocusSuccess(result, /*locked*/false);
119                break;
120            case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
121                mListener.onAutoFocusFail(result, /*locked*/false);
122                break;
123            case CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN:
124                mListener.onAutoFocusScan(result);
125                break;
126            case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN:
127                mListener.onAutoFocusScan(result);
128                break;
129            case CaptureResult.CONTROL_AF_STATE_INACTIVE:
130                mListener.onAutoFocusInactive(result);
131                break;
132        }
133    }
134
135    /**
136     * Lock the lens from moving. Typically used before taking a picture.
137     *
138     * <p>After calling this function, submit the new requestBuilder as a separate capture.
139     * Do not submit it as a repeating request or the AF lock will be repeated every time.</p>
140     *
141     * <p>Create a new repeating request from repeatingBuilder and set that as the updated
142     * repeating request.</p>
143     *
144     * <p>If the lock succeeds, {@link AutoFocusStateListener#onAutoFocusSuccess} with
145     * {@code locked == true} will be invoked. If the lock fails,
146     * {@link AutoFocusStateListener#onAutoFocusFail} with {@code scanning == false} will be
147     * invoked.</p>
148     *
149     * @param repeatingBuilder Builder for a repeating request.
150     * @param requestBuilder Builder for a non-repeating request.
151     *
152     */
153    public synchronized void lockAutoFocus(CaptureRequest.Builder repeatingBuilder,
154            CaptureRequest.Builder requestBuilder) {
155
156        if (VERBOSE_LOGGING) Log.v(TAG, "lockAutoFocus");
157
158        if (mCurrentAfMode == AF_UNINITIALIZED) {
159            throw new IllegalStateException("AF mode was not enabled");
160        }
161
162        mCurrentAfTrigger = CaptureRequest.CONTROL_AF_TRIGGER_START;
163
164        repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
165        requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
166
167        repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
168                CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
169        requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
170                CaptureRequest.CONTROL_AF_TRIGGER_START);
171    }
172
173    /**
174     * Unlock the lens, allowing it to move again. Typically used after taking a picture.
175     *
176     * <p>After calling this function, submit the new requestBuilder as a separate capture.
177     * Do not submit it as a repeating request or the AF lock will be repeated every time.</p>
178     *
179     * <p>Create a new repeating request from repeatingBuilder and set that as the updated
180     * repeating request.</p>
181     *
182     * <p>Once the unlock takes effect, {@link AutoFocusStateListener#onAutoFocusInactive} is
183     * invoked, and after that the effects depend on which mode you were in:
184     * <ul>
185     * <li>Passive - Scanning restarts with {@link AutoFocusStateListener#onAutoFocusScan}</li>
186     * <li>Active - The lens goes back to a default position (no callbacks)</li>
187     * </ul>
188     * </p>
189     *
190     * @param repeatingBuilder Builder for a repeating request.
191     * @param requestBuilder Builder for a non-repeating request.
192     *
193     */
194    public synchronized void unlockAutoFocus(CaptureRequest.Builder repeatingBuilder,
195            CaptureRequest.Builder requestBuilder) {
196
197        if (VERBOSE_LOGGING) Log.v(TAG, "unlockAutoFocus");
198
199        if (mCurrentAfMode == AF_UNINITIALIZED) {
200            throw new IllegalStateException("AF mode was not enabled");
201        }
202
203        mCurrentAfTrigger = CaptureRequest.CONTROL_AF_TRIGGER_CANCEL;
204
205        repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
206        requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
207
208        repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
209                CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
210        requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
211                CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
212    }
213
214    /**
215     * Enable active auto focus, immediately triggering a converging scan.
216     *
217     * <p>This is typically only used when locking the passive AF has failed.</p>
218     *
219     * <p>Once active AF scanning starts, {@link AutoFocusStateListener#onAutoFocusScan} will be
220     * invoked.</p>
221     *
222     * <p>If the active scan succeeds, {@link AutoFocusStateListener#onAutoFocusSuccess} with
223     * {@code locked == true} will be invoked. If the active scan fails,
224     * {@link AutoFocusStateListener#onAutoFocusFail} with {@code scanning == false} will be
225     * invoked.</p>
226     *
227     * <p>After calling this function, submit the new requestBuilder as a separate capture.
228     * Do not submit it as a repeating request or the AF trigger will be repeated every time.</p>
229     *
230     * <p>Create a new repeating request from repeatingBuilder and set that as the updated
231     * repeating request.</p>
232     *
233     * @param repeatingBuilder Builder for a repeating request.
234     * @param requestBuilder Builder for a non-repeating request.
235     *
236     * @param repeatingBuilder Builder for a repeating request.
237     */
238    public synchronized void setActiveAutoFocus(CaptureRequest.Builder repeatingBuilder,
239            CaptureRequest.Builder requestBuilder) {
240        if (VERBOSE_LOGGING) Log.v(TAG, "setActiveAutoFocus");
241
242        mCurrentAfMode = CaptureRequest.CONTROL_AF_MODE_AUTO;
243
244        repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
245        requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
246
247        repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
248                CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
249        requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
250                CaptureRequest.CONTROL_AF_TRIGGER_START);
251    }
252
253    /**
254     * Enable passive autofocus, immediately triggering a non-converging scan.
255     *
256     * <p>While passive autofocus is enabled, use {@link #lockAutoFocus} to lock
257     * the lens before taking a picture. Once a picture is taken, use {@link #unlockAutoFocus}
258     * to let the lens go back into passive scanning.</p>
259     *
260     * <p>Once passive AF scanning starts, {@link AutoFocusStateListener#onAutoFocusScan} will be
261     * invoked.</p>
262     *
263     * @param repeatingBuilder Builder for a repeating request.
264     * @param picture True for still capture AF, false for video AF.
265     */
266    public synchronized void setPassiveAutoFocus(boolean picture,
267            CaptureRequest.Builder repeatingBuilder) {
268        if (VERBOSE_LOGGING) Log.v(TAG, "setPassiveAutoFocus - picture " + picture);
269
270        if (picture) {
271            mCurrentAfMode = CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
272        } else {
273            mCurrentAfMode = CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO;
274        }
275
276        repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
277    }
278}
279