blob: 38f8e3947f9fb048f17da913f86d546eedec714f [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;
Yin-Chia Yeh35286a22015-03-09 16:53:14 -070031import android.hardware.camera2.params.OutputConfiguration;
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -070032import android.hardware.camera2.utils.CameraBinderDecorator;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070033import android.hardware.camera2.utils.CameraRuntimeException;
Igor Murashkin9c595172014-05-12 13:56:20 -070034import android.hardware.camera2.utils.LongParcelable;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070035import android.os.Handler;
Ruben Brunkdecfe952013-10-29 11:00:32 -070036import android.os.IBinder;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070037import android.os.Looper;
Ruben Brunkdecfe952013-10-29 11:00:32 -070038import android.os.RemoteException;
Igor Murashkin70725502013-06-25 20:27:06 +000039import android.util.Log;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070040import android.util.SparseArray;
Igor Murashkin70725502013-06-25 20:27:06 +000041import android.view.Surface;
42
Jianing Weid2c3a822014-03-27 18:27:43 -070043import java.util.AbstractMap.SimpleEntry;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070044import java.util.ArrayList;
Igor Murashkin1e854c52014-08-28 15:21:49 -070045import java.util.HashMap;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070046import java.util.HashSet;
Ruben Brunkdecfe952013-10-29 11:00:32 -070047import java.util.Iterator;
Igor Murashkin70725502013-06-25 20:27:06 +000048import java.util.List;
Jianing Weid2c3a822014-03-27 18:27:43 -070049import java.util.TreeSet;
Igor Murashkin70725502013-06-25 20:27:06 +000050
51/**
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070052 * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
Igor Murashkin70725502013-06-25 20:27:06 +000053 */
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -070054public class CameraDeviceImpl extends CameraDevice {
Igor Murashkin70725502013-06-25 20:27:06 +000055 private final String TAG;
Zhijun Heecb323e2013-07-31 09:40:27 -070056 private final boolean DEBUG;
Igor Murashkin70725502013-06-25 20:27:06 +000057
Ruben Brunkdecfe952013-10-29 11:00:32 -070058 private static final int REQUEST_ID_NONE = -1;
59
Igor Murashkin70725502013-06-25 20:27:06 +000060 // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
61 private ICameraDeviceUser mRemoteDevice;
62
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070063 // Lock to synchronize cross-thread access to device public interface
Igor Murashkin51dcfd652014-09-25 16:55:01 -070064 final Object mInterfaceLock = new Object(); // access from this class and Session only!
Igor Murashkin70725502013-06-25 20:27:06 +000065 private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
66
Eino-Ville Talvalafd887432014-09-04 13:07:40 -070067 private final StateCallback mDeviceCallback;
68 private volatile StateCallbackKK mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070069 private final Handler mDeviceHandler;
70
Igor Murashkin49b2b132014-06-18 19:03:00 -070071 private volatile boolean mClosing = false;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -070072 private boolean mInError = false;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070073 private boolean mIdle = true;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070074
Eino-Ville Talvalafd887432014-09-04 13:07:40 -070075 /** map request IDs to callback/request data */
76 private final SparseArray<CaptureCallbackHolder> mCaptureCallbackMap =
77 new SparseArray<CaptureCallbackHolder>();
Igor Murashkin70725502013-06-25 20:27:06 +000078
Ruben Brunkdecfe952013-10-29 11:00:32 -070079 private int mRepeatingRequestId = REQUEST_ID_NONE;
80 private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>();
Igor Murashkin57ea59b2013-08-23 16:55:57 -070081 // Map stream IDs to Surfaces
Yin-Chia Yeh981e0562015-03-12 13:39:26 -070082 private final SparseArray<OutputConfiguration> mConfiguredOutputs =
83 new SparseArray<OutputConfiguration>();
Igor Murashkin70725502013-06-25 20:27:06 +000084
85 private final String mCameraId;
Ruben Brunk57493682014-05-27 18:58:08 -070086 private final CameraCharacteristics mCharacteristics;
Zhijun He83159152014-07-16 11:32:59 -070087 private final int mTotalPartialCount;
Igor Murashkin70725502013-06-25 20:27:06 +000088
Jianing Weid2c3a822014-03-27 18:27:43 -070089 /**
90 * A list tracking request and its expected last frame.
91 * Updated when calling ICameraDeviceUser methods.
92 */
93 private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>>
94 mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>();
95
96 /**
97 * An object tracking received frame numbers.
98 * Updated when receiving callbacks from ICameraDeviceCallbacks.
99 */
100 private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
101
Igor Murashkin0b27d342014-05-30 09:45:05 -0700102 private CameraCaptureSessionImpl mCurrentSession;
Eino-Ville Talvala95037852014-09-14 14:07:05 -0700103 private int mNextSessionId = 0;
Igor Murashkin0b27d342014-05-30 09:45:05 -0700104
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700105 // Runnables for all state transitions, except error, which needs the
106 // error code argument
107
108 private final Runnable mCallOnOpened = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700109 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700110 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700111 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700112 synchronized(mInterfaceLock) {
113 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700114
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700115 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700116 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700117 if (sessionCallback != null) {
118 sessionCallback.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700119 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700120 mDeviceCallback.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700121 }
122 };
123
124 private final Runnable mCallOnUnconfigured = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700125 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700126 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700127 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700128 synchronized(mInterfaceLock) {
129 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700130
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700131 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700132 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700133 if (sessionCallback != null) {
134 sessionCallback.onUnconfigured(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700135 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700136 }
137 };
138
139 private final Runnable mCallOnActive = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700140 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700141 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700142 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700143 synchronized(mInterfaceLock) {
144 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700145
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700146 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700147 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700148 if (sessionCallback != null) {
149 sessionCallback.onActive(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700150 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700151 }
152 };
153
154 private final Runnable mCallOnBusy = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700155 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700156 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700157 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700158 synchronized(mInterfaceLock) {
159 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700160
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700161 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700162 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700163 if (sessionCallback != null) {
164 sessionCallback.onBusy(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700165 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700166 }
167 };
168
169 private final Runnable mCallOnClosed = new Runnable() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700170 private boolean mClosedOnce = false;
171
Jianing Weid2c3a822014-03-27 18:27:43 -0700172 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700173 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700174 if (mClosedOnce) {
175 throw new AssertionError("Don't post #onClosed more than once");
176 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700177 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700178 synchronized(mInterfaceLock) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700179 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700180 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700181 if (sessionCallback != null) {
182 sessionCallback.onClosed(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700183 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700184 mDeviceCallback.onClosed(CameraDeviceImpl.this);
Igor Murashkin49b2b132014-06-18 19:03:00 -0700185 mClosedOnce = true;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700186 }
187 };
188
189 private final Runnable mCallOnIdle = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700190 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700191 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700192 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700193 synchronized(mInterfaceLock) {
194 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700195
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700196 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700197 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700198 if (sessionCallback != null) {
199 sessionCallback.onIdle(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700200 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700201 }
202 };
203
204 private final Runnable mCallOnDisconnected = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700205 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700206 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700207 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700208 synchronized(mInterfaceLock) {
209 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700210
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700211 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700212 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700213 if (sessionCallback != null) {
214 sessionCallback.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700215 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700216 mDeviceCallback.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700217 }
218 };
219
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700220 public CameraDeviceImpl(String cameraId, StateCallback callback, Handler handler,
Ruben Brunk57493682014-05-27 18:58:08 -0700221 CameraCharacteristics characteristics) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700222 if (cameraId == null || callback == null || handler == null || characteristics == null) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700223 throw new IllegalArgumentException("Null argument given");
224 }
Igor Murashkin70725502013-06-25 20:27:06 +0000225 mCameraId = cameraId;
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700226 mDeviceCallback = callback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700227 mDeviceHandler = handler;
Ruben Brunk57493682014-05-27 18:58:08 -0700228 mCharacteristics = characteristics;
Eino-Ville Talvalab72d1ef2014-04-28 13:21:18 -0700229
230 final int MAX_TAG_LEN = 23;
231 String tag = String.format("CameraDevice-JV-%s", mCameraId);
232 if (tag.length() > MAX_TAG_LEN) {
233 tag = tag.substring(0, MAX_TAG_LEN);
234 }
235 TAG = tag;
Zhijun Heecb323e2013-07-31 09:40:27 -0700236 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Zhijun He83159152014-07-16 11:32:59 -0700237
238 Integer partialCount =
239 mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
240 if (partialCount == null) {
241 // 1 means partial result is not supported.
242 mTotalPartialCount = 1;
243 } else {
244 mTotalPartialCount = partialCount;
245 }
Igor Murashkin70725502013-06-25 20:27:06 +0000246 }
247
248 public CameraDeviceCallbacks getCallbacks() {
249 return mCallbacks;
250 }
251
Igor Murashkin70725502013-06-25 20:27:06 +0000252 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700253 synchronized(mInterfaceLock) {
254 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700255 // If setRemoteFailure already called, do nothing
256 if (mInError) return;
257
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700258 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
259
260 mDeviceHandler.post(mCallOnOpened);
261 mDeviceHandler.post(mCallOnUnconfigured);
262 }
Igor Murashkin70725502013-06-25 20:27:06 +0000263 }
264
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700265 /**
266 * Call to indicate failed connection to a remote camera device.
267 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700268 * <p>This places the camera device in the error state and informs the callback.
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700269 * Use in place of setRemoteDevice() when startup fails.</p>
270 */
271 public void setRemoteFailure(final CameraRuntimeException failure) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700272 int failureCode = StateCallback.ERROR_CAMERA_DEVICE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700273 boolean failureIsError = true;
274
275 switch (failure.getReason()) {
276 case CameraAccessException.CAMERA_IN_USE:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700277 failureCode = StateCallback.ERROR_CAMERA_IN_USE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700278 break;
279 case CameraAccessException.MAX_CAMERAS_IN_USE:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700280 failureCode = StateCallback.ERROR_MAX_CAMERAS_IN_USE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700281 break;
282 case CameraAccessException.CAMERA_DISABLED:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700283 failureCode = StateCallback.ERROR_CAMERA_DISABLED;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700284 break;
285 case CameraAccessException.CAMERA_DISCONNECTED:
286 failureIsError = false;
287 break;
288 case CameraAccessException.CAMERA_ERROR:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700289 failureCode = StateCallback.ERROR_CAMERA_DEVICE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700290 break;
291 default:
292 Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
293 break;
294 }
295 final int code = failureCode;
296 final boolean isError = failureIsError;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700297 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700298 mInError = true;
299 mDeviceHandler.post(new Runnable() {
Igor Murashkine1442202014-06-09 17:51:24 -0700300 @Override
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700301 public void run() {
302 if (isError) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700303 mDeviceCallback.onError(CameraDeviceImpl.this, code);
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700304 } else {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700305 mDeviceCallback.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700306 }
307 }
308 });
309 }
310 }
311
Igor Murashkin70725502013-06-25 20:27:06 +0000312 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700313 public String getId() {
314 return mCameraId;
315 }
316
Igor Murashkin70725502013-06-25 20:27:06 +0000317 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700318 // Leave this here for backwards compatibility with older code using this directly
Yin-Chia Yeh981e0562015-03-12 13:39:26 -0700319 ArrayList<OutputConfiguration> outputConfigs = new ArrayList<>(outputs.size());
320 for (Surface s : outputs) {
321 outputConfigs.add(new OutputConfiguration(s));
322 }
323 configureOutputsChecked(outputConfigs);
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700324 }
325
326 /**
327 * Attempt to configure the outputs; the device goes to idle and then configures the
328 * new outputs if possible.
329 *
330 * <p>The configuration may gracefully fail, if there are too many outputs, if the formats
331 * are not supported, or if the sizes for that format is not supported. In this case this
332 * function will return {@code false} and the unconfigured callback will be fired.</p>
333 *
334 * <p>If the configuration succeeds (with 1 or more outputs), then the idle callback is fired.
335 * Unconfiguring the device always fires the idle callback.</p>
336 *
337 * @param outputs a list of one or more surfaces, or {@code null} to unconfigure
338 * @return whether or not the configuration was successful
339 *
340 * @throws CameraAccessException if there were any unexpected problems during configuration
341 */
Yin-Chia Yeh981e0562015-03-12 13:39:26 -0700342 public boolean configureOutputsChecked(List<OutputConfiguration> outputs)
343 throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700344 // Treat a null input the same an empty list
345 if (outputs == null) {
Yin-Chia Yeh981e0562015-03-12 13:39:26 -0700346 outputs = new ArrayList<OutputConfiguration>();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700347 }
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700348 boolean success = false;
349
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700350 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700351 checkIfCameraClosedOrInError();
Yin-Chia Yeh981e0562015-03-12 13:39:26 -0700352 // Streams to create
353 HashSet<OutputConfiguration> addSet = new HashSet<OutputConfiguration>(outputs);
354 // Streams to delete
355 List<Integer> deleteList = new ArrayList<Integer>();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700356
357 // Determine which streams need to be created, which to be deleted
358 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
359 int streamId = mConfiguredOutputs.keyAt(i);
Yin-Chia Yeh981e0562015-03-12 13:39:26 -0700360 OutputConfiguration outConfig = mConfiguredOutputs.valueAt(i);
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700361
Yin-Chia Yeh981e0562015-03-12 13:39:26 -0700362 if (!outputs.contains(outConfig)) {
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700363 deleteList.add(streamId);
364 } else {
Yin-Chia Yeh981e0562015-03-12 13:39:26 -0700365 addSet.remove(outConfig); // Don't create a stream previously created
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700366 }
367 }
368
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700369 mDeviceHandler.post(mCallOnBusy);
370 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700371
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700372 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700373 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700374
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700375 mRemoteDevice.beginConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700376 // Delete all streams first (to free up HW resources)
377 for (Integer streamId : deleteList) {
378 mRemoteDevice.deleteStream(streamId);
379 mConfiguredOutputs.delete(streamId);
380 }
381
382 // Add all new streams
Yin-Chia Yeh981e0562015-03-12 13:39:26 -0700383 for (OutputConfiguration outConfig : outputs) {
384 if (addSet.contains(outConfig)) {
385 int streamId = mRemoteDevice.createStream(outConfig);
386 mConfiguredOutputs.put(streamId, outConfig);
387 }
Igor Murashkin70725502013-06-25 20:27:06 +0000388 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700389
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700390 try {
391 mRemoteDevice.endConfigure();
392 }
393 catch (IllegalArgumentException e) {
394 // OK. camera service can reject stream config if it's not supported by HAL
395 // This is only the result of a programmer misusing the camera2 api.
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700396 Log.w(TAG, "Stream configuration failed");
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700397 return false;
398 }
399
400 success = true;
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700401 } catch (CameraRuntimeException e) {
402 if (e.getReason() == CAMERA_IN_USE) {
403 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700404 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700405 }
406
407 throw e.asChecked();
408 } catch (RemoteException e) {
409 // impossible
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700410 return false;
411 } finally {
412 if (success && outputs.size() > 0) {
413 mDeviceHandler.post(mCallOnIdle);
414 } else {
415 // Always return to the 'unconfigured' state if we didn't hit a fatal error
416 mDeviceHandler.post(mCallOnUnconfigured);
417 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700418 }
Igor Murashkin70725502013-06-25 20:27:06 +0000419 }
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700420
421 return success;
Igor Murashkin70725502013-06-25 20:27:06 +0000422 }
423
424 @Override
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700425 public void createCaptureSession(List<Surface> outputs,
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700426 CameraCaptureSession.StateCallback callback, Handler handler)
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700427 throws CameraAccessException {
Yin-Chia Yeh35286a22015-03-09 16:53:14 -0700428 List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
429 for (Surface surface : outputs) {
430 outConfigurations.add(new OutputConfiguration(surface));
431 }
432 createCaptureSessionByOutputConfiguration(outConfigurations, callback, handler);
433 }
434
435 @Override
436 public void createCaptureSessionByOutputConfiguration(
437 List<OutputConfiguration> outputConfigurations,
438 CameraCaptureSession.StateCallback callback, Handler handler)
439 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700440 synchronized(mInterfaceLock) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700441 if (DEBUG) {
442 Log.d(TAG, "createCaptureSession");
443 }
444
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700445 checkIfCameraClosedOrInError();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700446
Eino-Ville Talvalad3b85f62014-08-05 15:02:31 -0700447 // Notify current session that it's going away, before starting camera operations
448 // After this call completes, the session is not allowed to call into CameraDeviceImpl
449 if (mCurrentSession != null) {
450 mCurrentSession.replaceSessionClose();
451 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700452
453 // TODO: dont block for this
454 boolean configureSuccess = true;
455 CameraAccessException pendingException = null;
456 try {
Yin-Chia Yeh981e0562015-03-12 13:39:26 -0700457 // configure outputs and then block until IDLE
458 configureSuccess = configureOutputsChecked(outputConfigurations);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700459 } catch (CameraAccessException e) {
460 configureSuccess = false;
461 pendingException = e;
Igor Murashkine1442202014-06-09 17:51:24 -0700462 if (DEBUG) {
463 Log.v(TAG, "createCaptureSession - failed with exception ", e);
464 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700465 }
466
Yin-Chia Yeh981e0562015-03-12 13:39:26 -0700467 List<Surface> outSurfaces = new ArrayList<>(outputConfigurations.size());
468 for (OutputConfiguration config : outputConfigurations) {
469 outSurfaces.add(config.getSurface());
470 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700471 // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
472 CameraCaptureSessionImpl newSession =
Eino-Ville Talvala95037852014-09-14 14:07:05 -0700473 new CameraCaptureSessionImpl(mNextSessionId++,
Yin-Chia Yeh35286a22015-03-09 16:53:14 -0700474 outSurfaces, callback, handler, this, mDeviceHandler,
Igor Murashkin0b27d342014-05-30 09:45:05 -0700475 configureSuccess);
476
Igor Murashkin0b27d342014-05-30 09:45:05 -0700477 // TODO: wait until current session closes, then create the new session
478 mCurrentSession = newSession;
479
480 if (pendingException != null) {
481 throw pendingException;
482 }
483
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700484 mSessionStateCallback = mCurrentSession.getDeviceStateCallback();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700485 }
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700486 }
487
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700488 /**
489 * For use by backwards-compatibility code only.
490 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700491 public void setSessionListener(StateCallbackKK sessionCallback) {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700492 synchronized(mInterfaceLock) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700493 mSessionStateCallback = sessionCallback;
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700494 }
495 }
496
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700497 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700498 public CaptureRequest.Builder createCaptureRequest(int templateType)
499 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700500 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700501 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000502
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700503 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000504
505 try {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700506 mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000507 } catch (CameraRuntimeException e) {
508 throw e.asChecked();
509 } catch (RemoteException e) {
510 // impossible
511 return null;
512 }
513
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700514 CaptureRequest.Builder builder =
515 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000516
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700517 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000518 }
519 }
520
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700521 public int capture(CaptureRequest request, CaptureCallback callback, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000522 throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700523 if (DEBUG) {
524 Log.d(TAG, "calling capture");
525 }
526 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
527 requestList.add(request);
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700528 return submitCaptureRequest(requestList, callback, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000529 }
530
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700531 public int captureBurst(List<CaptureRequest> requests, CaptureCallback callback,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700532 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700533 if (requests == null || requests.isEmpty()) {
534 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700535 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700536 return submitCaptureRequest(requests, callback, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000537 }
538
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700539 /**
540 * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
541 * starting and stopping repeating request and flushing.
542 *
543 * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700544 * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700545 * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
546 * is added to the list mFrameNumberRequestPairs.</p>
547 *
548 * @param requestId the request ID of the current repeating request.
549 *
550 * @param lastFrameNumber last frame number returned from binder.
551 */
552 private void checkEarlyTriggerSequenceComplete(
553 final int requestId, final long lastFrameNumber) {
554 // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700555 // was never sent to HAL. Should trigger onCaptureSequenceAborted immediately.
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700556 if (lastFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
557 final CaptureCallbackHolder holder;
558 int index = mCaptureCallbackMap.indexOfKey(requestId);
559 holder = (index >= 0) ? mCaptureCallbackMap.valueAt(index) : null;
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700560 if (holder != null) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700561 mCaptureCallbackMap.removeAt(index);
Jianing Weibaf0c652014-04-18 17:35:00 -0700562 if (DEBUG) {
563 Log.v(TAG, String.format(
564 "remove holder for requestId %d, "
565 + "because lastFrame is %d.",
566 requestId, lastFrameNumber));
567 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700568 }
569
570 if (holder != null) {
571 if (DEBUG) {
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700572 Log.v(TAG, "immediately trigger onCaptureSequenceAborted because"
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700573 + " request did not reach HAL");
574 }
575
576 Runnable resultDispatch = new Runnable() {
577 @Override
578 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700579 if (!CameraDeviceImpl.this.isClosed()) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700580 if (DEBUG) {
581 Log.d(TAG, String.format(
582 "early trigger sequence complete for request %d",
583 requestId));
584 }
585 if (lastFrameNumber < Integer.MIN_VALUE
586 || lastFrameNumber > Integer.MAX_VALUE) {
587 throw new AssertionError(lastFrameNumber + " cannot be cast to int");
588 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700589 holder.getCallback().onCaptureSequenceAborted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700590 CameraDeviceImpl.this,
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700591 requestId);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700592 }
593 }
594 };
595 holder.getHandler().post(resultDispatch);
596 } else {
597 Log.w(TAG, String.format(
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700598 "did not register callback to request %d",
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700599 requestId));
600 }
601 } else {
602 mFrameNumberRequestPairs.add(
603 new SimpleEntry<Long, Integer>(lastFrameNumber,
604 requestId));
Eino-Ville Talvala848fe732014-09-15 16:24:08 -0700605 // It is possible that the last frame has already arrived, so we need to check
606 // for sequence completion right away
607 checkAndFireSequenceComplete();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700608 }
609 }
610
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700611 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700612 Handler handler, boolean repeating) throws CameraAccessException {
613
614 // Need a valid handler, or current thread needs to have a looper, if
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700615 // callback is valid
616 handler = checkHandler(handler, callback);
Igor Murashkin70725502013-06-25 20:27:06 +0000617
Ruben Brunk7f2372b2014-07-02 11:05:08 -0700618 // Make sure that there all requests have at least 1 surface; all surfaces are non-null
619 for (CaptureRequest request : requestList) {
620 if (request.getTargets().isEmpty()) {
621 throw new IllegalArgumentException(
622 "Each request must have at least one Surface target");
623 }
624
625 for (Surface surface : request.getTargets()) {
626 if (surface == null) {
627 throw new IllegalArgumentException("Null Surface targets are not allowed");
628 }
629 }
630 }
631
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700632 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700633 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000634 int requestId;
635
Ruben Brunke73b41b2013-11-07 19:30:43 -0800636 if (repeating) {
637 stopRepeating();
638 }
639
Jianing Weid2c3a822014-03-27 18:27:43 -0700640 LongParcelable lastFrameNumberRef = new LongParcelable();
Igor Murashkin70725502013-06-25 20:27:06 +0000641 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700642 requestId = mRemoteDevice.submitRequestList(requestList, repeating,
643 /*out*/lastFrameNumberRef);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700644 if (DEBUG) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700645 Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
646 }
Igor Murashkin70725502013-06-25 20:27:06 +0000647 } catch (CameraRuntimeException e) {
648 throw e.asChecked();
649 } catch (RemoteException e) {
650 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700651 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000652 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700653
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700654 if (callback != null) {
655 mCaptureCallbackMap.put(requestId, new CaptureCallbackHolder(callback,
Jianing Weid2c3a822014-03-27 18:27:43 -0700656 requestList, handler, repeating));
Jianing Weibaf0c652014-04-18 17:35:00 -0700657 } else {
658 if (DEBUG) {
659 Log.d(TAG, "Listen for request " + requestId + " is null");
660 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700661 }
Igor Murashkin70725502013-06-25 20:27:06 +0000662
Jianing Weid2c3a822014-03-27 18:27:43 -0700663 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700664
Igor Murashkin70725502013-06-25 20:27:06 +0000665 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700666 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700667 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700668 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700669 mRepeatingRequestId = requestId;
Jianing Weid2c3a822014-03-27 18:27:43 -0700670 } else {
671 mFrameNumberRequestPairs.add(
672 new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
Igor Murashkin70725502013-06-25 20:27:06 +0000673 }
674
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700675 if (mIdle) {
676 mDeviceHandler.post(mCallOnActive);
677 }
678 mIdle = false;
679
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700680 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000681 }
682 }
683
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700684 public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700685 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700686 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
687 requestList.add(request);
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700688 return submitCaptureRequest(requestList, callback, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000689 }
690
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700691 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureCallback callback,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700692 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700693 if (requests == null || requests.isEmpty()) {
694 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700695 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700696 return submitCaptureRequest(requests, callback, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000697 }
698
Igor Murashkin70725502013-06-25 20:27:06 +0000699 public void stopRepeating() throws CameraAccessException {
700
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700701 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700702 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700703 if (mRepeatingRequestId != REQUEST_ID_NONE) {
704
705 int requestId = mRepeatingRequestId;
706 mRepeatingRequestId = REQUEST_ID_NONE;
707
708 // Queue for deletion after in-flight requests finish
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700709 if (mCaptureCallbackMap.get(requestId) != null) {
Zhijun He1a9b6462014-03-31 16:11:33 -0700710 mRepeatingRequestIdDeletedList.add(requestId);
711 }
Igor Murashkin70725502013-06-25 20:27:06 +0000712
713 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700714 LongParcelable lastFrameNumberRef = new LongParcelable();
715 mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
716 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700717
718 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
719
Igor Murashkin70725502013-06-25 20:27:06 +0000720 } catch (CameraRuntimeException e) {
721 throw e.asChecked();
722 } catch (RemoteException e) {
723 // impossible
724 return;
725 }
726 }
727 }
728 }
729
Zhijun Hed842fcd2013-12-26 14:14:04 -0800730 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700731
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700732 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700733 checkIfCameraClosedOrInError();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700734
Ruben Brunkdecfe952013-10-29 11:00:32 -0700735 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700736 throw new IllegalStateException("Active repeating request ongoing");
737 }
Zhijun He7f4d3142013-07-23 07:54:38 -0700738 try {
739 mRemoteDevice.waitUntilIdle();
740 } catch (CameraRuntimeException e) {
741 throw e.asChecked();
742 } catch (RemoteException e) {
743 // impossible
744 return;
745 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700746 }
Igor Murashkin70725502013-06-25 20:27:06 +0000747 }
748
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700749 public void flush() throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700750 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700751 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700752
753 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvalac346bbf2014-08-27 17:05:29 -0700754
755 // If already idle, just do a busy->idle transition immediately, don't actually
756 // flush.
757 if (mIdle) {
758 mDeviceHandler.post(mCallOnIdle);
759 return;
760 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700761 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700762 LongParcelable lastFrameNumberRef = new LongParcelable();
763 mRemoteDevice.flush(/*out*/lastFrameNumberRef);
764 if (mRepeatingRequestId != REQUEST_ID_NONE) {
765 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700766 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700767 mRepeatingRequestId = REQUEST_ID_NONE;
768 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700769 } catch (CameraRuntimeException e) {
770 throw e.asChecked();
771 } catch (RemoteException e) {
772 // impossible
773 return;
774 }
775 }
776 }
777
778 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700779 public void close() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700780 synchronized (mInterfaceLock) {
Igor Murashkin70725502013-06-25 20:27:06 +0000781 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700782 if (mRemoteDevice != null) {
783 mRemoteDevice.disconnect();
784 }
Igor Murashkin70725502013-06-25 20:27:06 +0000785 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700786 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000787 } catch (RemoteException e) {
788 // impossible
789 }
790
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700791 // Only want to fire the onClosed callback once;
792 // either a normal close where the remote device is valid
793 // or a close after a startup error (no remote device but in error state)
794 if (mRemoteDevice != null || mInError) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700795 mDeviceHandler.post(mCallOnClosed);
796 }
Igor Murashkin70725502013-06-25 20:27:06 +0000797
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700798 mRemoteDevice = null;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700799 mInError = false;
Igor Murashkin70725502013-06-25 20:27:06 +0000800 }
801 }
802
803 @Override
804 protected void finalize() throws Throwable {
805 try {
806 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000807 }
808 finally {
809 super.finalize();
810 }
811 }
812
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700813 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700814 * <p>A callback for tracking the progress of a {@link CaptureRequest}
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700815 * submitted to the camera device.</p>
816 *
817 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700818 public static abstract class CaptureCallback {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700819
820 /**
821 * This constant is used to indicate that no images were captured for
822 * the request.
823 *
824 * @hide
825 */
826 public static final int NO_FRAMES_CAPTURED = -1;
827
828 /**
829 * This method is called when the camera device has started capturing
830 * the output image for the request, at the beginning of image exposure.
831 *
832 * @see android.media.MediaActionSound
833 */
834 public void onCaptureStarted(CameraDevice camera,
Eino-Ville Talvalae8df3092014-09-08 14:30:50 -0700835 CaptureRequest request, long timestamp, long frameNumber) {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700836 // default empty implementation
837 }
838
839 /**
840 * This method is called when some results from an image capture are
841 * available.
842 *
843 * @hide
844 */
845 public void onCapturePartial(CameraDevice camera,
846 CaptureRequest request, CaptureResult result) {
847 // default empty implementation
848 }
849
850 /**
851 * This method is called when an image capture makes partial forward progress; some
852 * (but not all) results from an image capture are available.
853 *
854 */
855 public void onCaptureProgressed(CameraDevice camera,
856 CaptureRequest request, CaptureResult partialResult) {
857 // default empty implementation
858 }
859
860 /**
861 * This method is called when an image capture has fully completed and all the
862 * result metadata is available.
863 */
864 public void onCaptureCompleted(CameraDevice camera,
865 CaptureRequest request, TotalCaptureResult result) {
866 // default empty implementation
867 }
868
869 /**
870 * This method is called instead of {@link #onCaptureCompleted} when the
871 * camera device failed to produce a {@link CaptureResult} for the
872 * request.
873 */
874 public void onCaptureFailed(CameraDevice camera,
875 CaptureRequest request, CaptureFailure failure) {
876 // default empty implementation
877 }
878
879 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700880 * This method is called independently of the others in CaptureCallback,
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700881 * when a capture sequence finishes and all {@link CaptureResult}
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700882 * or {@link CaptureFailure} for it have been returned via this callback.
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700883 */
884 public void onCaptureSequenceCompleted(CameraDevice camera,
885 int sequenceId, long frameNumber) {
886 // default empty implementation
887 }
888
889 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700890 * This method is called independently of the others in CaptureCallback,
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700891 * when a capture sequence aborts before any {@link CaptureResult}
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700892 * or {@link CaptureFailure} for it have been returned via this callback.
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700893 */
894 public void onCaptureSequenceAborted(CameraDevice camera,
895 int sequenceId) {
896 // default empty implementation
897 }
898 }
899
900 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700901 * A callback for notifications about the state of a camera device, adding in the callbacks that
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700902 * were part of the earlier KK API design, but now only used internally.
903 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700904 public static abstract class StateCallbackKK extends StateCallback {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700905 /**
906 * The method called when a camera device has no outputs configured.
907 *
908 */
909 public void onUnconfigured(CameraDevice camera) {
910 // Default empty implementation
911 }
912
913 /**
914 * The method called when a camera device begins processing
915 * {@link CaptureRequest capture requests}.
916 *
917 */
918 public void onActive(CameraDevice camera) {
919 // Default empty implementation
920 }
921
922 /**
923 * The method called when a camera device is busy.
924 *
925 */
926 public void onBusy(CameraDevice camera) {
927 // Default empty implementation
928 }
929
930 /**
931 * The method called when a camera device has finished processing all
932 * submitted capture requests and has reached an idle state.
933 *
934 */
935 public void onIdle(CameraDevice camera) {
936 // Default empty implementation
937 }
938 }
939
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700940 static class CaptureCallbackHolder {
Igor Murashkin70725502013-06-25 20:27:06 +0000941
942 private final boolean mRepeating;
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700943 private final CaptureCallback mCallback;
Jianing Weid2c3a822014-03-27 18:27:43 -0700944 private final List<CaptureRequest> mRequestList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700945 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000946
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700947 CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList,
Jianing Weid2c3a822014-03-27 18:27:43 -0700948 Handler handler, boolean repeating) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700949 if (callback == null || handler == null) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700950 throw new UnsupportedOperationException(
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700951 "Must have a valid handler and a valid callback");
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700952 }
Igor Murashkin70725502013-06-25 20:27:06 +0000953 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700954 mHandler = handler;
Jianing Weid2c3a822014-03-27 18:27:43 -0700955 mRequestList = new ArrayList<CaptureRequest>(requestList);
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700956 mCallback = callback;
Igor Murashkin70725502013-06-25 20:27:06 +0000957 }
958
959 public boolean isRepeating() {
960 return mRepeating;
961 }
962
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700963 public CaptureCallback getCallback() {
964 return mCallback;
Igor Murashkin70725502013-06-25 20:27:06 +0000965 }
966
Jianing Weid2c3a822014-03-27 18:27:43 -0700967 public CaptureRequest getRequest(int subsequenceId) {
968 if (subsequenceId >= mRequestList.size()) {
969 throw new IllegalArgumentException(
970 String.format(
971 "Requested subsequenceId %d is larger than request list size %d.",
972 subsequenceId, mRequestList.size()));
973 } else {
974 if (subsequenceId < 0) {
975 throw new IllegalArgumentException(String.format(
976 "Requested subsequenceId %d is negative", subsequenceId));
977 } else {
978 return mRequestList.get(subsequenceId);
979 }
980 }
981 }
982
Igor Murashkin70725502013-06-25 20:27:06 +0000983 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700984 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +0000985 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700986
987 public Handler getHandler() {
988 return mHandler;
989 }
990
Igor Murashkin70725502013-06-25 20:27:06 +0000991 }
992
Jianing Weid2c3a822014-03-27 18:27:43 -0700993 /**
994 * This class tracks the last frame number for submitted requests.
995 */
996 public class FrameNumberTracker {
997
998 private long mCompletedFrameNumber = -1;
999 private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
Igor Murashkin1e854c52014-08-28 15:21:49 -07001000 /** Map frame numbers to list of partial results */
1001 private final HashMap<Long, List<CaptureResult>> mPartialResults = new HashMap<>();
Jianing Weid2c3a822014-03-27 18:27:43 -07001002
1003 private void update() {
1004 Iterator<Long> iter = mFutureErrorSet.iterator();
1005 while (iter.hasNext()) {
1006 long errorFrameNumber = iter.next();
1007 if (errorFrameNumber == mCompletedFrameNumber + 1) {
1008 mCompletedFrameNumber++;
1009 iter.remove();
1010 } else {
1011 break;
1012 }
1013 }
1014 }
1015
1016 /**
1017 * This function is called every time when a result or an error is received.
Igor Murashkin1e854c52014-08-28 15:21:49 -07001018 * @param frameNumber the frame number corresponding to the result or error
1019 * @param isError true if it is an error, false if it is not an error
Jianing Weid2c3a822014-03-27 18:27:43 -07001020 */
1021 public void updateTracker(long frameNumber, boolean isError) {
1022 if (isError) {
1023 mFutureErrorSet.add(frameNumber);
1024 } else {
1025 /**
1026 * HAL cannot send an OnResultReceived for frame N unless it knows for
1027 * sure that all frames prior to N have either errored out or completed.
1028 * So if the current frame is not an error, then all previous frames
1029 * should have arrived. The following line checks whether this holds.
1030 */
1031 if (frameNumber != mCompletedFrameNumber + 1) {
Zhijun He22589b42014-05-01 10:37:36 -07001032 Log.e(TAG, String.format(
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001033 "result frame number %d comes out of order, should be %d + 1",
1034 frameNumber, mCompletedFrameNumber));
Eino-Ville Talvala95037852014-09-14 14:07:05 -07001035 // Continue on to set the completed frame number to this frame anyway,
1036 // to be robust to lower-level errors and allow for clean shutdowns.
Jianing Weid2c3a822014-03-27 18:27:43 -07001037 }
Eino-Ville Talvala95037852014-09-14 14:07:05 -07001038 mCompletedFrameNumber = frameNumber;
Jianing Weid2c3a822014-03-27 18:27:43 -07001039 }
1040 update();
1041 }
1042
Igor Murashkin1e854c52014-08-28 15:21:49 -07001043 /**
1044 * This function is called every time a result has been completed.
1045 *
1046 * <p>It keeps a track of all the partial results already created for a particular
1047 * frame number.</p>
1048 *
1049 * @param frameNumber the frame number corresponding to the result
1050 * @param result the total or partial result
1051 * @param partial {@true} if the result is partial, {@code false} if total
1052 */
1053 public void updateTracker(long frameNumber, CaptureResult result, boolean partial) {
1054
1055 if (!partial) {
1056 // Update the total result's frame status as being successful
1057 updateTracker(frameNumber, /*isError*/false);
1058 // Don't keep a list of total results, we don't need to track them
1059 return;
1060 }
1061
1062 if (result == null) {
1063 // Do not record blank results; this also means there will be no total result
1064 // so it doesn't matter that the partials were not recorded
1065 return;
1066 }
1067
1068 // Partial results must be aggregated in-order for that frame number
1069 List<CaptureResult> partials = mPartialResults.get(frameNumber);
1070 if (partials == null) {
1071 partials = new ArrayList<>();
1072 mPartialResults.put(frameNumber, partials);
1073 }
1074
1075 partials.add(result);
1076 }
1077
1078 /**
1079 * Attempt to pop off all of the partial results seen so far for the {@code frameNumber}.
1080 *
1081 * <p>Once popped-off, the partial results are forgotten (unless {@code updateTracker}
1082 * is called again with new partials for that frame number).</p>
1083 *
1084 * @param frameNumber the frame number corresponding to the result
1085 * @return a list of partial results for that frame with at least 1 element,
1086 * or {@code null} if there were no partials recorded for that frame
1087 */
1088 public List<CaptureResult> popPartialResults(long frameNumber) {
1089 return mPartialResults.remove(frameNumber);
1090 }
1091
Jianing Weid2c3a822014-03-27 18:27:43 -07001092 public long getCompletedFrameNumber() {
1093 return mCompletedFrameNumber;
1094 }
1095
1096 }
1097
1098 private void checkAndFireSequenceComplete() {
1099 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
1100 Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
1101 while (iter.hasNext()) {
1102 final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
1103 if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
1104
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001105 // remove request from mCaptureCallbackMap
Jianing Weid2c3a822014-03-27 18:27:43 -07001106 final int requestId = frameNumberRequestPair.getValue();
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001107 final CaptureCallbackHolder holder;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001108 synchronized(mInterfaceLock) {
1109 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001110 Log.w(TAG, "Camera closed while checking sequences");
1111 return;
1112 }
1113
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001114 int index = mCaptureCallbackMap.indexOfKey(requestId);
1115 holder = (index >= 0) ? mCaptureCallbackMap.valueAt(index)
Jianing Weid2c3a822014-03-27 18:27:43 -07001116 : null;
1117 if (holder != null) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001118 mCaptureCallbackMap.removeAt(index);
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001119 if (DEBUG) {
1120 Log.v(TAG, String.format(
1121 "remove holder for requestId %d, "
1122 + "because lastFrame %d is <= %d",
1123 requestId, frameNumberRequestPair.getKey(),
1124 completedFrameNumber));
1125 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001126 }
1127 }
1128 iter.remove();
1129
1130 // Call onCaptureSequenceCompleted
1131 if (holder != null) {
1132 Runnable resultDispatch = new Runnable() {
1133 @Override
1134 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001135 if (!CameraDeviceImpl.this.isClosed()){
Jianing Weid2c3a822014-03-27 18:27:43 -07001136 if (DEBUG) {
1137 Log.d(TAG, String.format(
1138 "fire sequence complete for request %d",
1139 requestId));
1140 }
1141
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001142 long lastFrameNumber = frameNumberRequestPair.getKey();
1143 if (lastFrameNumber < Integer.MIN_VALUE
1144 || lastFrameNumber > Integer.MAX_VALUE) {
1145 throw new AssertionError(lastFrameNumber
1146 + " cannot be cast to int");
1147 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001148 holder.getCallback().onCaptureSequenceCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -07001149 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -07001150 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -07001151 lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -07001152 }
1153 }
1154 };
1155 holder.getHandler().post(resultDispatch);
1156 }
1157
1158 }
1159 }
1160 }
1161
Zhijun Heecb323e2013-07-31 09:40:27 -07001162 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001163 //
1164 // Constants below need to be kept up-to-date with
1165 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
1166 //
1167
1168 //
1169 // Error codes for onCameraError
1170 //
1171
1172 /**
1173 * Camera has been disconnected
1174 */
Ruben Brunke663cb772014-09-16 13:18:31 -07001175 public static final int ERROR_CAMERA_DISCONNECTED = 0;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001176 /**
1177 * Camera has encountered a device-level error
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001178 * Matches CameraDevice.StateCallback#ERROR_CAMERA_DEVICE
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001179 */
Ruben Brunke663cb772014-09-16 13:18:31 -07001180 public static final int ERROR_CAMERA_DEVICE = 1;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001181 /**
1182 * Camera has encountered a service-level error
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001183 * Matches CameraDevice.StateCallback#ERROR_CAMERA_SERVICE
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001184 */
Ruben Brunke663cb772014-09-16 13:18:31 -07001185 public static final int ERROR_CAMERA_SERVICE = 2;
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001186 /**
1187 * Camera has encountered an error processing a single request.
1188 */
Ruben Brunke663cb772014-09-16 13:18:31 -07001189 public static final int ERROR_CAMERA_REQUEST = 3;
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001190 /**
1191 * Camera has encountered an error producing metadata for a single capture
1192 */
Ruben Brunke663cb772014-09-16 13:18:31 -07001193 public static final int ERROR_CAMERA_RESULT = 4;
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001194 /**
1195 * Camera has encountered an error producing an image buffer for a single capture
1196 */
Ruben Brunke663cb772014-09-16 13:18:31 -07001197 public static final int ERROR_CAMERA_BUFFER = 5;
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001198
Igor Murashkin70725502013-06-25 20:27:06 +00001199 @Override
1200 public IBinder asBinder() {
1201 return this;
1202 }
1203
Igor Murashkin70725502013-06-25 20:27:06 +00001204 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001205 public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) {
1206 if (DEBUG) {
1207 Log.d(TAG, String.format(
Ruben Brunke663cb772014-09-16 13:18:31 -07001208 "Device error received, code %d, frame number %d, request ID %d, subseq ID %d",
1209 errorCode, resultExtras.getFrameNumber(), resultExtras.getRequestId(),
1210 resultExtras.getSubsequenceId()));
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001211 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001212
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001213 synchronized(mInterfaceLock) {
1214 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001215 return; // Camera already closed
1216 }
1217
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001218 switch (errorCode) {
1219 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001220 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnDisconnected);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001221 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001222 default:
1223 Log.e(TAG, "Unknown error from camera device: " + errorCode);
1224 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001225 case ERROR_CAMERA_DEVICE:
1226 case ERROR_CAMERA_SERVICE:
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001227 mInError = true;
1228 Runnable r = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -07001229 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001230 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001231 if (!CameraDeviceImpl.this.isClosed()) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001232 mDeviceCallback.onError(CameraDeviceImpl.this, errorCode);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001233 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001234 }
1235 };
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001236 CameraDeviceImpl.this.mDeviceHandler.post(r);
1237 break;
1238 case ERROR_CAMERA_REQUEST:
1239 case ERROR_CAMERA_RESULT:
1240 case ERROR_CAMERA_BUFFER:
1241 onCaptureErrorLocked(errorCode, resultExtras);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001242 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001243 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001244 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001245 }
1246
1247 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001248 public void onDeviceIdle() {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001249 if (DEBUG) {
1250 Log.d(TAG, "Camera now idle");
1251 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001252 synchronized(mInterfaceLock) {
1253 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07001254
Igor Murashkin21547d62014-06-04 15:21:42 -07001255 if (!CameraDeviceImpl.this.mIdle) {
1256 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnIdle);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001257 }
Igor Murashkin21547d62014-06-04 15:21:42 -07001258 CameraDeviceImpl.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001259 }
1260 }
1261
1262 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001263 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
1264 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae8df3092014-09-08 14:30:50 -07001265 final long frameNumber = resultExtras.getFrameNumber();
1266
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001267 if (DEBUG) {
Eino-Ville Talvalae8df3092014-09-08 14:30:50 -07001268 Log.d(TAG, "Capture started for id " + requestId + " frame number " + frameNumber);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001269 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001270 final CaptureCallbackHolder holder;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001271
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001272 synchronized(mInterfaceLock) {
1273 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07001274
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001275 // Get the callback for this frame ID, if there is one
1276 holder = CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001277
Igor Murashkin49b2b132014-06-18 19:03:00 -07001278 if (holder == null) {
1279 return;
1280 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001281
Igor Murashkin49b2b132014-06-18 19:03:00 -07001282 if (isClosed()) return;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001283
Igor Murashkin49b2b132014-06-18 19:03:00 -07001284 // Dispatch capture start notice
1285 holder.getHandler().post(
1286 new Runnable() {
1287 @Override
1288 public void run() {
1289 if (!CameraDeviceImpl.this.isClosed()) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001290 holder.getCallback().onCaptureStarted(
Igor Murashkin49b2b132014-06-18 19:03:00 -07001291 CameraDeviceImpl.this,
1292 holder.getRequest(resultExtras.getSubsequenceId()),
Eino-Ville Talvalae8df3092014-09-08 14:30:50 -07001293 timestamp, frameNumber);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001294 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001295 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001296 });
1297
1298 }
Igor Murashkin70725502013-06-25 20:27:06 +00001299 }
1300
1301 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001302 public void onResultReceived(CameraMetadataNative result,
1303 CaptureResultExtras resultExtras) throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -07001304
Jianing Weid2c3a822014-03-27 18:27:43 -07001305 int requestId = resultExtras.getRequestId();
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001306 long frameNumber = resultExtras.getFrameNumber();
1307
Zhijun Heecb323e2013-07-31 09:40:27 -07001308 if (DEBUG) {
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001309 Log.v(TAG, "Received result frame " + frameNumber + " for id "
Jianing Weibaf0c652014-04-18 17:35:00 -07001310 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -07001311 }
Ruben Brunk57493682014-05-27 18:58:08 -07001312
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001313 synchronized(mInterfaceLock) {
1314 if (mRemoteDevice == null) return; // Camera already closed
Ruben Brunk57493682014-05-27 18:58:08 -07001315
Igor Murashkin49b2b132014-06-18 19:03:00 -07001316 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
1317 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
1318 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
Ruben Brunk57493682014-05-27 18:58:08 -07001319
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001320 final CaptureCallbackHolder holder =
1321 CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +00001322
Zhijun He83159152014-07-16 11:32:59 -07001323 boolean isPartialResult =
1324 (resultExtras.getPartialResultCount() < mTotalPartialCount);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001325
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001326 // Check if we have a callback for this
Igor Murashkin49b2b132014-06-18 19:03:00 -07001327 if (holder == null) {
1328 if (DEBUG) {
1329 Log.d(TAG,
1330 "holder is null, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001331 + frameNumber);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001332 }
Igor Murashkin1e854c52014-08-28 15:21:49 -07001333
1334 mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult);
1335
Igor Murashkin49b2b132014-06-18 19:03:00 -07001336 return;
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001337 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001338
Igor Murashkin49b2b132014-06-18 19:03:00 -07001339 if (isClosed()) {
1340 if (DEBUG) {
1341 Log.d(TAG,
1342 "camera is closed, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001343 + frameNumber);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001344 }
Igor Murashkin1e854c52014-08-28 15:21:49 -07001345
1346 mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001347 return;
1348 }
Igor Murashkindb075af2014-05-21 10:07:08 -07001349
Igor Murashkin49b2b132014-06-18 19:03:00 -07001350 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
1351
Igor Murashkin49b2b132014-06-18 19:03:00 -07001352 Runnable resultDispatch = null;
1353
Igor Murashkin1e854c52014-08-28 15:21:49 -07001354 CaptureResult finalResult;
1355
Igor Murashkin49b2b132014-06-18 19:03:00 -07001356 // Either send a partial result or the final capture completed result
Zhijun He83159152014-07-16 11:32:59 -07001357 if (isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001358 final CaptureResult resultAsCapture =
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001359 new CaptureResult(result, request, resultExtras);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001360
1361 // Partial result
1362 resultDispatch = new Runnable() {
1363 @Override
1364 public void run() {
1365 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001366 holder.getCallback().onCaptureProgressed(
Igor Murashkin49b2b132014-06-18 19:03:00 -07001367 CameraDeviceImpl.this,
1368 request,
1369 resultAsCapture);
1370 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001371 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001372 };
Igor Murashkin1e854c52014-08-28 15:21:49 -07001373
1374 finalResult = resultAsCapture;
Igor Murashkin49b2b132014-06-18 19:03:00 -07001375 } else {
Igor Murashkin1e854c52014-08-28 15:21:49 -07001376 List<CaptureResult> partialResults =
1377 mFrameNumberTracker.popPartialResults(frameNumber);
1378
Igor Murashkin49b2b132014-06-18 19:03:00 -07001379 final TotalCaptureResult resultAsCapture =
Igor Murashkin1e854c52014-08-28 15:21:49 -07001380 new TotalCaptureResult(result, request, resultExtras, partialResults);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001381
Igor Murashkin49b2b132014-06-18 19:03:00 -07001382 // Final capture result
1383 resultDispatch = new Runnable() {
1384 @Override
1385 public void run() {
1386 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001387 holder.getCallback().onCaptureCompleted(
Igor Murashkin49b2b132014-06-18 19:03:00 -07001388 CameraDeviceImpl.this,
1389 request,
1390 resultAsCapture);
1391 }
1392 }
1393 };
Igor Murashkin1e854c52014-08-28 15:21:49 -07001394
1395 finalResult = resultAsCapture;
Igor Murashkin49b2b132014-06-18 19:03:00 -07001396 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001397
Igor Murashkin49b2b132014-06-18 19:03:00 -07001398 holder.getHandler().post(resultDispatch);
1399
Igor Murashkin1e854c52014-08-28 15:21:49 -07001400 // Collect the partials for a total result; or mark the frame as totally completed
1401 mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult);
1402
Igor Murashkin49b2b132014-06-18 19:03:00 -07001403 // Fire onCaptureSequenceCompleted
Zhijun He83159152014-07-16 11:32:59 -07001404 if (!isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001405 checkAndFireSequenceComplete();
1406 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001407 }
Igor Murashkin70725502013-06-25 20:27:06 +00001408 }
1409
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001410 /**
1411 * Called by onDeviceError for handling single-capture failures.
1412 */
1413 private void onCaptureErrorLocked(int errorCode, CaptureResultExtras resultExtras) {
1414
1415 final int requestId = resultExtras.getRequestId();
1416 final int subsequenceId = resultExtras.getSubsequenceId();
1417 final long frameNumber = resultExtras.getFrameNumber();
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001418 final CaptureCallbackHolder holder =
1419 CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001420
1421 final CaptureRequest request = holder.getRequest(subsequenceId);
1422
1423 // No way to report buffer errors right now
1424 if (errorCode == ERROR_CAMERA_BUFFER) {
1425 Log.e(TAG, String.format("Lost output buffer reported for frame %d", frameNumber));
1426 return;
1427 }
1428
1429 boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
1430
1431 // This is only approximate - exact handling needs the camera service and HAL to
1432 // disambiguate between request failures to due abort and due to real errors.
1433 // For now, assume that if the session believes we're mid-abort, then the error
1434 // is due to abort.
1435 int reason = (mCurrentSession != null && mCurrentSession.isAborting()) ?
1436 CaptureFailure.REASON_FLUSHED :
1437 CaptureFailure.REASON_ERROR;
1438
1439 final CaptureFailure failure = new CaptureFailure(
1440 request,
1441 reason,
1442 /*dropped*/ mayHaveBuffers,
1443 requestId,
1444 frameNumber);
1445
1446 Runnable failureDispatch = new Runnable() {
1447 @Override
1448 public void run() {
1449 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001450 holder.getCallback().onCaptureFailed(
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001451 CameraDeviceImpl.this,
1452 request,
1453 failure);
1454 }
1455 }
1456 };
1457 holder.getHandler().post(failureDispatch);
1458
1459 // Fire onCaptureSequenceCompleted if appropriate
1460 if (DEBUG) {
1461 Log.v(TAG, String.format("got error frame %d", frameNumber));
1462 }
1463 mFrameNumberTracker.updateTracker(frameNumber, /*error*/true);
1464 checkAndFireSequenceComplete();
1465 }
1466
1467 } // public class CameraDeviceCallbacks
Igor Murashkin70725502013-06-25 20:27:06 +00001468
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001469 /**
Igor Murashkin0b27d342014-05-30 09:45:05 -07001470 * Default handler management.
1471 *
1472 * <p>
1473 * If handler is null, get the current thread's
1474 * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
1475 * </p>
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001476 */
Igor Murashkin0b27d342014-05-30 09:45:05 -07001477 static Handler checkHandler(Handler handler) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001478 if (handler == null) {
1479 Looper looper = Looper.myLooper();
1480 if (looper == null) {
1481 throw new IllegalArgumentException(
1482 "No handler given, and current thread has no looper!");
1483 }
1484 handler = new Handler(looper);
1485 }
1486 return handler;
1487 }
1488
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001489 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001490 * Default handler management, conditional on there being a callback.
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001491 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001492 * <p>If the callback isn't null, check the handler, otherwise pass it through.</p>
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001493 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001494 static <T> Handler checkHandler(Handler handler, T callback) {
1495 if (callback != null) {
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001496 return checkHandler(handler);
1497 }
1498 return handler;
1499 }
1500
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001501 private void checkIfCameraClosedOrInError() throws CameraAccessException {
1502 if (mInError) {
1503 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
1504 "The camera device has encountered a serious error");
1505 }
Zhijun He7f4d3142013-07-23 07:54:38 -07001506 if (mRemoteDevice == null) {
1507 throw new IllegalStateException("CameraDevice was already closed");
1508 }
1509 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001510
Igor Murashkin49b2b132014-06-18 19:03:00 -07001511 /** Whether the camera device has started to close (may not yet have finished) */
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001512 private boolean isClosed() {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001513 return mClosing;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001514 }
Ruben Brunk57493682014-05-27 18:58:08 -07001515
1516 private CameraCharacteristics getCharacteristics() {
1517 return mCharacteristics;
1518 }
Igor Murashkin70725502013-06-25 20:27:06 +00001519}