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 
17 package android.hardware.camera2.legacy;
18 
19 import android.hardware.Camera;
20 import android.hardware.Camera.Parameters;
21 import android.hardware.camera2.impl.CameraMetadataNative;
22 import android.hardware.camera2.CaptureRequest;
23 import android.hardware.camera2.CaptureResult;
24 import android.hardware.camera2.utils.ParamsUtils;
25 import android.util.Log;
26 
27 import java.util.Objects;
28 
29 import static android.hardware.camera2.CaptureRequest.*;
30 import 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")
39 public class LegacyFocusStateMapper {
40     private static String TAG = "LegacyFocusStateMapper";
41     private static final boolean DEBUG = false;
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      */
LegacyFocusStateMapper(Camera camera)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      */
processRequestTriggers(CaptureRequest captureRequest, Camera.Parameters parameters)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 (DEBUG) {
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             Camera.AutoFocusMoveCallback afMoveCallback = new Camera.AutoFocusMoveCallback() {
118                 @Override
119                 public void onAutoFocusMoving(boolean start, Camera camera) {
120                     synchronized (mLock) {
121                         int latestAfRun = mAfRun;
122 
123                         if (DEBUG) {
124                             Log.v(TAG,
125                                     "onAutoFocusMoving - start " + start + " latest AF run " +
126                                             latestAfRun + ", last AF run " + currentAfRun
127                             );
128                         }
129 
130                         if (currentAfRun != latestAfRun) {
131                             Log.d(TAG,
132                                     "onAutoFocusMoving - ignoring move callbacks from old af run"
133                                             + currentAfRun
134                             );
135                             return;
136                         }
137 
138                         int newAfState = start ?
139                                 CONTROL_AF_STATE_PASSIVE_SCAN :
140                                 CONTROL_AF_STATE_PASSIVE_FOCUSED;
141                         // We never send CONTROL_AF_STATE_PASSIVE_UNFOCUSED
142 
143                         switch (afMode) {
144                             case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
145                             case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
146                                 break;
147                             // This callback should never be sent in any other AF mode
148                             default:
149                                 Log.w(TAG, "onAutoFocus - got unexpected onAutoFocus in mode "
150                                         + afMode);
151 
152                         }
153 
154                         mAfState = newAfState;
155                     }
156                 }
157             };
158 
159             // Only set move callback if we can call autofocus.
160             switch (afMode) {
161                 case Parameters.FOCUS_MODE_AUTO:
162                 case Parameters.FOCUS_MODE_MACRO:
163                 case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
164                 case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
165                     mCamera.setAutoFocusMoveCallback(afMoveCallback);
166             }
167         }
168 
169 
170         // AF Locking
171         switch (afTrigger) {
172             case CONTROL_AF_TRIGGER_START:
173 
174                 int afStateAfterStart;
175                 switch (afMode) {
176                     case Parameters.FOCUS_MODE_AUTO:
177                     case Parameters.FOCUS_MODE_MACRO:
178                         afStateAfterStart = CONTROL_AF_STATE_ACTIVE_SCAN;
179                         break;
180                     case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
181                     case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
182                         afStateAfterStart = CONTROL_AF_STATE_PASSIVE_SCAN;
183                         break;
184                     default:
185                         // EDOF, INFINITY
186                         afStateAfterStart = CONTROL_AF_STATE_INACTIVE;
187                 }
188 
189                 final int currentAfRun;
190                 synchronized (mLock) {
191                     currentAfRun = ++mAfRun;
192                     mAfState = afStateAfterStart;
193                 }
194 
195                 if (DEBUG) {
196                     Log.v(TAG, "processRequestTriggers - got AF_TRIGGER_START, " +
197                             "new AF run is " + currentAfRun);
198                 }
199 
200                 // Avoid calling autofocus unless we are in a state that supports calling this.
201                 if (afStateAfterStart == CONTROL_AF_STATE_INACTIVE) {
202                     break;
203                 }
204 
205                 mCamera.autoFocus(new Camera.AutoFocusCallback() {
206                     @Override
207                     public void onAutoFocus(boolean success, Camera camera) {
208                         synchronized (mLock) {
209                             int latestAfRun = mAfRun;
210 
211                             if (DEBUG) {
212                                 Log.v(TAG, "onAutoFocus - success " + success + " latest AF run " +
213                                         latestAfRun + ", last AF run " + currentAfRun);
214                             }
215 
216                             // Ignore old auto-focus results, since another trigger was requested
217                             if (latestAfRun != currentAfRun) {
218                                 Log.d(TAG, String.format("onAutoFocus - ignoring AF callback " +
219                                         "(old run %d, new run %d)", currentAfRun, latestAfRun));
220 
221                                 return;
222                             }
223 
224                             int newAfState = success ?
225                                     CONTROL_AF_STATE_FOCUSED_LOCKED :
226                                     CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
227 
228                             switch (afMode) {
229                                 case Parameters.FOCUS_MODE_AUTO:
230                                 case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
231                                 case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
232                                 case Parameters.FOCUS_MODE_MACRO:
233                                     break;
234                                 // This callback should never be sent in any other AF mode
235                                 default:
236                                     Log.w(TAG, "onAutoFocus - got unexpected onAutoFocus in mode "
237                                             + afMode);
238 
239                             }
240 
241                             mAfState = newAfState;
242                         }
243                     }
244                 });
245 
246                 break;
247             case CONTROL_AF_TRIGGER_CANCEL:
248                 synchronized (mLock) {
249                     int updatedAfRun;
250 
251                     synchronized (mLock) {
252                         updatedAfRun = ++mAfRun;
253                         mAfState = CONTROL_AF_STATE_INACTIVE;
254                     }
255 
256                     mCamera.cancelAutoFocus();
257 
258                     if (DEBUG) {
259                         Log.v(TAG, "processRequestTriggers - got AF_TRIGGER_CANCEL, " +
260                                 "new AF run is " + updatedAfRun);
261                     }
262                 }
263 
264                 break;
265             case CONTROL_AF_TRIGGER_IDLE:
266                 // No action necessary. The callbacks will handle transitions.
267                 break;
268             default:
269                 Log.w(TAG, "processRequestTriggers - ignoring unknown control.afTrigger = "
270                         + afTrigger);
271         }
272     }
273 
274     /**
275      * Update the {@code result} camera metadata map with the new value for the
276      * {@code control.afState}.
277      *
278      * <p>AF callbacks are processed in the background, and each call to {@link #mapResultTriggers}
279      * will have the latest AF state as reflected by the camera1 callbacks.</p>
280      *
281      * @param result a non-{@code null} result
282      */
mapResultTriggers(CameraMetadataNative result)283     public void mapResultTriggers(CameraMetadataNative result) {
284         checkNotNull(result, "result must not be null");
285 
286         int newAfState;
287         synchronized (mLock) {
288             newAfState = mAfState;
289         }
290 
291         if (DEBUG && newAfState != mAfStatePrevious) {
292             Log.v(TAG, String.format("mapResultTriggers - afState changed from %s to %s",
293                     afStateToString(mAfStatePrevious), afStateToString(newAfState)));
294         }
295 
296         result.set(CaptureResult.CONTROL_AF_STATE, newAfState);
297 
298         mAfStatePrevious = newAfState;
299     }
300 
afStateToString(int afState)301     private static String afStateToString(int afState) {
302         switch (afState) {
303             case CONTROL_AF_STATE_ACTIVE_SCAN:
304                 return "ACTIVE_SCAN";
305             case CONTROL_AF_STATE_FOCUSED_LOCKED:
306                 return "FOCUSED_LOCKED";
307             case CONTROL_AF_STATE_INACTIVE:
308                 return "INACTIVE";
309             case CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
310                 return "NOT_FOCUSED_LOCKED";
311             case CONTROL_AF_STATE_PASSIVE_FOCUSED:
312                 return "PASSIVE_FOCUSED";
313             case CONTROL_AF_STATE_PASSIVE_SCAN:
314                 return "PASSIVE_SCAN";
315             case CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
316                 return "PASSIVE_UNFOCUSED";
317             default :
318                 return "UNKNOWN(" + afState + ")";
319         }
320     }
321 }
322