CameraDeviceState.java revision d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6
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.camera2.impl.CameraMetadataNative; 20import android.hardware.camera2.utils.CameraBinderDecorator; 21import android.os.Handler; 22import 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 */ 42public class CameraDeviceState { 43 private static final String TAG = "CameraDeviceState"; 44 private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG); 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 int mCurrentState = STATE_UNCONFIGURED; 53 private int mCurrentError = CameraBinderDecorator.NO_ERROR; 54 55 private RequestHolder mCurrentRequest = null; 56 57 private Handler mCurrentHandler = null; 58 private CameraDeviceStateListener mCurrentListener = null; 59 60 61 /** 62 * CameraDeviceStateListener callbacks to be called after state transitions. 63 */ 64 public interface CameraDeviceStateListener { 65 void onError(int errorCode, RequestHolder holder); 66 void onConfiguring(); 67 void onIdle(); 68 void onCaptureStarted(RequestHolder holder); 69 void onCaptureResult(CameraMetadataNative result, RequestHolder holder); 70 } 71 72 /** 73 * Transition to the {@code ERROR} state. 74 * 75 * <p> 76 * The device cannot exit the {@code ERROR} state. If the device was not already in the 77 * {@code ERROR} state, {@link CameraDeviceStateListener#onError(int, RequestHolder)} will be 78 * called. 79 * </p> 80 * 81 * @param error the error to set. Should be one of the error codes defined in 82 * {@link android.hardware.camera2.utils.CameraBinderDecorator}. 83 */ 84 public synchronized void setError(int error) { 85 mCurrentError = error; 86 doStateTransition(STATE_ERROR); 87 } 88 89 /** 90 * Transition to the {@code CONFIGURING} state, or {@code ERROR} if in an invalid state. 91 * 92 * <p> 93 * If the device was not already in the {@code CONFIGURING} state, 94 * {@link CameraDeviceStateListener#onConfiguring()} will be called. 95 * </p> 96 * 97 * @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred. 98 */ 99 public synchronized int setConfiguring() { 100 doStateTransition(STATE_CONFIGURING); 101 return mCurrentError; 102 } 103 104 /** 105 * Transition to the {@code IDLE} state, or {@code ERROR} if in an invalid state. 106 * 107 * <p> 108 * If the device was not already in the {@code IDLE} state, 109 * {@link CameraDeviceStateListener#onIdle()} will be called. 110 * </p> 111 * 112 * @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred. 113 */ 114 public synchronized int setIdle() { 115 doStateTransition(STATE_IDLE); 116 return mCurrentError; 117 } 118 119 /** 120 * Transition to the {@code CAPTURING} state, or {@code ERROR} if in an invalid state. 121 * 122 * <p> 123 * If the device was not already in the {@code CAPTURING} state, 124 * {@link CameraDeviceStateListener#onCaptureStarted(RequestHolder)} will be called. 125 * </p> 126 * 127 * @param request A {@link RequestHolder} containing the request for the current capture. 128 * @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred. 129 */ 130 public synchronized int setCaptureStart(final RequestHolder request) { 131 mCurrentRequest = request; 132 doStateTransition(STATE_CAPTURING); 133 return mCurrentError; 134 } 135 136 /** 137 * Set the result for a capture. 138 * 139 * <p> 140 * If the device was in the {@code CAPTURING} state, 141 * {@link CameraDeviceStateListener#onCaptureResult(CameraMetadataNative, RequestHolder)} will 142 * be called with the given result, otherwise this will result in the device transitioning to 143 * the {@code ERROR} state, 144 * </p> 145 * 146 * @param request the {@link RequestHolder} request that created this result. 147 * @param result the {@link CameraMetadataNative} result to set. 148 * @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred. 149 */ 150 public synchronized int setCaptureResult(final RequestHolder request, 151 final CameraMetadataNative result) { 152 if (mCurrentState != STATE_CAPTURING) { 153 Log.e(TAG, "Cannot receive result while in state: " + mCurrentState); 154 mCurrentError = CameraBinderDecorator.INVALID_OPERATION; 155 doStateTransition(STATE_ERROR); 156 return mCurrentError; 157 } 158 159 if (mCurrentHandler != null && mCurrentListener != null) { 160 mCurrentHandler.post(new Runnable() { 161 @Override 162 public void run() { 163 mCurrentListener.onCaptureResult(result, request); 164 } 165 }); 166 } 167 return mCurrentError; 168 } 169 170 /** 171 * Set the listener for state transition callbacks. 172 * 173 * @param handler handler on which to call the callbacks. 174 * @param listener the {@link CameraDeviceStateListener} callbacks to call. 175 */ 176 public synchronized void setCameraDeviceCallbacks(Handler handler, 177 CameraDeviceStateListener listener) { 178 mCurrentHandler = handler; 179 mCurrentListener = listener; 180 } 181 182 private void doStateTransition(int newState) { 183 if (DEBUG) { 184 if (newState != mCurrentState) { 185 Log.d(TAG, "Transitioning to state " + newState); 186 } 187 } 188 switch(newState) { 189 case STATE_ERROR: 190 if (mCurrentState != STATE_ERROR && mCurrentHandler != null && 191 mCurrentListener != null) { 192 mCurrentHandler.post(new Runnable() { 193 @Override 194 public void run() { 195 mCurrentListener.onError(mCurrentError, mCurrentRequest); 196 } 197 }); 198 } 199 mCurrentState = STATE_ERROR; 200 break; 201 case STATE_CONFIGURING: 202 if (mCurrentState != STATE_UNCONFIGURED && mCurrentState != STATE_IDLE) { 203 Log.e(TAG, "Cannot call configure while in state: " + mCurrentState); 204 mCurrentError = CameraBinderDecorator.INVALID_OPERATION; 205 doStateTransition(STATE_ERROR); 206 break; 207 } 208 if (mCurrentState != STATE_CONFIGURING && mCurrentHandler != null && 209 mCurrentListener != null) { 210 mCurrentHandler.post(new Runnable() { 211 @Override 212 public void run() { 213 mCurrentListener.onConfiguring(); 214 } 215 }); 216 } 217 mCurrentState = STATE_CONFIGURING; 218 break; 219 case STATE_IDLE: 220 if (mCurrentState == STATE_IDLE) { 221 break; 222 } 223 224 if (mCurrentState != STATE_CONFIGURING && mCurrentState != STATE_CAPTURING) { 225 Log.e(TAG, "Cannot call idle while in state: " + mCurrentState); 226 mCurrentError = CameraBinderDecorator.INVALID_OPERATION; 227 doStateTransition(STATE_ERROR); 228 break; 229 } 230 231 if (mCurrentState != STATE_IDLE && mCurrentHandler != null && 232 mCurrentListener != null) { 233 mCurrentHandler.post(new Runnable() { 234 @Override 235 public void run() { 236 mCurrentListener.onIdle(); 237 } 238 }); 239 } 240 mCurrentState = STATE_IDLE; 241 break; 242 case STATE_CAPTURING: 243 if (mCurrentState != STATE_IDLE && mCurrentState != STATE_CAPTURING) { 244 Log.e(TAG, "Cannot call capture while in state: " + mCurrentState); 245 mCurrentError = CameraBinderDecorator.INVALID_OPERATION; 246 doStateTransition(STATE_ERROR); 247 break; 248 } 249 if (mCurrentHandler != null && mCurrentListener != null) { 250 mCurrentHandler.post(new Runnable() { 251 @Override 252 public void run() { 253 mCurrentListener.onCaptureStarted(mCurrentRequest); 254 } 255 }); 256 } 257 mCurrentState = STATE_CAPTURING; 258 break; 259 default: 260 throw new IllegalStateException("Transition to unknown state: " + newState); 261 } 262 } 263 264 265} 266