AutoFocusStateMachine.java revision 2d8e55f45e52ac0b18c0e46de602e6a6d5ab1001
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.CameraMetadata.Key;
20import android.hardware.camera2.CaptureRequest;
21import android.hardware.camera2.CaptureResult;
22import android.util.Log;
23
24import com.android.ex.camera2.utils.SysTrace;
25
26/**
27 * Manage the auto focus state machine for CameraDevice.
28 *
29 * <p>Requests are created only when the AF needs to be manipulated from the user,
30 * but automatic camera-caused AF state changes are broadcasted from any new result.</p>
31 */
32public class AutoFocusStateMachine {
33
34    public interface AutoFocusStateListener {
35        /**
36         * The camera is currently focused (either active or passive).
37         *
38         * @param locked True if the lens has been locked from moving, false otherwise.
39         */
40        void onAutoFocusSuccess(CaptureResult result, boolean locked);
41
42        /**
43         * The camera is currently not focused (either active or passive).
44         *
45         * @param locked False if the AF is still scanning, true if needs a restart.
46         */
47        void onAutoFocusFail(CaptureResult result, boolean locked);
48
49        /**
50         * The camera is currently scanning (either active or passive)
51         * and has not yet converged.
52         *
53         * <p>This is not called for results where the AF either succeeds or fails.</p>
54         */
55        void onAutoFocusScan(CaptureResult result);
56
57        /**
58         * The camera is currently not doing anything with the autofocus.
59         *
60         * <p>Autofocus could be off, or this could be an intermediate state transition as
61         * scanning restarts.</p>
62         */
63        void onAutoFocusInactive(CaptureResult result);
64    }
65
66    private static final String TAG = "AutoFocusStateMachine";
67    private static final boolean DEBUG_LOGGING = Log.isLoggable(TAG, Log.DEBUG);
68    private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE);
69    private static final int AF_UNINITIALIZED = -1;
70
71    private final AutoFocusStateListener mListener;
72    private int mLastAfState = AF_UNINITIALIZED;
73    private int mLastAfMode = AF_UNINITIALIZED;
74    private int mCurrentAfMode = AF_UNINITIALIZED;
75    private int mCurrentAfTrigger = AF_UNINITIALIZED;
76
77    private int mCurrentAfCookie = AF_UNINITIALIZED;
78    private String mCurrentAfTrace = "";
79    private int mLastAfCookie = 0;
80
81    public AutoFocusStateMachine(AutoFocusStateListener listener) {
82        if (listener == null) {
83            throw new IllegalArgumentException("listener should not be null");
84        }
85        mListener = listener;
86    }
87
88    /**
89     * Invoke every time we get a new CaptureResult via
90     * {@link CameraDevice.CaptureListener#onCaptureCompleted}.
91     *
92     * <p>This function is responsible for dispatching updates via the
93     * {@link AutoFocusStateListener} so without calling this on a regular basis, no
94     * AF changes will be observed.</p>
95     *
96     * @param result CaptureResult
97     */
98    public synchronized void onCaptureCompleted(CaptureResult result) {
99
100        /**
101         * Work-around for b/11269834
102         * Although these should never-ever happen, harden for ship
103         */
104        if (result == null) {
105            Log.w(TAG, "onCaptureCompleted - missing result, skipping AF update");
106            return;
107        }
108
109        Key<Integer> keyAfState = CaptureResult.CONTROL_AF_STATE;
110        if (keyAfState == null) {
111            Log.e(TAG, "onCaptureCompleted - missing android.control.afState key, " +
112                    "skipping AF update");
113            return;
114        }
115
116        Key<Integer> keyAfMode = CaptureResult.CONTROL_AF_MODE;
117        if (keyAfMode == null) {
118            Log.e(TAG, "onCaptureCompleted - missing android.control.afMode key, " +
119                    "skipping AF update");
120            return;
121        }
122
123        Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
124        Integer afMode = result.get(CaptureResult.CONTROL_AF_MODE);
125
126        /**
127         * Work-around for b/11238865
128         * This is a HAL bug as these fields should be there always.
129         */
130        if (afState == null) {
131            Log.w(TAG, "onCaptureCompleted - missing android.control.afState !");
132            return;
133        } else if (afMode == null) {
134            Log.w(TAG, "onCaptureCompleted - missing android.control.afMode !");
135            return;
136        }
137
138        if (DEBUG_LOGGING) Log.d(TAG, "onCaptureCompleted - new AF mode = " + afMode +
139                " new AF state = " + afState);
140
141        if (mLastAfState == afState && afMode == mLastAfMode) {
142            // Same AF state as last time, nothing else needs to be done.
143            return;
144        }
145
146        if (VERBOSE_LOGGING) Log.v(TAG, "onCaptureCompleted - new AF mode = " + afMode +
147                " new AF state = " + afState);
148
149        mLastAfState = afState;
150        mLastAfMode = afMode;
151
152        switch (afState) {
153            case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED:
154                mListener.onAutoFocusSuccess(result, /*locked*/true);
155                endTraceAsync();
156                break;
157            case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
158                mListener.onAutoFocusFail(result, /*locked*/true);
159                endTraceAsync();
160                break;
161            case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED:
162                mListener.onAutoFocusSuccess(result, /*locked*/false);
163                break;
164            case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
165                mListener.onAutoFocusFail(result, /*locked*/false);
166                break;
167            case CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN:
168                mListener.onAutoFocusScan(result);
169                break;
170            case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN:
171                mListener.onAutoFocusScan(result);
172                break;
173            case CaptureResult.CONTROL_AF_STATE_INACTIVE:
174                mListener.onAutoFocusInactive(result);
175                break;
176        }
177    }
178
179    /**
180     * Lock the lens from moving. Typically used before taking a picture.
181     *
182     * <p>After calling this function, submit the new requestBuilder as a separate capture.
183     * Do not submit it as a repeating request or the AF lock will be repeated every time.</p>
184     *
185     * <p>Create a new repeating request from repeatingBuilder and set that as the updated
186     * repeating request.</p>
187     *
188     * <p>If the lock succeeds, {@link AutoFocusStateListener#onAutoFocusSuccess} with
189     * {@code locked == true} will be invoked. If the lock fails,
190     * {@link AutoFocusStateListener#onAutoFocusFail} with {@code scanning == false} will be
191     * invoked.</p>
192     *
193     * @param repeatingBuilder Builder for a repeating request.
194     * @param requestBuilder Builder for a non-repeating request.
195     *
196     */
197    public synchronized void lockAutoFocus(CaptureRequest.Builder repeatingBuilder,
198            CaptureRequest.Builder requestBuilder) {
199
200        if (VERBOSE_LOGGING) Log.v(TAG, "lockAutoFocus");
201
202        if (mCurrentAfMode == AF_UNINITIALIZED) {
203            throw new IllegalStateException("AF mode was not enabled");
204        }
205
206        beginTraceAsync("AFSM_lockAutoFocus");
207
208        mCurrentAfTrigger = CaptureRequest.CONTROL_AF_TRIGGER_START;
209
210        repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
211        requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
212
213        repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
214                CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
215        requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
216                CaptureRequest.CONTROL_AF_TRIGGER_START);
217    }
218
219    /**
220     * Unlock the lens, allowing it to move again. Typically used after taking a picture.
221     *
222     * <p>After calling this function, submit the new requestBuilder as a separate capture.
223     * Do not submit it as a repeating request or the AF lock will be repeated every time.</p>
224     *
225     * <p>Create a new repeating request from repeatingBuilder and set that as the updated
226     * repeating request.</p>
227     *
228     * <p>Once the unlock takes effect, {@link AutoFocusStateListener#onAutoFocusInactive} is
229     * invoked, and after that the effects depend on which mode you were in:
230     * <ul>
231     * <li>Passive - Scanning restarts with {@link AutoFocusStateListener#onAutoFocusScan}</li>
232     * <li>Active - The lens goes back to a default position (no callbacks)</li>
233     * </ul>
234     * </p>
235     *
236     * @param repeatingBuilder Builder for a repeating request.
237     * @param requestBuilder Builder for a non-repeating request.
238     *
239     */
240    public synchronized void unlockAutoFocus(CaptureRequest.Builder repeatingBuilder,
241            CaptureRequest.Builder requestBuilder) {
242
243        if (VERBOSE_LOGGING) Log.v(TAG, "unlockAutoFocus");
244
245        if (mCurrentAfMode == AF_UNINITIALIZED) {
246            throw new IllegalStateException("AF mode was not enabled");
247        }
248
249        mCurrentAfTrigger = CaptureRequest.CONTROL_AF_TRIGGER_CANCEL;
250
251        repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
252        requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
253
254        repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
255                CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
256        requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
257                CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
258    }
259
260    /**
261     * Enable active auto focus, immediately triggering a converging scan.
262     *
263     * <p>This is typically only used when locking the passive AF has failed.</p>
264     *
265     * <p>Once active AF scanning starts, {@link AutoFocusStateListener#onAutoFocusScan} will be
266     * invoked.</p>
267     *
268     * <p>If the active scan succeeds, {@link AutoFocusStateListener#onAutoFocusSuccess} with
269     * {@code locked == true} will be invoked. If the active scan fails,
270     * {@link AutoFocusStateListener#onAutoFocusFail} with {@code scanning == false} will be
271     * invoked.</p>
272     *
273     * <p>After calling this function, submit the new requestBuilder as a separate capture.
274     * Do not submit it as a repeating request or the AF trigger will be repeated every time.</p>
275     *
276     * <p>Create a new repeating request from repeatingBuilder and set that as the updated
277     * repeating request.</p>
278     *
279     * @param repeatingBuilder Builder for a repeating request.
280     * @param requestBuilder Builder for a non-repeating request.
281     *
282     * @param repeatingBuilder Builder for a repeating request.
283     */
284    public synchronized void setActiveAutoFocus(CaptureRequest.Builder repeatingBuilder,
285            CaptureRequest.Builder requestBuilder) {
286        if (VERBOSE_LOGGING) Log.v(TAG, "setActiveAutoFocus");
287
288        beginTraceAsync("AFSM_setActiveAutoFocus");
289
290        mCurrentAfMode = CaptureRequest.CONTROL_AF_MODE_AUTO;
291
292        repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
293        requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
294
295        repeatingBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
296                CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
297        requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
298                CaptureRequest.CONTROL_AF_TRIGGER_START);
299    }
300
301    /**
302     * Enable passive autofocus, immediately triggering a non-converging scan.
303     *
304     * <p>While passive autofocus is enabled, use {@link #lockAutoFocus} to lock
305     * the lens before taking a picture. Once a picture is taken, use {@link #unlockAutoFocus}
306     * to let the lens go back into passive scanning.</p>
307     *
308     * <p>Once passive AF scanning starts, {@link AutoFocusStateListener#onAutoFocusScan} will be
309     * invoked.</p>
310     *
311     * @param repeatingBuilder Builder for a repeating request.
312     * @param picture True for still capture AF, false for video AF.
313     */
314    public synchronized void setPassiveAutoFocus(boolean picture,
315            CaptureRequest.Builder repeatingBuilder) {
316        if (VERBOSE_LOGGING) Log.v(TAG, "setPassiveAutoFocus - picture " + picture);
317
318        if (picture) {
319            mCurrentAfMode = CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
320        } else {
321            mCurrentAfMode = CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO;
322        }
323
324        repeatingBuilder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentAfMode);
325    }
326
327    private synchronized void beginTraceAsync(String sectionName) {
328        if (mCurrentAfCookie != AF_UNINITIALIZED) {
329            // Terminate any currently active async sections before beginning another section
330            SysTrace.endSectionAsync(mCurrentAfTrace, mCurrentAfCookie);
331        }
332
333        mLastAfCookie++;
334        mCurrentAfCookie = mLastAfCookie;
335        mCurrentAfTrace = sectionName;
336
337        SysTrace.beginSectionAsync(sectionName, mCurrentAfCookie);
338    }
339
340    private synchronized void endTraceAsync() {
341        if (mCurrentAfCookie == AF_UNINITIALIZED) {
342            Log.w(TAG, "endTraceAsync - no current trace active");
343            return;
344        }
345
346        SysTrace.endSectionAsync(mCurrentAfTrace, mCurrentAfCookie);
347        mCurrentAfCookie = AF_UNINITIALIZED;
348    }
349}
350