blob: b0b94e3ac00991e224e1b5ac1c9264dd534569e8 [file] [log] [blame]
Ruben Brunkfeb50af2014-05-09 19:58:49 -07001/*
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
Ruben Brunk4aed87a2014-09-21 18:35:31 -070019import android.hardware.camera2.impl.CameraDeviceImpl;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070020import android.hardware.camera2.impl.CameraMetadataNative;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070021import 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>
Ruben Brunkd85e1a62014-06-11 10:35:45 -070037 * <li>{@code IDLE -> IDLE}</li>
Ruben Brunkfeb50af2014-05-09 19:58:49 -070038 * <li>{@code CAPTURING -> IDLE}</li>
39 * <li>{@code ANY -> ERROR}</li>
40 * </ul>
41 */
42public class CameraDeviceState {
43 private static final String TAG = "CameraDeviceState";
Eino-Ville Talvalaa78791f2015-06-01 12:39:54 -070044 private static final boolean DEBUG = false;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070045
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
Ruben Brunke663cb772014-09-16 13:18:31 -070052 private static final String[] sStateNames = { "ERROR", "UNCONFIGURED", "CONFIGURING", "IDLE",
53 "CAPTURING"};
54
Ruben Brunkfeb50af2014-05-09 19:58:49 -070055 private int mCurrentState = STATE_UNCONFIGURED;
Ruben Brunk4aed87a2014-09-21 18:35:31 -070056 private int mCurrentError = NO_CAPTURE_ERROR;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070057
58 private RequestHolder mCurrentRequest = null;
59
60 private Handler mCurrentHandler = null;
61 private CameraDeviceStateListener mCurrentListener = null;
62
Ruben Brunke663cb772014-09-16 13:18:31 -070063 /**
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;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070068
69 /**
70 * CameraDeviceStateListener callbacks to be called after state transitions.
71 */
72 public interface CameraDeviceStateListener {
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -070073 void onError(int errorCode, Object errorArg, RequestHolder holder);
Ruben Brunkfeb50af2014-05-09 19:58:49 -070074 void onConfiguring();
75 void onIdle();
Igor Murashkin51dcfd652014-09-25 16:55:01 -070076 void onBusy();
Ruben Brunk91838de2014-07-16 17:24:17 -070077 void onCaptureStarted(RequestHolder holder, long timestamp);
Ruben Brunkfeb50af2014-05-09 19:58:49 -070078 void onCaptureResult(CameraMetadataNative result, RequestHolder holder);
79 }
80
81 /**
82 * Transition to the {@code ERROR} state.
83 *
84 * <p>
85 * The device cannot exit the {@code ERROR} state. If the device was not already in the
86 * {@code ERROR} state, {@link CameraDeviceStateListener#onError(int, RequestHolder)} will be
87 * called.
88 * </p>
89 *
90 * @param error the error to set. Should be one of the error codes defined in
Ruben Brunk4aed87a2014-09-21 18:35:31 -070091 * {@link CameraDeviceImpl.CameraDeviceCallbacks}.
Ruben Brunkfeb50af2014-05-09 19:58:49 -070092 */
93 public synchronized void setError(int error) {
94 mCurrentError = error;
95 doStateTransition(STATE_ERROR);
96 }
97
98 /**
99 * Transition to the {@code CONFIGURING} state, or {@code ERROR} if in an invalid state.
100 *
101 * <p>
102 * If the device was not already in the {@code CONFIGURING} state,
103 * {@link CameraDeviceStateListener#onConfiguring()} will be called.
104 * </p>
105 *
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700106 * @return {@code false} if an error has occurred.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700107 */
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700108 public synchronized boolean setConfiguring() {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700109 doStateTransition(STATE_CONFIGURING);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700110 return mCurrentError == NO_CAPTURE_ERROR;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700111 }
112
113 /**
114 * Transition to the {@code IDLE} state, or {@code ERROR} if in an invalid state.
115 *
116 * <p>
117 * If the device was not already in the {@code IDLE} state,
118 * {@link CameraDeviceStateListener#onIdle()} will be called.
119 * </p>
120 *
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700121 * @return {@code false} if an error has occurred.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700122 */
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700123 public synchronized boolean setIdle() {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700124 doStateTransition(STATE_IDLE);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700125 return mCurrentError == NO_CAPTURE_ERROR;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700126 }
127
128 /**
129 * Transition to the {@code CAPTURING} state, or {@code ERROR} if in an invalid state.
130 *
131 * <p>
132 * If the device was not already in the {@code CAPTURING} state,
133 * {@link CameraDeviceStateListener#onCaptureStarted(RequestHolder)} will be called.
134 * </p>
135 *
136 * @param request A {@link RequestHolder} containing the request for the current capture.
Ruben Brunk91838de2014-07-16 17:24:17 -0700137 * @param timestamp The timestamp of the capture start in nanoseconds.
Ruben Brunke663cb772014-09-16 13:18:31 -0700138 * @param captureError Report a recoverable error for a single request using a valid
139 * error code for {@code ICameraDeviceCallbacks}, or
140 * {@link #NO_CAPTURE_ERROR}
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700141 * @return {@code false} if an error has occurred.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700142 */
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700143 public synchronized boolean setCaptureStart(final RequestHolder request, long timestamp,
Ruben Brunke663cb772014-09-16 13:18:31 -0700144 int captureError) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700145 mCurrentRequest = request;
Ruben Brunke663cb772014-09-16 13:18:31 -0700146 doStateTransition(STATE_CAPTURING, timestamp, captureError);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700147 return mCurrentError == NO_CAPTURE_ERROR;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700148 }
149
150 /**
151 * Set the result for a capture.
152 *
153 * <p>
154 * If the device was in the {@code CAPTURING} state,
155 * {@link CameraDeviceStateListener#onCaptureResult(CameraMetadataNative, RequestHolder)} will
156 * be called with the given result, otherwise this will result in the device transitioning to
157 * the {@code ERROR} state,
158 * </p>
159 *
Ruben Brunke663cb772014-09-16 13:18:31 -0700160 * @param request The {@link RequestHolder} request that created this result.
161 * @param result The {@link CameraMetadataNative} result to set.
162 * @param captureError Report a recoverable error for a single buffer or result using a valid
163 * error code for {@code ICameraDeviceCallbacks}, or
164 * {@link #NO_CAPTURE_ERROR}.
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700165 * @param captureErrorArg An argument for some error captureError codes.
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700166 * @return {@code false} if an error has occurred.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700167 */
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700168 public synchronized boolean setCaptureResult(final RequestHolder request,
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700169 final CameraMetadataNative result,
170 final int captureError, final Object captureErrorArg) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700171 if (mCurrentState != STATE_CAPTURING) {
172 Log.e(TAG, "Cannot receive result while in state: " + mCurrentState);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700173 mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700174 doStateTransition(STATE_ERROR);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700175 return mCurrentError == NO_CAPTURE_ERROR;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700176 }
177
178 if (mCurrentHandler != null && mCurrentListener != null) {
Ruben Brunke663cb772014-09-16 13:18:31 -0700179 if (captureError != NO_CAPTURE_ERROR) {
180 mCurrentHandler.post(new Runnable() {
181 @Override
182 public void run() {
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700183 mCurrentListener.onError(captureError, captureErrorArg, request);
Ruben Brunke663cb772014-09-16 13:18:31 -0700184 }
185 });
186 } else {
187 mCurrentHandler.post(new Runnable() {
188 @Override
189 public void run() {
190 mCurrentListener.onCaptureResult(result, request);
191 }
192 });
193 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700194 }
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700195 return mCurrentError == NO_CAPTURE_ERROR;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700196 }
197
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700198 public synchronized boolean setCaptureResult(final RequestHolder request,
199 final CameraMetadataNative result) {
200 return setCaptureResult(request, result, NO_CAPTURE_ERROR, /*errorArg*/null);
201 }
202
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700203 /**
204 * Set the listener for state transition callbacks.
205 *
206 * @param handler handler on which to call the callbacks.
207 * @param listener the {@link CameraDeviceStateListener} callbacks to call.
208 */
209 public synchronized void setCameraDeviceCallbacks(Handler handler,
210 CameraDeviceStateListener listener) {
211 mCurrentHandler = handler;
212 mCurrentListener = listener;
213 }
214
215 private void doStateTransition(int newState) {
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700216 doStateTransition(newState, /*timestamp*/0, NO_CAPTURE_ERROR);
Ruben Brunk91838de2014-07-16 17:24:17 -0700217 }
218
Ruben Brunke663cb772014-09-16 13:18:31 -0700219 private void doStateTransition(int newState, final long timestamp, final int error) {
220 if (newState != mCurrentState) {
221 String stateName = "UNKNOWN";
222 if (newState >= 0 && newState < sStateNames.length) {
223 stateName = sStateNames[newState];
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700224 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700225 Log.i(TAG, "Legacy camera service transitioning to state " + stateName);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700226 }
Igor Murashkin51dcfd652014-09-25 16:55:01 -0700227
228 // If we transitioned into a non-IDLE/non-ERROR state then mark the device as busy
229 if(newState != STATE_ERROR && newState != STATE_IDLE) {
230 if (mCurrentState != newState && mCurrentHandler != null &&
231 mCurrentListener != null) {
232 mCurrentHandler.post(new Runnable() {
233 @Override
234 public void run() {
235 mCurrentListener.onBusy();
236 }
237 });
238 }
239 }
240
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700241 switch(newState) {
242 case STATE_ERROR:
243 if (mCurrentState != STATE_ERROR && mCurrentHandler != null &&
244 mCurrentListener != null) {
245 mCurrentHandler.post(new Runnable() {
246 @Override
247 public void run() {
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700248 mCurrentListener.onError(mCurrentError, /*errorArg*/null, mCurrentRequest);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700249 }
250 });
251 }
252 mCurrentState = STATE_ERROR;
253 break;
254 case STATE_CONFIGURING:
255 if (mCurrentState != STATE_UNCONFIGURED && mCurrentState != STATE_IDLE) {
256 Log.e(TAG, "Cannot call configure while in state: " + mCurrentState);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700257 mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700258 doStateTransition(STATE_ERROR);
259 break;
260 }
261 if (mCurrentState != STATE_CONFIGURING && mCurrentHandler != null &&
262 mCurrentListener != null) {
263 mCurrentHandler.post(new Runnable() {
264 @Override
265 public void run() {
266 mCurrentListener.onConfiguring();
267 }
268 });
269 }
270 mCurrentState = STATE_CONFIGURING;
271 break;
272 case STATE_IDLE:
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700273 if (mCurrentState == STATE_IDLE) {
274 break;
275 }
276
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700277 if (mCurrentState != STATE_CONFIGURING && mCurrentState != STATE_CAPTURING) {
278 Log.e(TAG, "Cannot call idle while in state: " + mCurrentState);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700279 mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700280 doStateTransition(STATE_ERROR);
281 break;
282 }
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700283
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700284 if (mCurrentState != STATE_IDLE && mCurrentHandler != null &&
285 mCurrentListener != null) {
286 mCurrentHandler.post(new Runnable() {
287 @Override
288 public void run() {
289 mCurrentListener.onIdle();
290 }
291 });
292 }
293 mCurrentState = STATE_IDLE;
294 break;
295 case STATE_CAPTURING:
296 if (mCurrentState != STATE_IDLE && mCurrentState != STATE_CAPTURING) {
297 Log.e(TAG, "Cannot call capture while in state: " + mCurrentState);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700298 mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700299 doStateTransition(STATE_ERROR);
300 break;
301 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700302
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700303 if (mCurrentHandler != null && mCurrentListener != null) {
Ruben Brunke663cb772014-09-16 13:18:31 -0700304 if (error != NO_CAPTURE_ERROR) {
305 mCurrentHandler.post(new Runnable() {
306 @Override
307 public void run() {
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700308 mCurrentListener.onError(error, /*errorArg*/null, mCurrentRequest);
Ruben Brunke663cb772014-09-16 13:18:31 -0700309 }
310 });
311 } else {
312 mCurrentHandler.post(new Runnable() {
313 @Override
314 public void run() {
315 mCurrentListener.onCaptureStarted(mCurrentRequest, timestamp);
316 }
317 });
318 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700319 }
320 mCurrentState = STATE_CAPTURING;
321 break;
322 default:
323 throw new IllegalStateException("Transition to unknown state: " + newState);
324 }
325 }
326
327
328}