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.camera2.impl.CameraDeviceImpl; 20 import android.hardware.camera2.impl.CameraMetadataNative; 21 import android.os.Handler; 22 import android.util.Log; 23 24 /** 25 * Emulates a the state of a single Camera2 device. 26 * 27 * <p> 28 * This class acts as the state machine for a camera device. Valid state transitions are given 29 * in the table below: 30 * </p> 31 * 32 * <ul> 33 * <li>{@code UNCONFIGURED -> CONFIGURING}</li> 34 * <li>{@code CONFIGURING -> IDLE}</li> 35 * <li>{@code IDLE -> CONFIGURING}</li> 36 * <li>{@code IDLE -> CAPTURING}</li> 37 * <li>{@code IDLE -> IDLE}</li> 38 * <li>{@code CAPTURING -> IDLE}</li> 39 * <li>{@code ANY -> ERROR}</li> 40 * </ul> 41 */ 42 public class CameraDeviceState { 43 private static final String TAG = "CameraDeviceState"; 44 private static final boolean DEBUG = false; 45 46 private static final int STATE_ERROR = 0; 47 private static final int STATE_UNCONFIGURED = 1; 48 private static final int STATE_CONFIGURING = 2; 49 private static final int STATE_IDLE = 3; 50 private static final int STATE_CAPTURING = 4; 51 52 private static final String[] sStateNames = { "ERROR", "UNCONFIGURED", "CONFIGURING", "IDLE", 53 "CAPTURING"}; 54 55 private int mCurrentState = STATE_UNCONFIGURED; 56 private int mCurrentError = NO_CAPTURE_ERROR; 57 58 private RequestHolder mCurrentRequest = null; 59 60 private Handler mCurrentHandler = null; 61 private CameraDeviceStateListener mCurrentListener = null; 62 63 /** 64 * Error code used by {@link #setCaptureStart} and {@link #setCaptureResult} to indicate that no 65 * error has occurred. 66 */ 67 public static final int NO_CAPTURE_ERROR = -1; 68 69 /** 70 * CameraDeviceStateListener callbacks to be called after state transitions. 71 */ 72 public interface CameraDeviceStateListener { onError(int errorCode, Object errorArg, RequestHolder holder)73 void onError(int errorCode, Object errorArg, RequestHolder holder); onConfiguring()74 void onConfiguring(); onIdle()75 void onIdle(); onBusy()76 void onBusy(); onCaptureStarted(RequestHolder holder, long timestamp)77 void onCaptureStarted(RequestHolder holder, long timestamp); onCaptureResult(CameraMetadataNative result, RequestHolder holder)78 void onCaptureResult(CameraMetadataNative result, RequestHolder holder); onRepeatingRequestError(long lastFrameNumber)79 void onRepeatingRequestError(long lastFrameNumber); 80 } 81 82 /** 83 * Transition to the {@code ERROR} state. 84 * 85 * <p> 86 * The device cannot exit the {@code ERROR} state. If the device was not already in the 87 * {@code ERROR} state, {@link CameraDeviceStateListener#onError(int, RequestHolder)} will be 88 * called. 89 * </p> 90 * 91 * @param error the error to set. Should be one of the error codes defined in 92 * {@link CameraDeviceImpl.CameraDeviceCallbacks}. 93 */ setError(int error)94 public synchronized void setError(int error) { 95 mCurrentError = error; 96 doStateTransition(STATE_ERROR); 97 } 98 99 /** 100 * Transition to the {@code CONFIGURING} state, or {@code ERROR} if in an invalid state. 101 * 102 * <p> 103 * If the device was not already in the {@code CONFIGURING} state, 104 * {@link CameraDeviceStateListener#onConfiguring()} will be called. 105 * </p> 106 * 107 * @return {@code false} if an error has occurred. 108 */ setConfiguring()109 public synchronized boolean setConfiguring() { 110 doStateTransition(STATE_CONFIGURING); 111 return mCurrentError == NO_CAPTURE_ERROR; 112 } 113 114 /** 115 * Transition to the {@code IDLE} state, or {@code ERROR} if in an invalid state. 116 * 117 * <p> 118 * If the device was not already in the {@code IDLE} state, 119 * {@link CameraDeviceStateListener#onIdle()} will be called. 120 * </p> 121 * 122 * @return {@code false} if an error has occurred. 123 */ setIdle()124 public synchronized boolean setIdle() { 125 doStateTransition(STATE_IDLE); 126 return mCurrentError == NO_CAPTURE_ERROR; 127 } 128 129 /** 130 * Transition to the {@code CAPTURING} state, or {@code ERROR} if in an invalid state. 131 * 132 * <p> 133 * If the device was not already in the {@code CAPTURING} state, 134 * {@link CameraDeviceStateListener#onCaptureStarted(RequestHolder)} will be called. 135 * </p> 136 * 137 * @param request A {@link RequestHolder} containing the request for the current capture. 138 * @param timestamp The timestamp of the capture start in nanoseconds. 139 * @param captureError Report a recoverable error for a single request using a valid 140 * error code for {@code ICameraDeviceCallbacks}, or 141 * {@link #NO_CAPTURE_ERROR} 142 * @return {@code false} if an error has occurred. 143 */ setCaptureStart(final RequestHolder request, long timestamp, int captureError)144 public synchronized boolean setCaptureStart(final RequestHolder request, long timestamp, 145 int captureError) { 146 mCurrentRequest = request; 147 doStateTransition(STATE_CAPTURING, timestamp, captureError); 148 return mCurrentError == NO_CAPTURE_ERROR; 149 } 150 151 /** 152 * Set the result for a capture. 153 * 154 * <p> 155 * If the device was in the {@code CAPTURING} state, 156 * {@link CameraDeviceStateListener#onCaptureResult(CameraMetadataNative, RequestHolder)} will 157 * be called with the given result, otherwise this will result in the device transitioning to 158 * the {@code ERROR} state, 159 * </p> 160 * 161 * @param request The {@link RequestHolder} request that created this result. 162 * @param result The {@link CameraMetadataNative} result to set. 163 * @param captureError Report a recoverable error for a single buffer or result using a valid 164 * error code for {@code ICameraDeviceCallbacks}, or 165 * {@link #NO_CAPTURE_ERROR}. 166 * @param captureErrorArg An argument for some error captureError codes. 167 * @return {@code false} if an error has occurred. 168 */ setCaptureResult(final RequestHolder request, final CameraMetadataNative result, final int captureError, final Object captureErrorArg)169 public synchronized boolean setCaptureResult(final RequestHolder request, 170 final CameraMetadataNative result, 171 final int captureError, final Object captureErrorArg) { 172 if (mCurrentState != STATE_CAPTURING) { 173 Log.e(TAG, "Cannot receive result while in state: " + mCurrentState); 174 mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE; 175 doStateTransition(STATE_ERROR); 176 return mCurrentError == NO_CAPTURE_ERROR; 177 } 178 179 if (mCurrentHandler != null && mCurrentListener != null) { 180 if (captureError != NO_CAPTURE_ERROR) { 181 mCurrentHandler.post(new Runnable() { 182 @Override 183 public void run() { 184 mCurrentListener.onError(captureError, captureErrorArg, request); 185 } 186 }); 187 } else { 188 mCurrentHandler.post(new Runnable() { 189 @Override 190 public void run() { 191 mCurrentListener.onCaptureResult(result, request); 192 } 193 }); 194 } 195 } 196 return mCurrentError == NO_CAPTURE_ERROR; 197 } 198 setCaptureResult(final RequestHolder request, final CameraMetadataNative result)199 public synchronized boolean setCaptureResult(final RequestHolder request, 200 final CameraMetadataNative result) { 201 return setCaptureResult(request, result, NO_CAPTURE_ERROR, /*errorArg*/null); 202 } 203 204 /** 205 * Set repeating request error. 206 * 207 * <p>Repeating request has been stopped due to an error such as abandoned output surfaces.</p> 208 * 209 * @param lastFrameNumber Frame number of the last repeating request before it is stopped. 210 */ setRepeatingRequestError(final long lastFrameNumber)211 public synchronized void setRepeatingRequestError(final long lastFrameNumber) { 212 mCurrentHandler.post(new Runnable() { 213 @Override 214 public void run() { 215 mCurrentListener.onRepeatingRequestError(lastFrameNumber); 216 } 217 }); 218 } 219 220 /** 221 * Set the listener for state transition callbacks. 222 * 223 * @param handler handler on which to call the callbacks. 224 * @param listener the {@link CameraDeviceStateListener} callbacks to call. 225 */ setCameraDeviceCallbacks(Handler handler, CameraDeviceStateListener listener)226 public synchronized void setCameraDeviceCallbacks(Handler handler, 227 CameraDeviceStateListener listener) { 228 mCurrentHandler = handler; 229 mCurrentListener = listener; 230 } 231 doStateTransition(int newState)232 private void doStateTransition(int newState) { 233 doStateTransition(newState, /*timestamp*/0, NO_CAPTURE_ERROR); 234 } 235 doStateTransition(int newState, final long timestamp, final int error)236 private void doStateTransition(int newState, final long timestamp, final int error) { 237 if (newState != mCurrentState) { 238 String stateName = "UNKNOWN"; 239 if (newState >= 0 && newState < sStateNames.length) { 240 stateName = sStateNames[newState]; 241 } 242 Log.i(TAG, "Legacy camera service transitioning to state " + stateName); 243 } 244 245 // If we transitioned into a non-IDLE/non-ERROR state then mark the device as busy 246 if(newState != STATE_ERROR && newState != STATE_IDLE) { 247 if (mCurrentState != newState && mCurrentHandler != null && 248 mCurrentListener != null) { 249 mCurrentHandler.post(new Runnable() { 250 @Override 251 public void run() { 252 mCurrentListener.onBusy(); 253 } 254 }); 255 } 256 } 257 258 switch(newState) { 259 case STATE_ERROR: 260 if (mCurrentState != STATE_ERROR && mCurrentHandler != null && 261 mCurrentListener != null) { 262 mCurrentHandler.post(new Runnable() { 263 @Override 264 public void run() { 265 mCurrentListener.onError(mCurrentError, /*errorArg*/null, mCurrentRequest); 266 } 267 }); 268 } 269 mCurrentState = STATE_ERROR; 270 break; 271 case STATE_CONFIGURING: 272 if (mCurrentState != STATE_UNCONFIGURED && mCurrentState != STATE_IDLE) { 273 Log.e(TAG, "Cannot call configure while in state: " + mCurrentState); 274 mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE; 275 doStateTransition(STATE_ERROR); 276 break; 277 } 278 if (mCurrentState != STATE_CONFIGURING && mCurrentHandler != null && 279 mCurrentListener != null) { 280 mCurrentHandler.post(new Runnable() { 281 @Override 282 public void run() { 283 mCurrentListener.onConfiguring(); 284 } 285 }); 286 } 287 mCurrentState = STATE_CONFIGURING; 288 break; 289 case STATE_IDLE: 290 if (mCurrentState == STATE_IDLE) { 291 break; 292 } 293 294 if (mCurrentState != STATE_CONFIGURING && mCurrentState != STATE_CAPTURING) { 295 Log.e(TAG, "Cannot call idle while in state: " + mCurrentState); 296 mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE; 297 doStateTransition(STATE_ERROR); 298 break; 299 } 300 301 if (mCurrentState != STATE_IDLE && mCurrentHandler != null && 302 mCurrentListener != null) { 303 mCurrentHandler.post(new Runnable() { 304 @Override 305 public void run() { 306 mCurrentListener.onIdle(); 307 } 308 }); 309 } 310 mCurrentState = STATE_IDLE; 311 break; 312 case STATE_CAPTURING: 313 if (mCurrentState != STATE_IDLE && mCurrentState != STATE_CAPTURING) { 314 Log.e(TAG, "Cannot call capture while in state: " + mCurrentState); 315 mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE; 316 doStateTransition(STATE_ERROR); 317 break; 318 } 319 320 if (mCurrentHandler != null && mCurrentListener != null) { 321 if (error != NO_CAPTURE_ERROR) { 322 mCurrentHandler.post(new Runnable() { 323 @Override 324 public void run() { 325 mCurrentListener.onError(error, /*errorArg*/null, mCurrentRequest); 326 } 327 }); 328 } else { 329 mCurrentHandler.post(new Runnable() { 330 @Override 331 public void run() { 332 mCurrentListener.onCaptureStarted(mCurrentRequest, timestamp); 333 } 334 }); 335 } 336 } 337 mCurrentState = STATE_CAPTURING; 338 break; 339 default: 340 throw new IllegalStateException("Transition to unknown state: " + newState); 341 } 342 } 343 344 345 } 346