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