LegacyFocusStateMapper.java revision 0a1ef4dbf39aa3dfae1a91daf972ae3457ce27fe
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.hardware.camera2.legacy;
18
19import android.hardware.Camera;
20import android.hardware.Camera.Parameters;
21import android.hardware.camera2.impl.CameraMetadataNative;
22import android.hardware.camera2.CaptureRequest;
23import android.hardware.camera2.CaptureResult;
24import android.hardware.camera2.utils.ParamsUtils;
25import android.util.Log;
26
27import java.util.Objects;
28
29import static android.hardware.camera2.CaptureRequest.*;
30import static com.android.internal.util.Preconditions.*;
31
32/**
33 * Map capture request data into legacy focus state transitions.
34 *
35 * <p>This object will asynchronously process auto-focus changes, so no interaction
36 * with it is necessary beyond reading the current state and updating with the latest trigger.</p>
37 */
38@SuppressWarnings("deprecation")
39public class LegacyFocusStateMapper {
40    private static String TAG = "LegacyFocusStateMapper";
41    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
42
43    private final Camera mCamera;
44
45    private int mAfStatePrevious = CONTROL_AF_STATE_INACTIVE;
46    private String mAfModePrevious = null;
47
48    /** Guard mAfRun and mAfState */
49    private final Object mLock = new Object();
50    /** Guard access with mLock */
51    private int mAfRun = 0;
52    /** Guard access with mLock */
53    private int mAfState = CONTROL_AF_STATE_INACTIVE;
54
55    /**
56     * Instantiate a new focus state mapper.
57     *
58     * @param camera a non-{@code null} camera1 device
59     *
60     * @throws NullPointerException if any of the args were {@code null}
61     */
62    public LegacyFocusStateMapper(Camera camera) {
63        mCamera = checkNotNull(camera, "camera must not be null");
64    }
65
66    /**
67     * Process the AF triggers from the request as a camera1 autofocus routine.
68     *
69     * <p>This method should be called after the parameters are {@link LegacyRequestMapper mapped}
70     * with the request.</p>
71     *
72     * <p>Callbacks are processed in the background, and the next call to {@link #mapResultTriggers}
73     * will have the latest AF state as reflected by the camera1 callbacks.</p>
74     *
75     * <p>None of the arguments will be mutated.</p>
76     *
77     * @param captureRequest a non-{@code null} request
78     * @param parameters a non-{@code null} parameters corresponding to this request (read-only)
79     */
80    public void processRequestTriggers(CaptureRequest captureRequest,
81            Camera.Parameters parameters) {
82        checkNotNull(captureRequest, "captureRequest must not be null");
83
84        /*
85         * control.afTrigger
86         */
87        int afTrigger = ParamsUtils.getOrDefault(captureRequest, CONTROL_AF_TRIGGER,
88                CONTROL_AF_TRIGGER_IDLE);
89
90        final String afMode = parameters.getFocusMode();
91
92        if (!Objects.equals(mAfModePrevious, afMode)) {
93            if (VERBOSE) {
94                Log.v(TAG, "processRequestTriggers - AF mode switched from " + mAfModePrevious +
95                        " to " + afMode);
96            }
97
98            // Switching modes always goes back to INACTIVE; ignore callbacks from previous modes
99
100            synchronized (mLock) {
101                ++mAfRun;
102                mAfState = CONTROL_AF_STATE_INACTIVE;
103            }
104            mCamera.cancelAutoFocus();
105        }
106
107        mAfModePrevious = afMode;
108
109        // Passive AF Scanning
110        {
111            final int currentAfRun;
112
113            synchronized (mLock) {
114                currentAfRun = mAfRun;
115            }
116
117            mCamera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() {
118                @Override
119                public void onAutoFocusMoving(boolean start, Camera camera) {
120                    synchronized (mLock) {
121                        int latestAfRun = mAfRun;
122
123                        if (VERBOSE) {
124                            Log.v(TAG, "onAutoFocusMoving - start " + start + " latest AF run " +
125                                    latestAfRun + ", last AF run " + currentAfRun);
126                        }
127
128                        if (currentAfRun != latestAfRun) {
129                            Log.d(TAG,
130                                    "onAutoFocusMoving - ignoring move callbacks from old af run"
131                                            + currentAfRun);
132                            return;
133                        }
134
135                        int newAfState = start ?
136                                CONTROL_AF_STATE_PASSIVE_SCAN :
137                                CONTROL_AF_STATE_PASSIVE_FOCUSED;
138                        // We never send CONTROL_AF_STATE_PASSIVE_UNFOCUSED
139
140                        switch (afMode) {
141                            case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
142                            case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
143                                break;
144                            // This callback should never be sent in any other AF mode
145                            default:
146                                Log.w(TAG, "onAutoFocus - got unexpected onAutoFocus in mode "
147                                        + afMode);
148
149                        }
150
151                        mAfState = newAfState;
152                    }
153                }
154            });
155        }
156
157        // AF Locking
158        switch (afTrigger) {
159            case CONTROL_AF_TRIGGER_START:
160
161                int afStateAfterStart;
162                switch (afMode) {
163                    case Parameters.FOCUS_MODE_AUTO:
164                    case Parameters.FOCUS_MODE_MACRO:
165                        afStateAfterStart = CONTROL_AF_STATE_ACTIVE_SCAN;
166                        break;
167                    case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
168                    case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
169                        afStateAfterStart = CONTROL_AF_STATE_PASSIVE_SCAN;
170                    default:
171                        // EDOF, INFINITY
172                        afStateAfterStart = CONTROL_AF_STATE_INACTIVE;
173                }
174
175                final int currentAfRun;
176                synchronized (mLock) {
177                    currentAfRun = ++mAfRun;
178                    mAfState = afStateAfterStart;
179                }
180
181                if (VERBOSE) {
182                    Log.v(TAG, "processRequestTriggers - got AF_TRIGGER_START, " +
183                            "new AF run is " + currentAfRun);
184                }
185
186                mCamera.autoFocus(new Camera.AutoFocusCallback() {
187                    @Override
188                    public void onAutoFocus(boolean success, Camera camera) {
189                        synchronized (mLock) {
190                            int latestAfRun = mAfRun;
191
192                            if (VERBOSE) {
193                                Log.v(TAG, "onAutoFocus - success " + success + " latest AF run " +
194                                        latestAfRun + ", last AF run " + currentAfRun);
195                            }
196
197                            // Ignore old auto-focus results, since another trigger was requested
198                            if (latestAfRun != currentAfRun) {
199                                Log.d(TAG, String.format("onAutoFocus - ignoring AF callback " +
200                                        "(old run %d, new run %d)", currentAfRun, latestAfRun));
201
202                                return;
203                            }
204
205                            int newAfState = success ?
206                                    CONTROL_AF_STATE_FOCUSED_LOCKED :
207                                    CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
208
209                            switch (afMode) {
210                                case Parameters.FOCUS_MODE_AUTO:
211                                case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
212                                case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
213                                case Parameters.FOCUS_MODE_MACRO:
214                                    break;
215                                // This callback should never be sent in any other AF mode
216                                default:
217                                    Log.w(TAG, "onAutoFocus - got unexpected onAutoFocus in mode "
218                                            + afMode);
219
220                            }
221
222                            mAfState = newAfState;
223                        }
224                    }
225                });
226
227                break;
228            case CONTROL_AF_TRIGGER_CANCEL:
229                synchronized (mLock) {
230                    int updatedAfRun;
231
232                    synchronized (mLock) {
233                        updatedAfRun = ++mAfRun;
234                        mAfState = CONTROL_AF_STATE_INACTIVE;
235                    }
236
237                    mCamera.cancelAutoFocus();
238
239                    if (VERBOSE) {
240                        Log.v(TAG, "processRequestTriggers - got AF_TRIGGER_CANCEL, " +
241                                "new AF run is " + updatedAfRun);
242                    }
243                }
244
245                break;
246            case CONTROL_AF_TRIGGER_IDLE:
247                // No action necessary. The callbacks will handle transitions.
248                break;
249            default:
250                Log.w(TAG, "processRequestTriggers - ignoring unknown control.afTrigger = "
251                        + afTrigger);
252        }
253    }
254
255    /**
256     * Update the {@code result} camera metadata map with the new value for the
257     * {@code control.afState}.
258     *
259     * <p>AF callbacks are processed in the background, and each call to {@link #mapResultTriggers}
260     * will have the latest AF state as reflected by the camera1 callbacks.</p>
261     *
262     * @param result a non-{@code null} result
263     */
264    public void mapResultTriggers(CameraMetadataNative result) {
265        checkNotNull(result, "result must not be null");
266
267        int newAfState;
268        synchronized (mLock) {
269            newAfState = mAfState;
270        }
271
272        if (VERBOSE && newAfState != mAfStatePrevious) {
273            Log.v(TAG, String.format("mapResultTriggers - afState changed from %s to %s",
274                    afStateToString(mAfStatePrevious), afStateToString(newAfState)));
275        }
276
277        result.set(CaptureResult.CONTROL_AF_STATE, newAfState);
278
279        mAfStatePrevious = newAfState;
280    }
281
282    private static String afStateToString(int afState) {
283        switch (afState) {
284            case CONTROL_AF_STATE_ACTIVE_SCAN:
285                return "ACTIVE_SCAN";
286            case CONTROL_AF_STATE_FOCUSED_LOCKED:
287                return "FOCUSED_LOCKED";
288            case CONTROL_AF_STATE_INACTIVE:
289                return "INACTIVE";
290            case CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
291                return "NOT_FOCUSED_LOCKED";
292            case CONTROL_AF_STATE_PASSIVE_FOCUSED:
293                return "PASSIVE_FOCUSED";
294            case CONTROL_AF_STATE_PASSIVE_SCAN:
295                return "PASSIVE_SCAN";
296            case CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
297                return "PASSIVE_UNFOCUSED";
298            default :
299                return "UNKNOWN(" + afState + ")";
300        }
301    }
302}
303