blob: 89e2d98453fda67295722204d081571e88a7ac4d [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";
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
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 {
73 void onError(int errorCode, RequestHolder holder);
74 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}.
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700165 * @return {@code false} if an error has occurred.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700166 */
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700167 public synchronized boolean setCaptureResult(final RequestHolder request,
Ruben Brunke663cb772014-09-16 13:18:31 -0700168 final CameraMetadataNative result,
169 final int captureError) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700170 if (mCurrentState != STATE_CAPTURING) {
171 Log.e(TAG, "Cannot receive result while in state: " + mCurrentState);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700172 mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700173 doStateTransition(STATE_ERROR);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700174 return mCurrentError == NO_CAPTURE_ERROR;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700175 }
176
177 if (mCurrentHandler != null && mCurrentListener != null) {
Ruben Brunke663cb772014-09-16 13:18:31 -0700178 if (captureError != NO_CAPTURE_ERROR) {
179 mCurrentHandler.post(new Runnable() {
180 @Override
181 public void run() {
182 mCurrentListener.onError(captureError, request);
183 }
184 });
185 } else {
186 mCurrentHandler.post(new Runnable() {
187 @Override
188 public void run() {
189 mCurrentListener.onCaptureResult(result, request);
190 }
191 });
192 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700193 }
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700194 return mCurrentError == NO_CAPTURE_ERROR;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700195 }
196
197 /**
198 * Set the listener for state transition callbacks.
199 *
200 * @param handler handler on which to call the callbacks.
201 * @param listener the {@link CameraDeviceStateListener} callbacks to call.
202 */
203 public synchronized void setCameraDeviceCallbacks(Handler handler,
204 CameraDeviceStateListener listener) {
205 mCurrentHandler = handler;
206 mCurrentListener = listener;
207 }
208
209 private void doStateTransition(int newState) {
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700210 doStateTransition(newState, /*timestamp*/0, NO_CAPTURE_ERROR);
Ruben Brunk91838de2014-07-16 17:24:17 -0700211 }
212
Ruben Brunke663cb772014-09-16 13:18:31 -0700213 private void doStateTransition(int newState, final long timestamp, final int error) {
214 if (newState != mCurrentState) {
215 String stateName = "UNKNOWN";
216 if (newState >= 0 && newState < sStateNames.length) {
217 stateName = sStateNames[newState];
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700218 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700219 Log.i(TAG, "Legacy camera service transitioning to state " + stateName);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700220 }
Igor Murashkin51dcfd652014-09-25 16:55:01 -0700221
222 // If we transitioned into a non-IDLE/non-ERROR state then mark the device as busy
223 if(newState != STATE_ERROR && newState != STATE_IDLE) {
224 if (mCurrentState != newState && mCurrentHandler != null &&
225 mCurrentListener != null) {
226 mCurrentHandler.post(new Runnable() {
227 @Override
228 public void run() {
229 mCurrentListener.onBusy();
230 }
231 });
232 }
233 }
234
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700235 switch(newState) {
236 case STATE_ERROR:
237 if (mCurrentState != STATE_ERROR && mCurrentHandler != null &&
238 mCurrentListener != null) {
239 mCurrentHandler.post(new Runnable() {
240 @Override
241 public void run() {
242 mCurrentListener.onError(mCurrentError, mCurrentRequest);
243 }
244 });
245 }
246 mCurrentState = STATE_ERROR;
247 break;
248 case STATE_CONFIGURING:
249 if (mCurrentState != STATE_UNCONFIGURED && mCurrentState != STATE_IDLE) {
250 Log.e(TAG, "Cannot call configure while in state: " + mCurrentState);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700251 mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700252 doStateTransition(STATE_ERROR);
253 break;
254 }
255 if (mCurrentState != STATE_CONFIGURING && mCurrentHandler != null &&
256 mCurrentListener != null) {
257 mCurrentHandler.post(new Runnable() {
258 @Override
259 public void run() {
260 mCurrentListener.onConfiguring();
261 }
262 });
263 }
264 mCurrentState = STATE_CONFIGURING;
265 break;
266 case STATE_IDLE:
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700267 if (mCurrentState == STATE_IDLE) {
268 break;
269 }
270
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700271 if (mCurrentState != STATE_CONFIGURING && mCurrentState != STATE_CAPTURING) {
272 Log.e(TAG, "Cannot call idle while in state: " + mCurrentState);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700273 mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700274 doStateTransition(STATE_ERROR);
275 break;
276 }
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700277
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700278 if (mCurrentState != STATE_IDLE && mCurrentHandler != null &&
279 mCurrentListener != null) {
280 mCurrentHandler.post(new Runnable() {
281 @Override
282 public void run() {
283 mCurrentListener.onIdle();
284 }
285 });
286 }
287 mCurrentState = STATE_IDLE;
288 break;
289 case STATE_CAPTURING:
290 if (mCurrentState != STATE_IDLE && mCurrentState != STATE_CAPTURING) {
291 Log.e(TAG, "Cannot call capture while in state: " + mCurrentState);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700292 mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700293 doStateTransition(STATE_ERROR);
294 break;
295 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700296
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700297 if (mCurrentHandler != null && mCurrentListener != null) {
Ruben Brunke663cb772014-09-16 13:18:31 -0700298 if (error != NO_CAPTURE_ERROR) {
299 mCurrentHandler.post(new Runnable() {
300 @Override
301 public void run() {
302 mCurrentListener.onError(error, mCurrentRequest);
303 }
304 });
305 } else {
306 mCurrentHandler.post(new Runnable() {
307 @Override
308 public void run() {
309 mCurrentListener.onCaptureStarted(mCurrentRequest, timestamp);
310 }
311 });
312 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700313 }
314 mCurrentState = STATE_CAPTURING;
315 break;
316 default:
317 throw new IllegalStateException("Transition to unknown state: " + newState);
318 }
319 }
320
321
322}