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