blob: ec450bd14cc82ebde81d117c284591ae546c0773 [file] [log] [blame]
Igor Murashkin70725502013-06-25 20:27:06 +00001/*
2 * Copyright (C) 2013 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
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070017package android.hardware.camera2.impl;
Igor Murashkin70725502013-06-25 20:27:06 +000018
Igor Murashkin57ea59b2013-08-23 16:55:57 -070019import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
20
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070021import android.hardware.camera2.CameraAccessException;
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -070022import android.hardware.camera2.CameraCaptureSession;
Ruben Brunk57493682014-05-27 18:58:08 -070023import android.hardware.camera2.CameraCharacteristics;
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -070024import android.hardware.camera2.CameraDevice;
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070025import android.hardware.camera2.CaptureRequest;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070026import android.hardware.camera2.CaptureResult;
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -070027import android.hardware.camera2.CaptureFailure;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070028import android.hardware.camera2.ICameraDeviceCallbacks;
29import android.hardware.camera2.ICameraDeviceUser;
Igor Murashkindb075af2014-05-21 10:07:08 -070030import android.hardware.camera2.TotalCaptureResult;
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -070031import android.hardware.camera2.utils.CameraBinderDecorator;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070032import android.hardware.camera2.utils.CameraRuntimeException;
Igor Murashkin9c595172014-05-12 13:56:20 -070033import android.hardware.camera2.utils.LongParcelable;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070034import android.os.Handler;
Ruben Brunkdecfe952013-10-29 11:00:32 -070035import android.os.IBinder;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070036import android.os.Looper;
Ruben Brunkdecfe952013-10-29 11:00:32 -070037import android.os.RemoteException;
Igor Murashkin70725502013-06-25 20:27:06 +000038import android.util.Log;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070039import android.util.SparseArray;
Igor Murashkin70725502013-06-25 20:27:06 +000040import android.view.Surface;
41
Jianing Weid2c3a822014-03-27 18:27:43 -070042import java.util.AbstractMap.SimpleEntry;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070043import java.util.ArrayList;
Igor Murashkin1e854c52014-08-28 15:21:49 -070044import java.util.HashMap;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070045import java.util.HashSet;
Ruben Brunkdecfe952013-10-29 11:00:32 -070046import java.util.Iterator;
Igor Murashkin70725502013-06-25 20:27:06 +000047import java.util.List;
Jianing Weid2c3a822014-03-27 18:27:43 -070048import java.util.TreeSet;
Igor Murashkin70725502013-06-25 20:27:06 +000049
50/**
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070051 * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
Igor Murashkin70725502013-06-25 20:27:06 +000052 */
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -070053public class CameraDeviceImpl extends CameraDevice {
Igor Murashkin70725502013-06-25 20:27:06 +000054 private final String TAG;
Zhijun Heecb323e2013-07-31 09:40:27 -070055 private final boolean DEBUG;
Igor Murashkin70725502013-06-25 20:27:06 +000056
Ruben Brunkdecfe952013-10-29 11:00:32 -070057 private static final int REQUEST_ID_NONE = -1;
58
Igor Murashkin70725502013-06-25 20:27:06 +000059 // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
60 private ICameraDeviceUser mRemoteDevice;
61
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070062 // Lock to synchronize cross-thread access to device public interface
Igor Murashkin51dcfd652014-09-25 16:55:01 -070063 final Object mInterfaceLock = new Object(); // access from this class and Session only!
Igor Murashkin70725502013-06-25 20:27:06 +000064 private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
65
Eino-Ville Talvalafd887432014-09-04 13:07:40 -070066 private final StateCallback mDeviceCallback;
67 private volatile StateCallbackKK mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070068 private final Handler mDeviceHandler;
69
Igor Murashkin49b2b132014-06-18 19:03:00 -070070 private volatile boolean mClosing = false;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -070071 private boolean mInError = false;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070072 private boolean mIdle = true;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070073
Eino-Ville Talvalafd887432014-09-04 13:07:40 -070074 /** map request IDs to callback/request data */
75 private final SparseArray<CaptureCallbackHolder> mCaptureCallbackMap =
76 new SparseArray<CaptureCallbackHolder>();
Igor Murashkin70725502013-06-25 20:27:06 +000077
Ruben Brunkdecfe952013-10-29 11:00:32 -070078 private int mRepeatingRequestId = REQUEST_ID_NONE;
79 private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>();
Igor Murashkin57ea59b2013-08-23 16:55:57 -070080 // Map stream IDs to Surfaces
81 private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
Igor Murashkin70725502013-06-25 20:27:06 +000082
83 private final String mCameraId;
Ruben Brunk57493682014-05-27 18:58:08 -070084 private final CameraCharacteristics mCharacteristics;
Zhijun He83159152014-07-16 11:32:59 -070085 private final int mTotalPartialCount;
Igor Murashkin70725502013-06-25 20:27:06 +000086
Jianing Weid2c3a822014-03-27 18:27:43 -070087 /**
88 * A list tracking request and its expected last frame.
89 * Updated when calling ICameraDeviceUser methods.
90 */
91 private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>>
92 mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>();
93
94 /**
95 * An object tracking received frame numbers.
96 * Updated when receiving callbacks from ICameraDeviceCallbacks.
97 */
98 private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
99
Igor Murashkin0b27d342014-05-30 09:45:05 -0700100 private CameraCaptureSessionImpl mCurrentSession;
Eino-Ville Talvala95037852014-09-14 14:07:05 -0700101 private int mNextSessionId = 0;
Igor Murashkin0b27d342014-05-30 09:45:05 -0700102
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700103 // Runnables for all state transitions, except error, which needs the
104 // error code argument
105
106 private final Runnable mCallOnOpened = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700107 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700108 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700109 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700110 synchronized(mInterfaceLock) {
111 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700112
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700113 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700114 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700115 if (sessionCallback != null) {
116 sessionCallback.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700117 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700118 mDeviceCallback.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700119 }
120 };
121
122 private final Runnable mCallOnUnconfigured = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700123 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700124 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700125 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700126 synchronized(mInterfaceLock) {
127 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700128
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700129 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700130 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700131 if (sessionCallback != null) {
132 sessionCallback.onUnconfigured(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700133 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700134 }
135 };
136
137 private final Runnable mCallOnActive = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700138 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700139 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700140 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700141 synchronized(mInterfaceLock) {
142 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700143
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700144 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700145 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700146 if (sessionCallback != null) {
147 sessionCallback.onActive(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700148 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700149 }
150 };
151
152 private final Runnable mCallOnBusy = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700153 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700154 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700155 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700156 synchronized(mInterfaceLock) {
157 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700158
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700159 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700160 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700161 if (sessionCallback != null) {
162 sessionCallback.onBusy(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700163 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700164 }
165 };
166
167 private final Runnable mCallOnClosed = new Runnable() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700168 private boolean mClosedOnce = false;
169
Jianing Weid2c3a822014-03-27 18:27:43 -0700170 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700171 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700172 if (mClosedOnce) {
173 throw new AssertionError("Don't post #onClosed more than once");
174 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700175 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700176 synchronized(mInterfaceLock) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700177 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700178 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700179 if (sessionCallback != null) {
180 sessionCallback.onClosed(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700181 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700182 mDeviceCallback.onClosed(CameraDeviceImpl.this);
Igor Murashkin49b2b132014-06-18 19:03:00 -0700183 mClosedOnce = true;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700184 }
185 };
186
187 private final Runnable mCallOnIdle = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700188 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700189 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700190 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700191 synchronized(mInterfaceLock) {
192 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700193
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700194 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700195 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700196 if (sessionCallback != null) {
197 sessionCallback.onIdle(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700198 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700199 }
200 };
201
202 private final Runnable mCallOnDisconnected = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700203 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700204 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700205 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700206 synchronized(mInterfaceLock) {
207 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700208
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700209 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700210 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700211 if (sessionCallback != null) {
212 sessionCallback.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700213 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700214 mDeviceCallback.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700215 }
216 };
217
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700218 public CameraDeviceImpl(String cameraId, StateCallback callback, Handler handler,
Ruben Brunk57493682014-05-27 18:58:08 -0700219 CameraCharacteristics characteristics) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700220 if (cameraId == null || callback == null || handler == null || characteristics == null) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700221 throw new IllegalArgumentException("Null argument given");
222 }
Igor Murashkin70725502013-06-25 20:27:06 +0000223 mCameraId = cameraId;
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700224 mDeviceCallback = callback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700225 mDeviceHandler = handler;
Ruben Brunk57493682014-05-27 18:58:08 -0700226 mCharacteristics = characteristics;
Eino-Ville Talvalab72d1ef2014-04-28 13:21:18 -0700227
228 final int MAX_TAG_LEN = 23;
229 String tag = String.format("CameraDevice-JV-%s", mCameraId);
230 if (tag.length() > MAX_TAG_LEN) {
231 tag = tag.substring(0, MAX_TAG_LEN);
232 }
233 TAG = tag;
Zhijun Heecb323e2013-07-31 09:40:27 -0700234 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Zhijun He83159152014-07-16 11:32:59 -0700235
236 Integer partialCount =
237 mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
238 if (partialCount == null) {
239 // 1 means partial result is not supported.
240 mTotalPartialCount = 1;
241 } else {
242 mTotalPartialCount = partialCount;
243 }
Igor Murashkin70725502013-06-25 20:27:06 +0000244 }
245
246 public CameraDeviceCallbacks getCallbacks() {
247 return mCallbacks;
248 }
249
Igor Murashkin70725502013-06-25 20:27:06 +0000250 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700251 synchronized(mInterfaceLock) {
252 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700253 // If setRemoteFailure already called, do nothing
254 if (mInError) return;
255
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700256 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
257
258 mDeviceHandler.post(mCallOnOpened);
259 mDeviceHandler.post(mCallOnUnconfigured);
260 }
Igor Murashkin70725502013-06-25 20:27:06 +0000261 }
262
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700263 /**
264 * Call to indicate failed connection to a remote camera device.
265 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700266 * <p>This places the camera device in the error state and informs the callback.
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700267 * Use in place of setRemoteDevice() when startup fails.</p>
268 */
269 public void setRemoteFailure(final CameraRuntimeException failure) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700270 int failureCode = StateCallback.ERROR_CAMERA_DEVICE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700271 boolean failureIsError = true;
272
273 switch (failure.getReason()) {
274 case CameraAccessException.CAMERA_IN_USE:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700275 failureCode = StateCallback.ERROR_CAMERA_IN_USE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700276 break;
277 case CameraAccessException.MAX_CAMERAS_IN_USE:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700278 failureCode = StateCallback.ERROR_MAX_CAMERAS_IN_USE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700279 break;
280 case CameraAccessException.CAMERA_DISABLED:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700281 failureCode = StateCallback.ERROR_CAMERA_DISABLED;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700282 break;
283 case CameraAccessException.CAMERA_DISCONNECTED:
284 failureIsError = false;
285 break;
286 case CameraAccessException.CAMERA_ERROR:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700287 failureCode = StateCallback.ERROR_CAMERA_DEVICE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700288 break;
289 default:
290 Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
291 break;
292 }
293 final int code = failureCode;
294 final boolean isError = failureIsError;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700295 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700296 mInError = true;
297 mDeviceHandler.post(new Runnable() {
Igor Murashkine1442202014-06-09 17:51:24 -0700298 @Override
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700299 public void run() {
300 if (isError) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700301 mDeviceCallback.onError(CameraDeviceImpl.this, code);
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700302 } else {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700303 mDeviceCallback.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700304 }
305 }
306 });
307 }
308 }
309
Igor Murashkin70725502013-06-25 20:27:06 +0000310 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700311 public String getId() {
312 return mCameraId;
313 }
314
Igor Murashkin70725502013-06-25 20:27:06 +0000315 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700316 // Leave this here for backwards compatibility with older code using this directly
317 configureOutputsChecked(outputs);
318 }
319
320 /**
321 * Attempt to configure the outputs; the device goes to idle and then configures the
322 * new outputs if possible.
323 *
324 * <p>The configuration may gracefully fail, if there are too many outputs, if the formats
325 * are not supported, or if the sizes for that format is not supported. In this case this
326 * function will return {@code false} and the unconfigured callback will be fired.</p>
327 *
328 * <p>If the configuration succeeds (with 1 or more outputs), then the idle callback is fired.
329 * Unconfiguring the device always fires the idle callback.</p>
330 *
331 * @param outputs a list of one or more surfaces, or {@code null} to unconfigure
332 * @return whether or not the configuration was successful
333 *
334 * @throws CameraAccessException if there were any unexpected problems during configuration
335 */
336 public boolean configureOutputsChecked(List<Surface> outputs) throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700337 // Treat a null input the same an empty list
338 if (outputs == null) {
339 outputs = new ArrayList<Surface>();
340 }
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700341 boolean success = false;
342
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700343 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700344 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700345
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700346 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
347 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
348
349 // Determine which streams need to be created, which to be deleted
350 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
351 int streamId = mConfiguredOutputs.keyAt(i);
352 Surface s = mConfiguredOutputs.valueAt(i);
353
354 if (!outputs.contains(s)) {
355 deleteList.add(streamId);
356 } else {
357 addSet.remove(s); // Don't create a stream previously created
358 }
359 }
360
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700361 mDeviceHandler.post(mCallOnBusy);
362 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700363
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700364 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700365 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700366
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700367 mRemoteDevice.beginConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700368 // Delete all streams first (to free up HW resources)
369 for (Integer streamId : deleteList) {
370 mRemoteDevice.deleteStream(streamId);
371 mConfiguredOutputs.delete(streamId);
372 }
373
374 // Add all new streams
375 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000376 // TODO: remove width,height,format since we are ignoring
377 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700378 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
379 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000380 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700381
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700382 try {
383 mRemoteDevice.endConfigure();
384 }
385 catch (IllegalArgumentException e) {
386 // OK. camera service can reject stream config if it's not supported by HAL
387 // This is only the result of a programmer misusing the camera2 api.
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700388 Log.w(TAG, "Stream configuration failed");
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700389 return false;
390 }
391
392 success = true;
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700393 } catch (CameraRuntimeException e) {
394 if (e.getReason() == CAMERA_IN_USE) {
395 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700396 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700397 }
398
399 throw e.asChecked();
400 } catch (RemoteException e) {
401 // impossible
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700402 return false;
403 } finally {
404 if (success && outputs.size() > 0) {
405 mDeviceHandler.post(mCallOnIdle);
406 } else {
407 // Always return to the 'unconfigured' state if we didn't hit a fatal error
408 mDeviceHandler.post(mCallOnUnconfigured);
409 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700410 }
Igor Murashkin70725502013-06-25 20:27:06 +0000411 }
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700412
413 return success;
Igor Murashkin70725502013-06-25 20:27:06 +0000414 }
415
416 @Override
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700417 public void createCaptureSession(List<Surface> outputs,
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700418 CameraCaptureSession.StateCallback callback, Handler handler)
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700419 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700420 synchronized(mInterfaceLock) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700421 if (DEBUG) {
422 Log.d(TAG, "createCaptureSession");
423 }
424
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700425 checkIfCameraClosedOrInError();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700426
Eino-Ville Talvalad3b85f62014-08-05 15:02:31 -0700427 // Notify current session that it's going away, before starting camera operations
428 // After this call completes, the session is not allowed to call into CameraDeviceImpl
429 if (mCurrentSession != null) {
430 mCurrentSession.replaceSessionClose();
431 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700432
433 // TODO: dont block for this
434 boolean configureSuccess = true;
435 CameraAccessException pendingException = null;
436 try {
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700437 configureSuccess = configureOutputsChecked(outputs); // and then block until IDLE
Igor Murashkin0b27d342014-05-30 09:45:05 -0700438 } catch (CameraAccessException e) {
439 configureSuccess = false;
440 pendingException = e;
Igor Murashkine1442202014-06-09 17:51:24 -0700441 if (DEBUG) {
442 Log.v(TAG, "createCaptureSession - failed with exception ", e);
443 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700444 }
445
446 // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
447 CameraCaptureSessionImpl newSession =
Eino-Ville Talvala95037852014-09-14 14:07:05 -0700448 new CameraCaptureSessionImpl(mNextSessionId++,
449 outputs, callback, handler, this, mDeviceHandler,
Igor Murashkin0b27d342014-05-30 09:45:05 -0700450 configureSuccess);
451
Igor Murashkin0b27d342014-05-30 09:45:05 -0700452 // TODO: wait until current session closes, then create the new session
453 mCurrentSession = newSession;
454
455 if (pendingException != null) {
456 throw pendingException;
457 }
458
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700459 mSessionStateCallback = mCurrentSession.getDeviceStateCallback();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700460 }
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700461 }
462
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700463 /**
464 * For use by backwards-compatibility code only.
465 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700466 public void setSessionListener(StateCallbackKK sessionCallback) {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700467 synchronized(mInterfaceLock) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700468 mSessionStateCallback = sessionCallback;
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700469 }
470 }
471
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700472 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700473 public CaptureRequest.Builder createCaptureRequest(int templateType)
474 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700475 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700476 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000477
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700478 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000479
480 try {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700481 mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000482 } catch (CameraRuntimeException e) {
483 throw e.asChecked();
484 } catch (RemoteException e) {
485 // impossible
486 return null;
487 }
488
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700489 CaptureRequest.Builder builder =
490 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000491
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700492 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000493 }
494 }
495
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700496 public int capture(CaptureRequest request, CaptureCallback callback, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000497 throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700498 if (DEBUG) {
499 Log.d(TAG, "calling capture");
500 }
501 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
502 requestList.add(request);
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700503 return submitCaptureRequest(requestList, callback, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000504 }
505
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700506 public int captureBurst(List<CaptureRequest> requests, CaptureCallback callback,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700507 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700508 if (requests == null || requests.isEmpty()) {
509 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700510 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700511 return submitCaptureRequest(requests, callback, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000512 }
513
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700514 /**
515 * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
516 * starting and stopping repeating request and flushing.
517 *
518 * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700519 * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700520 * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
521 * is added to the list mFrameNumberRequestPairs.</p>
522 *
523 * @param requestId the request ID of the current repeating request.
524 *
525 * @param lastFrameNumber last frame number returned from binder.
526 */
527 private void checkEarlyTriggerSequenceComplete(
528 final int requestId, final long lastFrameNumber) {
529 // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700530 // was never sent to HAL. Should trigger onCaptureSequenceAborted immediately.
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700531 if (lastFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
532 final CaptureCallbackHolder holder;
533 int index = mCaptureCallbackMap.indexOfKey(requestId);
534 holder = (index >= 0) ? mCaptureCallbackMap.valueAt(index) : null;
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700535 if (holder != null) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700536 mCaptureCallbackMap.removeAt(index);
Jianing Weibaf0c652014-04-18 17:35:00 -0700537 if (DEBUG) {
538 Log.v(TAG, String.format(
539 "remove holder for requestId %d, "
540 + "because lastFrame is %d.",
541 requestId, lastFrameNumber));
542 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700543 }
544
545 if (holder != null) {
546 if (DEBUG) {
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700547 Log.v(TAG, "immediately trigger onCaptureSequenceAborted because"
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700548 + " request did not reach HAL");
549 }
550
551 Runnable resultDispatch = new Runnable() {
552 @Override
553 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700554 if (!CameraDeviceImpl.this.isClosed()) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700555 if (DEBUG) {
556 Log.d(TAG, String.format(
557 "early trigger sequence complete for request %d",
558 requestId));
559 }
560 if (lastFrameNumber < Integer.MIN_VALUE
561 || lastFrameNumber > Integer.MAX_VALUE) {
562 throw new AssertionError(lastFrameNumber + " cannot be cast to int");
563 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700564 holder.getCallback().onCaptureSequenceAborted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700565 CameraDeviceImpl.this,
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700566 requestId);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700567 }
568 }
569 };
570 holder.getHandler().post(resultDispatch);
571 } else {
572 Log.w(TAG, String.format(
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700573 "did not register callback to request %d",
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700574 requestId));
575 }
576 } else {
577 mFrameNumberRequestPairs.add(
578 new SimpleEntry<Long, Integer>(lastFrameNumber,
579 requestId));
Eino-Ville Talvala848fe732014-09-15 16:24:08 -0700580 // It is possible that the last frame has already arrived, so we need to check
581 // for sequence completion right away
582 checkAndFireSequenceComplete();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700583 }
584 }
585
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700586 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700587 Handler handler, boolean repeating) throws CameraAccessException {
588
589 // Need a valid handler, or current thread needs to have a looper, if
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700590 // callback is valid
591 handler = checkHandler(handler, callback);
Igor Murashkin70725502013-06-25 20:27:06 +0000592
Ruben Brunk7f2372b2014-07-02 11:05:08 -0700593 // Make sure that there all requests have at least 1 surface; all surfaces are non-null
594 for (CaptureRequest request : requestList) {
595 if (request.getTargets().isEmpty()) {
596 throw new IllegalArgumentException(
597 "Each request must have at least one Surface target");
598 }
599
600 for (Surface surface : request.getTargets()) {
601 if (surface == null) {
602 throw new IllegalArgumentException("Null Surface targets are not allowed");
603 }
604 }
605 }
606
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700607 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700608 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000609 int requestId;
610
Ruben Brunke73b41b2013-11-07 19:30:43 -0800611 if (repeating) {
612 stopRepeating();
613 }
614
Jianing Weid2c3a822014-03-27 18:27:43 -0700615 LongParcelable lastFrameNumberRef = new LongParcelable();
Igor Murashkin70725502013-06-25 20:27:06 +0000616 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700617 requestId = mRemoteDevice.submitRequestList(requestList, repeating,
618 /*out*/lastFrameNumberRef);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700619 if (DEBUG) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700620 Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
621 }
Igor Murashkin70725502013-06-25 20:27:06 +0000622 } catch (CameraRuntimeException e) {
623 throw e.asChecked();
624 } catch (RemoteException e) {
625 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700626 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000627 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700628
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700629 if (callback != null) {
630 mCaptureCallbackMap.put(requestId, new CaptureCallbackHolder(callback,
Jianing Weid2c3a822014-03-27 18:27:43 -0700631 requestList, handler, repeating));
Jianing Weibaf0c652014-04-18 17:35:00 -0700632 } else {
633 if (DEBUG) {
634 Log.d(TAG, "Listen for request " + requestId + " is null");
635 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700636 }
Igor Murashkin70725502013-06-25 20:27:06 +0000637
Jianing Weid2c3a822014-03-27 18:27:43 -0700638 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700639
Igor Murashkin70725502013-06-25 20:27:06 +0000640 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700641 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700642 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700643 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700644 mRepeatingRequestId = requestId;
Jianing Weid2c3a822014-03-27 18:27:43 -0700645 } else {
646 mFrameNumberRequestPairs.add(
647 new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
Igor Murashkin70725502013-06-25 20:27:06 +0000648 }
649
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700650 if (mIdle) {
651 mDeviceHandler.post(mCallOnActive);
652 }
653 mIdle = false;
654
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700655 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000656 }
657 }
658
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700659 public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700660 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700661 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
662 requestList.add(request);
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700663 return submitCaptureRequest(requestList, callback, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000664 }
665
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700666 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureCallback callback,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700667 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700668 if (requests == null || requests.isEmpty()) {
669 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700670 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700671 return submitCaptureRequest(requests, callback, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000672 }
673
Igor Murashkin70725502013-06-25 20:27:06 +0000674 public void stopRepeating() throws CameraAccessException {
675
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700676 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700677 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700678 if (mRepeatingRequestId != REQUEST_ID_NONE) {
679
680 int requestId = mRepeatingRequestId;
681 mRepeatingRequestId = REQUEST_ID_NONE;
682
683 // Queue for deletion after in-flight requests finish
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700684 if (mCaptureCallbackMap.get(requestId) != null) {
Zhijun He1a9b6462014-03-31 16:11:33 -0700685 mRepeatingRequestIdDeletedList.add(requestId);
686 }
Igor Murashkin70725502013-06-25 20:27:06 +0000687
688 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700689 LongParcelable lastFrameNumberRef = new LongParcelable();
690 mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
691 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700692
693 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
694
Igor Murashkin70725502013-06-25 20:27:06 +0000695 } catch (CameraRuntimeException e) {
696 throw e.asChecked();
697 } catch (RemoteException e) {
698 // impossible
699 return;
700 }
701 }
702 }
703 }
704
Zhijun Hed842fcd2013-12-26 14:14:04 -0800705 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700706
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700707 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700708 checkIfCameraClosedOrInError();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700709
Ruben Brunkdecfe952013-10-29 11:00:32 -0700710 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700711 throw new IllegalStateException("Active repeating request ongoing");
712 }
Zhijun He7f4d3142013-07-23 07:54:38 -0700713 try {
714 mRemoteDevice.waitUntilIdle();
715 } catch (CameraRuntimeException e) {
716 throw e.asChecked();
717 } catch (RemoteException e) {
718 // impossible
719 return;
720 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700721 }
Igor Murashkin70725502013-06-25 20:27:06 +0000722 }
723
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700724 public void flush() throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700725 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700726 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700727
728 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvalac346bbf2014-08-27 17:05:29 -0700729
730 // If already idle, just do a busy->idle transition immediately, don't actually
731 // flush.
732 if (mIdle) {
733 mDeviceHandler.post(mCallOnIdle);
734 return;
735 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700736 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700737 LongParcelable lastFrameNumberRef = new LongParcelable();
738 mRemoteDevice.flush(/*out*/lastFrameNumberRef);
739 if (mRepeatingRequestId != REQUEST_ID_NONE) {
740 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700741 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700742 mRepeatingRequestId = REQUEST_ID_NONE;
743 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700744 } catch (CameraRuntimeException e) {
745 throw e.asChecked();
746 } catch (RemoteException e) {
747 // impossible
748 return;
749 }
750 }
751 }
752
753 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700754 public void close() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700755 synchronized (mInterfaceLock) {
Igor Murashkin70725502013-06-25 20:27:06 +0000756 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700757 if (mRemoteDevice != null) {
758 mRemoteDevice.disconnect();
759 }
Igor Murashkin70725502013-06-25 20:27:06 +0000760 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700761 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000762 } catch (RemoteException e) {
763 // impossible
764 }
765
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700766 // Only want to fire the onClosed callback once;
767 // either a normal close where the remote device is valid
768 // or a close after a startup error (no remote device but in error state)
769 if (mRemoteDevice != null || mInError) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700770 mDeviceHandler.post(mCallOnClosed);
771 }
Igor Murashkin70725502013-06-25 20:27:06 +0000772
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700773 mRemoteDevice = null;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700774 mInError = false;
Igor Murashkin70725502013-06-25 20:27:06 +0000775 }
776 }
777
778 @Override
779 protected void finalize() throws Throwable {
780 try {
781 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000782 }
783 finally {
784 super.finalize();
785 }
786 }
787
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700788 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700789 * <p>A callback for tracking the progress of a {@link CaptureRequest}
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700790 * submitted to the camera device.</p>
791 *
792 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700793 public static abstract class CaptureCallback {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700794
795 /**
796 * This constant is used to indicate that no images were captured for
797 * the request.
798 *
799 * @hide
800 */
801 public static final int NO_FRAMES_CAPTURED = -1;
802
803 /**
804 * This method is called when the camera device has started capturing
805 * the output image for the request, at the beginning of image exposure.
806 *
807 * @see android.media.MediaActionSound
808 */
809 public void onCaptureStarted(CameraDevice camera,
Eino-Ville Talvalae8df3092014-09-08 14:30:50 -0700810 CaptureRequest request, long timestamp, long frameNumber) {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700811 // default empty implementation
812 }
813
814 /**
815 * This method is called when some results from an image capture are
816 * available.
817 *
818 * @hide
819 */
820 public void onCapturePartial(CameraDevice camera,
821 CaptureRequest request, CaptureResult result) {
822 // default empty implementation
823 }
824
825 /**
826 * This method is called when an image capture makes partial forward progress; some
827 * (but not all) results from an image capture are available.
828 *
829 */
830 public void onCaptureProgressed(CameraDevice camera,
831 CaptureRequest request, CaptureResult partialResult) {
832 // default empty implementation
833 }
834
835 /**
836 * This method is called when an image capture has fully completed and all the
837 * result metadata is available.
838 */
839 public void onCaptureCompleted(CameraDevice camera,
840 CaptureRequest request, TotalCaptureResult result) {
841 // default empty implementation
842 }
843
844 /**
845 * This method is called instead of {@link #onCaptureCompleted} when the
846 * camera device failed to produce a {@link CaptureResult} for the
847 * request.
848 */
849 public void onCaptureFailed(CameraDevice camera,
850 CaptureRequest request, CaptureFailure failure) {
851 // default empty implementation
852 }
853
854 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700855 * This method is called independently of the others in CaptureCallback,
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700856 * when a capture sequence finishes and all {@link CaptureResult}
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700857 * or {@link CaptureFailure} for it have been returned via this callback.
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700858 */
859 public void onCaptureSequenceCompleted(CameraDevice camera,
860 int sequenceId, long frameNumber) {
861 // default empty implementation
862 }
863
864 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700865 * This method is called independently of the others in CaptureCallback,
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700866 * when a capture sequence aborts before any {@link CaptureResult}
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700867 * or {@link CaptureFailure} for it have been returned via this callback.
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700868 */
869 public void onCaptureSequenceAborted(CameraDevice camera,
870 int sequenceId) {
871 // default empty implementation
872 }
873 }
874
875 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700876 * A callback for notifications about the state of a camera device, adding in the callbacks that
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700877 * were part of the earlier KK API design, but now only used internally.
878 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700879 public static abstract class StateCallbackKK extends StateCallback {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700880 /**
881 * The method called when a camera device has no outputs configured.
882 *
883 */
884 public void onUnconfigured(CameraDevice camera) {
885 // Default empty implementation
886 }
887
888 /**
889 * The method called when a camera device begins processing
890 * {@link CaptureRequest capture requests}.
891 *
892 */
893 public void onActive(CameraDevice camera) {
894 // Default empty implementation
895 }
896
897 /**
898 * The method called when a camera device is busy.
899 *
900 */
901 public void onBusy(CameraDevice camera) {
902 // Default empty implementation
903 }
904
905 /**
906 * The method called when a camera device has finished processing all
907 * submitted capture requests and has reached an idle state.
908 *
909 */
910 public void onIdle(CameraDevice camera) {
911 // Default empty implementation
912 }
913 }
914
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700915 static class CaptureCallbackHolder {
Igor Murashkin70725502013-06-25 20:27:06 +0000916
917 private final boolean mRepeating;
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700918 private final CaptureCallback mCallback;
Jianing Weid2c3a822014-03-27 18:27:43 -0700919 private final List<CaptureRequest> mRequestList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700920 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000921
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700922 CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList,
Jianing Weid2c3a822014-03-27 18:27:43 -0700923 Handler handler, boolean repeating) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700924 if (callback == null || handler == null) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700925 throw new UnsupportedOperationException(
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700926 "Must have a valid handler and a valid callback");
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700927 }
Igor Murashkin70725502013-06-25 20:27:06 +0000928 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700929 mHandler = handler;
Jianing Weid2c3a822014-03-27 18:27:43 -0700930 mRequestList = new ArrayList<CaptureRequest>(requestList);
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700931 mCallback = callback;
Igor Murashkin70725502013-06-25 20:27:06 +0000932 }
933
934 public boolean isRepeating() {
935 return mRepeating;
936 }
937
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700938 public CaptureCallback getCallback() {
939 return mCallback;
Igor Murashkin70725502013-06-25 20:27:06 +0000940 }
941
Jianing Weid2c3a822014-03-27 18:27:43 -0700942 public CaptureRequest getRequest(int subsequenceId) {
943 if (subsequenceId >= mRequestList.size()) {
944 throw new IllegalArgumentException(
945 String.format(
946 "Requested subsequenceId %d is larger than request list size %d.",
947 subsequenceId, mRequestList.size()));
948 } else {
949 if (subsequenceId < 0) {
950 throw new IllegalArgumentException(String.format(
951 "Requested subsequenceId %d is negative", subsequenceId));
952 } else {
953 return mRequestList.get(subsequenceId);
954 }
955 }
956 }
957
Igor Murashkin70725502013-06-25 20:27:06 +0000958 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700959 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +0000960 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700961
962 public Handler getHandler() {
963 return mHandler;
964 }
965
Igor Murashkin70725502013-06-25 20:27:06 +0000966 }
967
Jianing Weid2c3a822014-03-27 18:27:43 -0700968 /**
969 * This class tracks the last frame number for submitted requests.
970 */
971 public class FrameNumberTracker {
972
973 private long mCompletedFrameNumber = -1;
974 private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
Igor Murashkin1e854c52014-08-28 15:21:49 -0700975 /** Map frame numbers to list of partial results */
976 private final HashMap<Long, List<CaptureResult>> mPartialResults = new HashMap<>();
Jianing Weid2c3a822014-03-27 18:27:43 -0700977
978 private void update() {
979 Iterator<Long> iter = mFutureErrorSet.iterator();
980 while (iter.hasNext()) {
981 long errorFrameNumber = iter.next();
982 if (errorFrameNumber == mCompletedFrameNumber + 1) {
983 mCompletedFrameNumber++;
984 iter.remove();
985 } else {
986 break;
987 }
988 }
989 }
990
991 /**
992 * This function is called every time when a result or an error is received.
Igor Murashkin1e854c52014-08-28 15:21:49 -0700993 * @param frameNumber the frame number corresponding to the result or error
994 * @param isError true if it is an error, false if it is not an error
Jianing Weid2c3a822014-03-27 18:27:43 -0700995 */
996 public void updateTracker(long frameNumber, boolean isError) {
997 if (isError) {
998 mFutureErrorSet.add(frameNumber);
999 } else {
1000 /**
1001 * HAL cannot send an OnResultReceived for frame N unless it knows for
1002 * sure that all frames prior to N have either errored out or completed.
1003 * So if the current frame is not an error, then all previous frames
1004 * should have arrived. The following line checks whether this holds.
1005 */
1006 if (frameNumber != mCompletedFrameNumber + 1) {
Zhijun He22589b42014-05-01 10:37:36 -07001007 Log.e(TAG, String.format(
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001008 "result frame number %d comes out of order, should be %d + 1",
1009 frameNumber, mCompletedFrameNumber));
Eino-Ville Talvala95037852014-09-14 14:07:05 -07001010 // Continue on to set the completed frame number to this frame anyway,
1011 // to be robust to lower-level errors and allow for clean shutdowns.
Jianing Weid2c3a822014-03-27 18:27:43 -07001012 }
Eino-Ville Talvala95037852014-09-14 14:07:05 -07001013 mCompletedFrameNumber = frameNumber;
Jianing Weid2c3a822014-03-27 18:27:43 -07001014 }
1015 update();
1016 }
1017
Igor Murashkin1e854c52014-08-28 15:21:49 -07001018 /**
1019 * This function is called every time a result has been completed.
1020 *
1021 * <p>It keeps a track of all the partial results already created for a particular
1022 * frame number.</p>
1023 *
1024 * @param frameNumber the frame number corresponding to the result
1025 * @param result the total or partial result
1026 * @param partial {@true} if the result is partial, {@code false} if total
1027 */
1028 public void updateTracker(long frameNumber, CaptureResult result, boolean partial) {
1029
1030 if (!partial) {
1031 // Update the total result's frame status as being successful
1032 updateTracker(frameNumber, /*isError*/false);
1033 // Don't keep a list of total results, we don't need to track them
1034 return;
1035 }
1036
1037 if (result == null) {
1038 // Do not record blank results; this also means there will be no total result
1039 // so it doesn't matter that the partials were not recorded
1040 return;
1041 }
1042
1043 // Partial results must be aggregated in-order for that frame number
1044 List<CaptureResult> partials = mPartialResults.get(frameNumber);
1045 if (partials == null) {
1046 partials = new ArrayList<>();
1047 mPartialResults.put(frameNumber, partials);
1048 }
1049
1050 partials.add(result);
1051 }
1052
1053 /**
1054 * Attempt to pop off all of the partial results seen so far for the {@code frameNumber}.
1055 *
1056 * <p>Once popped-off, the partial results are forgotten (unless {@code updateTracker}
1057 * is called again with new partials for that frame number).</p>
1058 *
1059 * @param frameNumber the frame number corresponding to the result
1060 * @return a list of partial results for that frame with at least 1 element,
1061 * or {@code null} if there were no partials recorded for that frame
1062 */
1063 public List<CaptureResult> popPartialResults(long frameNumber) {
1064 return mPartialResults.remove(frameNumber);
1065 }
1066
Jianing Weid2c3a822014-03-27 18:27:43 -07001067 public long getCompletedFrameNumber() {
1068 return mCompletedFrameNumber;
1069 }
1070
1071 }
1072
1073 private void checkAndFireSequenceComplete() {
1074 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
1075 Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
1076 while (iter.hasNext()) {
1077 final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
1078 if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
1079
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001080 // remove request from mCaptureCallbackMap
Jianing Weid2c3a822014-03-27 18:27:43 -07001081 final int requestId = frameNumberRequestPair.getValue();
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001082 final CaptureCallbackHolder holder;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001083 synchronized(mInterfaceLock) {
1084 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001085 Log.w(TAG, "Camera closed while checking sequences");
1086 return;
1087 }
1088
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001089 int index = mCaptureCallbackMap.indexOfKey(requestId);
1090 holder = (index >= 0) ? mCaptureCallbackMap.valueAt(index)
Jianing Weid2c3a822014-03-27 18:27:43 -07001091 : null;
1092 if (holder != null) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001093 mCaptureCallbackMap.removeAt(index);
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001094 if (DEBUG) {
1095 Log.v(TAG, String.format(
1096 "remove holder for requestId %d, "
1097 + "because lastFrame %d is <= %d",
1098 requestId, frameNumberRequestPair.getKey(),
1099 completedFrameNumber));
1100 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001101 }
1102 }
1103 iter.remove();
1104
1105 // Call onCaptureSequenceCompleted
1106 if (holder != null) {
1107 Runnable resultDispatch = new Runnable() {
1108 @Override
1109 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001110 if (!CameraDeviceImpl.this.isClosed()){
Jianing Weid2c3a822014-03-27 18:27:43 -07001111 if (DEBUG) {
1112 Log.d(TAG, String.format(
1113 "fire sequence complete for request %d",
1114 requestId));
1115 }
1116
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001117 long lastFrameNumber = frameNumberRequestPair.getKey();
1118 if (lastFrameNumber < Integer.MIN_VALUE
1119 || lastFrameNumber > Integer.MAX_VALUE) {
1120 throw new AssertionError(lastFrameNumber
1121 + " cannot be cast to int");
1122 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001123 holder.getCallback().onCaptureSequenceCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -07001124 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -07001125 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -07001126 lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -07001127 }
1128 }
1129 };
1130 holder.getHandler().post(resultDispatch);
1131 }
1132
1133 }
1134 }
1135 }
1136
Zhijun Heecb323e2013-07-31 09:40:27 -07001137 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001138 //
1139 // Constants below need to be kept up-to-date with
1140 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
1141 //
1142
1143 //
1144 // Error codes for onCameraError
1145 //
1146
1147 /**
1148 * Camera has been disconnected
1149 */
Ruben Brunke663cb772014-09-16 13:18:31 -07001150 public static final int ERROR_CAMERA_DISCONNECTED = 0;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001151 /**
1152 * Camera has encountered a device-level error
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001153 * Matches CameraDevice.StateCallback#ERROR_CAMERA_DEVICE
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001154 */
Ruben Brunke663cb772014-09-16 13:18:31 -07001155 public static final int ERROR_CAMERA_DEVICE = 1;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001156 /**
1157 * Camera has encountered a service-level error
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001158 * Matches CameraDevice.StateCallback#ERROR_CAMERA_SERVICE
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001159 */
Ruben Brunke663cb772014-09-16 13:18:31 -07001160 public static final int ERROR_CAMERA_SERVICE = 2;
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001161 /**
1162 * Camera has encountered an error processing a single request.
1163 */
Ruben Brunke663cb772014-09-16 13:18:31 -07001164 public static final int ERROR_CAMERA_REQUEST = 3;
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001165 /**
1166 * Camera has encountered an error producing metadata for a single capture
1167 */
Ruben Brunke663cb772014-09-16 13:18:31 -07001168 public static final int ERROR_CAMERA_RESULT = 4;
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001169 /**
1170 * Camera has encountered an error producing an image buffer for a single capture
1171 */
Ruben Brunke663cb772014-09-16 13:18:31 -07001172 public static final int ERROR_CAMERA_BUFFER = 5;
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001173
Igor Murashkin70725502013-06-25 20:27:06 +00001174 @Override
1175 public IBinder asBinder() {
1176 return this;
1177 }
1178
Igor Murashkin70725502013-06-25 20:27:06 +00001179 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001180 public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) {
1181 if (DEBUG) {
1182 Log.d(TAG, String.format(
Ruben Brunke663cb772014-09-16 13:18:31 -07001183 "Device error received, code %d, frame number %d, request ID %d, subseq ID %d",
1184 errorCode, resultExtras.getFrameNumber(), resultExtras.getRequestId(),
1185 resultExtras.getSubsequenceId()));
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001186 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001187
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001188 synchronized(mInterfaceLock) {
1189 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001190 return; // Camera already closed
1191 }
1192
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001193 switch (errorCode) {
1194 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001195 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnDisconnected);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001196 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001197 default:
1198 Log.e(TAG, "Unknown error from camera device: " + errorCode);
1199 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001200 case ERROR_CAMERA_DEVICE:
1201 case ERROR_CAMERA_SERVICE:
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001202 mInError = true;
1203 Runnable r = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -07001204 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001205 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001206 if (!CameraDeviceImpl.this.isClosed()) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001207 mDeviceCallback.onError(CameraDeviceImpl.this, errorCode);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001208 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001209 }
1210 };
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001211 CameraDeviceImpl.this.mDeviceHandler.post(r);
1212 break;
1213 case ERROR_CAMERA_REQUEST:
1214 case ERROR_CAMERA_RESULT:
1215 case ERROR_CAMERA_BUFFER:
1216 onCaptureErrorLocked(errorCode, resultExtras);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001217 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001218 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001219 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001220 }
1221
1222 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001223 public void onDeviceIdle() {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001224 if (DEBUG) {
1225 Log.d(TAG, "Camera now idle");
1226 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001227 synchronized(mInterfaceLock) {
1228 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07001229
Igor Murashkin21547d62014-06-04 15:21:42 -07001230 if (!CameraDeviceImpl.this.mIdle) {
1231 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnIdle);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001232 }
Igor Murashkin21547d62014-06-04 15:21:42 -07001233 CameraDeviceImpl.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001234 }
1235 }
1236
1237 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001238 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
1239 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae8df3092014-09-08 14:30:50 -07001240 final long frameNumber = resultExtras.getFrameNumber();
1241
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001242 if (DEBUG) {
Eino-Ville Talvalae8df3092014-09-08 14:30:50 -07001243 Log.d(TAG, "Capture started for id " + requestId + " frame number " + frameNumber);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001244 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001245 final CaptureCallbackHolder holder;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001246
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001247 synchronized(mInterfaceLock) {
1248 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07001249
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001250 // Get the callback for this frame ID, if there is one
1251 holder = CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001252
Igor Murashkin49b2b132014-06-18 19:03:00 -07001253 if (holder == null) {
1254 return;
1255 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001256
Igor Murashkin49b2b132014-06-18 19:03:00 -07001257 if (isClosed()) return;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001258
Igor Murashkin49b2b132014-06-18 19:03:00 -07001259 // Dispatch capture start notice
1260 holder.getHandler().post(
1261 new Runnable() {
1262 @Override
1263 public void run() {
1264 if (!CameraDeviceImpl.this.isClosed()) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001265 holder.getCallback().onCaptureStarted(
Igor Murashkin49b2b132014-06-18 19:03:00 -07001266 CameraDeviceImpl.this,
1267 holder.getRequest(resultExtras.getSubsequenceId()),
Eino-Ville Talvalae8df3092014-09-08 14:30:50 -07001268 timestamp, frameNumber);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001269 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001270 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001271 });
1272
1273 }
Igor Murashkin70725502013-06-25 20:27:06 +00001274 }
1275
1276 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001277 public void onResultReceived(CameraMetadataNative result,
1278 CaptureResultExtras resultExtras) throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -07001279
Jianing Weid2c3a822014-03-27 18:27:43 -07001280 int requestId = resultExtras.getRequestId();
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001281 long frameNumber = resultExtras.getFrameNumber();
1282
Zhijun Heecb323e2013-07-31 09:40:27 -07001283 if (DEBUG) {
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001284 Log.v(TAG, "Received result frame " + frameNumber + " for id "
Jianing Weibaf0c652014-04-18 17:35:00 -07001285 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -07001286 }
Ruben Brunk57493682014-05-27 18:58:08 -07001287
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001288 synchronized(mInterfaceLock) {
1289 if (mRemoteDevice == null) return; // Camera already closed
Ruben Brunk57493682014-05-27 18:58:08 -07001290
Igor Murashkin49b2b132014-06-18 19:03:00 -07001291 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
1292 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
1293 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
Ruben Brunk57493682014-05-27 18:58:08 -07001294
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001295 final CaptureCallbackHolder holder =
1296 CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +00001297
Zhijun He83159152014-07-16 11:32:59 -07001298 boolean isPartialResult =
1299 (resultExtras.getPartialResultCount() < mTotalPartialCount);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001300
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001301 // Check if we have a callback for this
Igor Murashkin49b2b132014-06-18 19:03:00 -07001302 if (holder == null) {
1303 if (DEBUG) {
1304 Log.d(TAG,
1305 "holder is null, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001306 + frameNumber);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001307 }
Igor Murashkin1e854c52014-08-28 15:21:49 -07001308
1309 mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult);
1310
Igor Murashkin49b2b132014-06-18 19:03:00 -07001311 return;
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001312 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001313
Igor Murashkin49b2b132014-06-18 19:03:00 -07001314 if (isClosed()) {
1315 if (DEBUG) {
1316 Log.d(TAG,
1317 "camera is closed, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001318 + frameNumber);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001319 }
Igor Murashkin1e854c52014-08-28 15:21:49 -07001320
1321 mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001322 return;
1323 }
Igor Murashkindb075af2014-05-21 10:07:08 -07001324
Igor Murashkin49b2b132014-06-18 19:03:00 -07001325 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
1326
Igor Murashkin49b2b132014-06-18 19:03:00 -07001327 Runnable resultDispatch = null;
1328
Igor Murashkin1e854c52014-08-28 15:21:49 -07001329 CaptureResult finalResult;
1330
Igor Murashkin49b2b132014-06-18 19:03:00 -07001331 // Either send a partial result or the final capture completed result
Zhijun He83159152014-07-16 11:32:59 -07001332 if (isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001333 final CaptureResult resultAsCapture =
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001334 new CaptureResult(result, request, resultExtras);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001335
1336 // Partial result
1337 resultDispatch = new Runnable() {
1338 @Override
1339 public void run() {
1340 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001341 holder.getCallback().onCaptureProgressed(
Igor Murashkin49b2b132014-06-18 19:03:00 -07001342 CameraDeviceImpl.this,
1343 request,
1344 resultAsCapture);
1345 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001346 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001347 };
Igor Murashkin1e854c52014-08-28 15:21:49 -07001348
1349 finalResult = resultAsCapture;
Igor Murashkin49b2b132014-06-18 19:03:00 -07001350 } else {
Igor Murashkin1e854c52014-08-28 15:21:49 -07001351 List<CaptureResult> partialResults =
1352 mFrameNumberTracker.popPartialResults(frameNumber);
1353
Igor Murashkin49b2b132014-06-18 19:03:00 -07001354 final TotalCaptureResult resultAsCapture =
Igor Murashkin1e854c52014-08-28 15:21:49 -07001355 new TotalCaptureResult(result, request, resultExtras, partialResults);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001356
Igor Murashkin49b2b132014-06-18 19:03:00 -07001357 // Final capture result
1358 resultDispatch = new Runnable() {
1359 @Override
1360 public void run() {
1361 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001362 holder.getCallback().onCaptureCompleted(
Igor Murashkin49b2b132014-06-18 19:03:00 -07001363 CameraDeviceImpl.this,
1364 request,
1365 resultAsCapture);
1366 }
1367 }
1368 };
Igor Murashkin1e854c52014-08-28 15:21:49 -07001369
1370 finalResult = resultAsCapture;
Igor Murashkin49b2b132014-06-18 19:03:00 -07001371 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001372
Igor Murashkin49b2b132014-06-18 19:03:00 -07001373 holder.getHandler().post(resultDispatch);
1374
Igor Murashkin1e854c52014-08-28 15:21:49 -07001375 // Collect the partials for a total result; or mark the frame as totally completed
1376 mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult);
1377
Igor Murashkin49b2b132014-06-18 19:03:00 -07001378 // Fire onCaptureSequenceCompleted
Zhijun He83159152014-07-16 11:32:59 -07001379 if (!isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001380 checkAndFireSequenceComplete();
1381 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001382 }
Igor Murashkin70725502013-06-25 20:27:06 +00001383 }
1384
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001385 /**
1386 * Called by onDeviceError for handling single-capture failures.
1387 */
1388 private void onCaptureErrorLocked(int errorCode, CaptureResultExtras resultExtras) {
1389
1390 final int requestId = resultExtras.getRequestId();
1391 final int subsequenceId = resultExtras.getSubsequenceId();
1392 final long frameNumber = resultExtras.getFrameNumber();
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001393 final CaptureCallbackHolder holder =
1394 CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001395
1396 final CaptureRequest request = holder.getRequest(subsequenceId);
1397
1398 // No way to report buffer errors right now
1399 if (errorCode == ERROR_CAMERA_BUFFER) {
1400 Log.e(TAG, String.format("Lost output buffer reported for frame %d", frameNumber));
1401 return;
1402 }
1403
1404 boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
1405
1406 // This is only approximate - exact handling needs the camera service and HAL to
1407 // disambiguate between request failures to due abort and due to real errors.
1408 // For now, assume that if the session believes we're mid-abort, then the error
1409 // is due to abort.
1410 int reason = (mCurrentSession != null && mCurrentSession.isAborting()) ?
1411 CaptureFailure.REASON_FLUSHED :
1412 CaptureFailure.REASON_ERROR;
1413
1414 final CaptureFailure failure = new CaptureFailure(
1415 request,
1416 reason,
1417 /*dropped*/ mayHaveBuffers,
1418 requestId,
1419 frameNumber);
1420
1421 Runnable failureDispatch = new Runnable() {
1422 @Override
1423 public void run() {
1424 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001425 holder.getCallback().onCaptureFailed(
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001426 CameraDeviceImpl.this,
1427 request,
1428 failure);
1429 }
1430 }
1431 };
1432 holder.getHandler().post(failureDispatch);
1433
1434 // Fire onCaptureSequenceCompleted if appropriate
1435 if (DEBUG) {
1436 Log.v(TAG, String.format("got error frame %d", frameNumber));
1437 }
1438 mFrameNumberTracker.updateTracker(frameNumber, /*error*/true);
1439 checkAndFireSequenceComplete();
1440 }
1441
1442 } // public class CameraDeviceCallbacks
Igor Murashkin70725502013-06-25 20:27:06 +00001443
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001444 /**
Igor Murashkin0b27d342014-05-30 09:45:05 -07001445 * Default handler management.
1446 *
1447 * <p>
1448 * If handler is null, get the current thread's
1449 * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
1450 * </p>
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001451 */
Igor Murashkin0b27d342014-05-30 09:45:05 -07001452 static Handler checkHandler(Handler handler) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001453 if (handler == null) {
1454 Looper looper = Looper.myLooper();
1455 if (looper == null) {
1456 throw new IllegalArgumentException(
1457 "No handler given, and current thread has no looper!");
1458 }
1459 handler = new Handler(looper);
1460 }
1461 return handler;
1462 }
1463
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001464 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001465 * Default handler management, conditional on there being a callback.
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001466 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001467 * <p>If the callback isn't null, check the handler, otherwise pass it through.</p>
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001468 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001469 static <T> Handler checkHandler(Handler handler, T callback) {
1470 if (callback != null) {
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001471 return checkHandler(handler);
1472 }
1473 return handler;
1474 }
1475
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001476 private void checkIfCameraClosedOrInError() throws CameraAccessException {
1477 if (mInError) {
1478 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
1479 "The camera device has encountered a serious error");
1480 }
Zhijun He7f4d3142013-07-23 07:54:38 -07001481 if (mRemoteDevice == null) {
1482 throw new IllegalStateException("CameraDevice was already closed");
1483 }
1484 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001485
Igor Murashkin49b2b132014-06-18 19:03:00 -07001486 /** Whether the camera device has started to close (may not yet have finished) */
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001487 private boolean isClosed() {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001488 return mClosing;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001489 }
Ruben Brunk57493682014-05-27 18:58:08 -07001490
1491 private CameraCharacteristics getCharacteristics() {
1492 return mCharacteristics;
1493 }
Igor Murashkin70725502013-06-25 20:27:06 +00001494}