blob: 1dc5533aa288f02f3c8ed61fc878e3ba76c68d57 [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
55 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
64 private final Object mInterfaceLock = new Object();
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
82 private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
Igor Murashkin70725502013-06-25 20:27:06 +000083
84 private final String mCameraId;
Ruben Brunk57493682014-05-27 18:58:08 -070085 private final CameraCharacteristics mCharacteristics;
Zhijun He83159152014-07-16 11:32:59 -070086 private final int mTotalPartialCount;
Igor Murashkin70725502013-06-25 20:27:06 +000087
Jianing Weid2c3a822014-03-27 18:27:43 -070088 /**
89 * A list tracking request and its expected last frame.
90 * Updated when calling ICameraDeviceUser methods.
91 */
92 private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>>
93 mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>();
94
95 /**
96 * An object tracking received frame numbers.
97 * Updated when receiving callbacks from ICameraDeviceCallbacks.
98 */
99 private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
100
Igor Murashkin0b27d342014-05-30 09:45:05 -0700101 private CameraCaptureSessionImpl mCurrentSession;
Eino-Ville Talvala95037852014-09-14 14:07:05 -0700102 private int mNextSessionId = 0;
Igor Murashkin0b27d342014-05-30 09:45:05 -0700103
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700104 // Runnables for all state transitions, except error, which needs the
105 // error code argument
106
107 private final Runnable mCallOnOpened = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700108 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700109 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700110 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700111 synchronized(mInterfaceLock) {
112 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700113
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700114 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700115 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700116 if (sessionCallback != null) {
117 sessionCallback.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700118 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700119 mDeviceCallback.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700120 }
121 };
122
123 private final Runnable mCallOnUnconfigured = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700124 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700125 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700126 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700127 synchronized(mInterfaceLock) {
128 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700129
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700130 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700131 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700132 if (sessionCallback != null) {
133 sessionCallback.onUnconfigured(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700134 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700135 }
136 };
137
138 private final Runnable mCallOnActive = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700139 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700140 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700141 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700142 synchronized(mInterfaceLock) {
143 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700144
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700145 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700146 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700147 if (sessionCallback != null) {
148 sessionCallback.onActive(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700149 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700150 }
151 };
152
153 private final Runnable mCallOnBusy = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700154 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700155 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700156 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700157 synchronized(mInterfaceLock) {
158 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700159
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700160 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700161 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700162 if (sessionCallback != null) {
163 sessionCallback.onBusy(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700164 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700165 }
166 };
167
168 private final Runnable mCallOnClosed = new Runnable() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700169 private boolean mClosedOnce = false;
170
Jianing Weid2c3a822014-03-27 18:27:43 -0700171 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700172 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700173 if (mClosedOnce) {
174 throw new AssertionError("Don't post #onClosed more than once");
175 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700176 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700177 synchronized(mInterfaceLock) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700178 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700179 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700180 if (sessionCallback != null) {
181 sessionCallback.onClosed(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700182 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700183 mDeviceCallback.onClosed(CameraDeviceImpl.this);
Igor Murashkin49b2b132014-06-18 19:03:00 -0700184 mClosedOnce = true;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700185 }
186 };
187
188 private final Runnable mCallOnIdle = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700189 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700190 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700191 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700192 synchronized(mInterfaceLock) {
193 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700194
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700195 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700196 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700197 if (sessionCallback != null) {
198 sessionCallback.onIdle(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700199 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700200 }
201 };
202
203 private final Runnable mCallOnDisconnected = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700204 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700205 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700206 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700207 synchronized(mInterfaceLock) {
208 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700209
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700210 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700211 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700212 if (sessionCallback != null) {
213 sessionCallback.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700214 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700215 mDeviceCallback.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700216 }
217 };
218
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700219 public CameraDeviceImpl(String cameraId, StateCallback callback, Handler handler,
Ruben Brunk57493682014-05-27 18:58:08 -0700220 CameraCharacteristics characteristics) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700221 if (cameraId == null || callback == null || handler == null || characteristics == null) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700222 throw new IllegalArgumentException("Null argument given");
223 }
Igor Murashkin70725502013-06-25 20:27:06 +0000224 mCameraId = cameraId;
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700225 mDeviceCallback = callback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700226 mDeviceHandler = handler;
Ruben Brunk57493682014-05-27 18:58:08 -0700227 mCharacteristics = characteristics;
Eino-Ville Talvalab72d1ef2014-04-28 13:21:18 -0700228
229 final int MAX_TAG_LEN = 23;
230 String tag = String.format("CameraDevice-JV-%s", mCameraId);
231 if (tag.length() > MAX_TAG_LEN) {
232 tag = tag.substring(0, MAX_TAG_LEN);
233 }
234 TAG = tag;
Zhijun Heecb323e2013-07-31 09:40:27 -0700235 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Zhijun He83159152014-07-16 11:32:59 -0700236
237 Integer partialCount =
238 mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
239 if (partialCount == null) {
240 // 1 means partial result is not supported.
241 mTotalPartialCount = 1;
242 } else {
243 mTotalPartialCount = partialCount;
244 }
Igor Murashkin70725502013-06-25 20:27:06 +0000245 }
246
247 public CameraDeviceCallbacks getCallbacks() {
248 return mCallbacks;
249 }
250
Igor Murashkin70725502013-06-25 20:27:06 +0000251 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700252 synchronized(mInterfaceLock) {
253 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700254 // If setRemoteFailure already called, do nothing
255 if (mInError) return;
256
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700257 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
258
259 mDeviceHandler.post(mCallOnOpened);
260 mDeviceHandler.post(mCallOnUnconfigured);
261 }
Igor Murashkin70725502013-06-25 20:27:06 +0000262 }
263
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700264 /**
265 * Call to indicate failed connection to a remote camera device.
266 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700267 * <p>This places the camera device in the error state and informs the callback.
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700268 * Use in place of setRemoteDevice() when startup fails.</p>
269 */
270 public void setRemoteFailure(final CameraRuntimeException failure) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700271 int failureCode = StateCallback.ERROR_CAMERA_DEVICE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700272 boolean failureIsError = true;
273
274 switch (failure.getReason()) {
275 case CameraAccessException.CAMERA_IN_USE:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700276 failureCode = StateCallback.ERROR_CAMERA_IN_USE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700277 break;
278 case CameraAccessException.MAX_CAMERAS_IN_USE:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700279 failureCode = StateCallback.ERROR_MAX_CAMERAS_IN_USE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700280 break;
281 case CameraAccessException.CAMERA_DISABLED:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700282 failureCode = StateCallback.ERROR_CAMERA_DISABLED;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700283 break;
284 case CameraAccessException.CAMERA_DISCONNECTED:
285 failureIsError = false;
286 break;
287 case CameraAccessException.CAMERA_ERROR:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700288 failureCode = StateCallback.ERROR_CAMERA_DEVICE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700289 break;
290 default:
291 Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
292 break;
293 }
294 final int code = failureCode;
295 final boolean isError = failureIsError;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700296 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700297 mInError = true;
298 mDeviceHandler.post(new Runnable() {
Igor Murashkine1442202014-06-09 17:51:24 -0700299 @Override
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700300 public void run() {
301 if (isError) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700302 mDeviceCallback.onError(CameraDeviceImpl.this, code);
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700303 } else {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700304 mDeviceCallback.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700305 }
306 }
307 });
308 }
309 }
310
Igor Murashkin70725502013-06-25 20:27:06 +0000311 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700312 public String getId() {
313 return mCameraId;
314 }
315
Igor Murashkin70725502013-06-25 20:27:06 +0000316 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700317 // Leave this here for backwards compatibility with older code using this directly
318 configureOutputsChecked(outputs);
319 }
320
321 /**
322 * Attempt to configure the outputs; the device goes to idle and then configures the
323 * new outputs if possible.
324 *
325 * <p>The configuration may gracefully fail, if there are too many outputs, if the formats
326 * are not supported, or if the sizes for that format is not supported. In this case this
327 * function will return {@code false} and the unconfigured callback will be fired.</p>
328 *
329 * <p>If the configuration succeeds (with 1 or more outputs), then the idle callback is fired.
330 * Unconfiguring the device always fires the idle callback.</p>
331 *
332 * @param outputs a list of one or more surfaces, or {@code null} to unconfigure
333 * @return whether or not the configuration was successful
334 *
335 * @throws CameraAccessException if there were any unexpected problems during configuration
336 */
337 public boolean configureOutputsChecked(List<Surface> outputs) throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700338 // Treat a null input the same an empty list
339 if (outputs == null) {
340 outputs = new ArrayList<Surface>();
341 }
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700342 boolean success = false;
343
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700344 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700345 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700346
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700347 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
348 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
349
350 // Determine which streams need to be created, which to be deleted
351 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
352 int streamId = mConfiguredOutputs.keyAt(i);
353 Surface s = mConfiguredOutputs.valueAt(i);
354
355 if (!outputs.contains(s)) {
356 deleteList.add(streamId);
357 } else {
358 addSet.remove(s); // Don't create a stream previously created
359 }
360 }
361
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700362 mDeviceHandler.post(mCallOnBusy);
363 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700364
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700365 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700366 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700367
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700368 mRemoteDevice.beginConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700369 // Delete all streams first (to free up HW resources)
370 for (Integer streamId : deleteList) {
371 mRemoteDevice.deleteStream(streamId);
372 mConfiguredOutputs.delete(streamId);
373 }
374
375 // Add all new streams
376 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000377 // TODO: remove width,height,format since we are ignoring
378 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700379 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
380 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000381 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700382
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700383 try {
384 mRemoteDevice.endConfigure();
385 }
386 catch (IllegalArgumentException e) {
387 // OK. camera service can reject stream config if it's not supported by HAL
388 // This is only the result of a programmer misusing the camera2 api.
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700389 Log.w(TAG, "Stream configuration failed");
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700390 return false;
391 }
392
393 success = true;
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700394 } catch (CameraRuntimeException e) {
395 if (e.getReason() == CAMERA_IN_USE) {
396 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700397 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700398 }
399
400 throw e.asChecked();
401 } catch (RemoteException e) {
402 // impossible
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700403 return false;
404 } finally {
405 if (success && outputs.size() > 0) {
406 mDeviceHandler.post(mCallOnIdle);
407 } else {
408 // Always return to the 'unconfigured' state if we didn't hit a fatal error
409 mDeviceHandler.post(mCallOnUnconfigured);
410 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700411 }
Igor Murashkin70725502013-06-25 20:27:06 +0000412 }
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700413
414 return success;
Igor Murashkin70725502013-06-25 20:27:06 +0000415 }
416
417 @Override
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700418 public void createCaptureSession(List<Surface> outputs,
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700419 CameraCaptureSession.StateCallback callback, Handler handler)
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700420 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700421 synchronized(mInterfaceLock) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700422 if (DEBUG) {
423 Log.d(TAG, "createCaptureSession");
424 }
425
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700426 checkIfCameraClosedOrInError();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700427
Eino-Ville Talvalad3b85f62014-08-05 15:02:31 -0700428 // Notify current session that it's going away, before starting camera operations
429 // After this call completes, the session is not allowed to call into CameraDeviceImpl
430 if (mCurrentSession != null) {
431 mCurrentSession.replaceSessionClose();
432 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700433
434 // TODO: dont block for this
435 boolean configureSuccess = true;
436 CameraAccessException pendingException = null;
437 try {
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700438 configureSuccess = configureOutputsChecked(outputs); // and then block until IDLE
Igor Murashkin0b27d342014-05-30 09:45:05 -0700439 } catch (CameraAccessException e) {
440 configureSuccess = false;
441 pendingException = e;
Igor Murashkine1442202014-06-09 17:51:24 -0700442 if (DEBUG) {
443 Log.v(TAG, "createCaptureSession - failed with exception ", e);
444 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700445 }
446
447 // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
448 CameraCaptureSessionImpl newSession =
Eino-Ville Talvala95037852014-09-14 14:07:05 -0700449 new CameraCaptureSessionImpl(mNextSessionId++,
450 outputs, callback, handler, this, mDeviceHandler,
Igor Murashkin0b27d342014-05-30 09:45:05 -0700451 configureSuccess);
452
Igor Murashkin0b27d342014-05-30 09:45:05 -0700453 // TODO: wait until current session closes, then create the new session
454 mCurrentSession = newSession;
455
456 if (pendingException != null) {
457 throw pendingException;
458 }
459
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700460 mSessionStateCallback = mCurrentSession.getDeviceStateCallback();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700461 }
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700462 }
463
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700464 /**
465 * For use by backwards-compatibility code only.
466 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700467 public void setSessionListener(StateCallbackKK sessionCallback) {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700468 synchronized(mInterfaceLock) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700469 mSessionStateCallback = sessionCallback;
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700470 }
471 }
472
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700473 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700474 public CaptureRequest.Builder createCaptureRequest(int templateType)
475 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700476 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700477 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000478
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700479 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000480
481 try {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700482 mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000483 } catch (CameraRuntimeException e) {
484 throw e.asChecked();
485 } catch (RemoteException e) {
486 // impossible
487 return null;
488 }
489
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700490 CaptureRequest.Builder builder =
491 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000492
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700493 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000494 }
495 }
496
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700497 public int capture(CaptureRequest request, CaptureCallback callback, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000498 throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700499 if (DEBUG) {
500 Log.d(TAG, "calling capture");
501 }
502 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
503 requestList.add(request);
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700504 return submitCaptureRequest(requestList, callback, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000505 }
506
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700507 public int captureBurst(List<CaptureRequest> requests, CaptureCallback callback,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700508 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700509 if (requests == null || requests.isEmpty()) {
510 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700511 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700512 return submitCaptureRequest(requests, callback, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000513 }
514
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700515 /**
516 * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
517 * starting and stopping repeating request and flushing.
518 *
519 * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700520 * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700521 * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
522 * is added to the list mFrameNumberRequestPairs.</p>
523 *
524 * @param requestId the request ID of the current repeating request.
525 *
526 * @param lastFrameNumber last frame number returned from binder.
527 */
528 private void checkEarlyTriggerSequenceComplete(
529 final int requestId, final long lastFrameNumber) {
530 // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700531 // was never sent to HAL. Should trigger onCaptureSequenceAborted immediately.
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700532 if (lastFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
533 final CaptureCallbackHolder holder;
534 int index = mCaptureCallbackMap.indexOfKey(requestId);
535 holder = (index >= 0) ? mCaptureCallbackMap.valueAt(index) : null;
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700536 if (holder != null) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700537 mCaptureCallbackMap.removeAt(index);
Jianing Weibaf0c652014-04-18 17:35:00 -0700538 if (DEBUG) {
539 Log.v(TAG, String.format(
540 "remove holder for requestId %d, "
541 + "because lastFrame is %d.",
542 requestId, lastFrameNumber));
543 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700544 }
545
546 if (holder != null) {
547 if (DEBUG) {
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700548 Log.v(TAG, "immediately trigger onCaptureSequenceAborted because"
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700549 + " request did not reach HAL");
550 }
551
552 Runnable resultDispatch = new Runnable() {
553 @Override
554 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700555 if (!CameraDeviceImpl.this.isClosed()) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700556 if (DEBUG) {
557 Log.d(TAG, String.format(
558 "early trigger sequence complete for request %d",
559 requestId));
560 }
561 if (lastFrameNumber < Integer.MIN_VALUE
562 || lastFrameNumber > Integer.MAX_VALUE) {
563 throw new AssertionError(lastFrameNumber + " cannot be cast to int");
564 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700565 holder.getCallback().onCaptureSequenceAborted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700566 CameraDeviceImpl.this,
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700567 requestId);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700568 }
569 }
570 };
571 holder.getHandler().post(resultDispatch);
572 } else {
573 Log.w(TAG, String.format(
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700574 "did not register callback to request %d",
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700575 requestId));
576 }
577 } else {
578 mFrameNumberRequestPairs.add(
579 new SimpleEntry<Long, Integer>(lastFrameNumber,
580 requestId));
Eino-Ville Talvala848fe732014-09-15 16:24:08 -0700581 // It is possible that the last frame has already arrived, so we need to check
582 // for sequence completion right away
583 checkAndFireSequenceComplete();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700584 }
585 }
586
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700587 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700588 Handler handler, boolean repeating) throws CameraAccessException {
589
590 // Need a valid handler, or current thread needs to have a looper, if
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700591 // callback is valid
592 handler = checkHandler(handler, callback);
Igor Murashkin70725502013-06-25 20:27:06 +0000593
Ruben Brunk7f2372b2014-07-02 11:05:08 -0700594 // Make sure that there all requests have at least 1 surface; all surfaces are non-null
595 for (CaptureRequest request : requestList) {
596 if (request.getTargets().isEmpty()) {
597 throw new IllegalArgumentException(
598 "Each request must have at least one Surface target");
599 }
600
601 for (Surface surface : request.getTargets()) {
602 if (surface == null) {
603 throw new IllegalArgumentException("Null Surface targets are not allowed");
604 }
605 }
606 }
607
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700608 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700609 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000610 int requestId;
611
Ruben Brunke73b41b2013-11-07 19:30:43 -0800612 if (repeating) {
613 stopRepeating();
614 }
615
Jianing Weid2c3a822014-03-27 18:27:43 -0700616 LongParcelable lastFrameNumberRef = new LongParcelable();
Igor Murashkin70725502013-06-25 20:27:06 +0000617 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700618 requestId = mRemoteDevice.submitRequestList(requestList, repeating,
619 /*out*/lastFrameNumberRef);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700620 if (DEBUG) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700621 Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
622 }
Igor Murashkin70725502013-06-25 20:27:06 +0000623 } catch (CameraRuntimeException e) {
624 throw e.asChecked();
625 } catch (RemoteException e) {
626 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700627 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000628 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700629
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700630 if (callback != null) {
631 mCaptureCallbackMap.put(requestId, new CaptureCallbackHolder(callback,
Jianing Weid2c3a822014-03-27 18:27:43 -0700632 requestList, handler, repeating));
Jianing Weibaf0c652014-04-18 17:35:00 -0700633 } else {
634 if (DEBUG) {
635 Log.d(TAG, "Listen for request " + requestId + " is null");
636 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700637 }
Igor Murashkin70725502013-06-25 20:27:06 +0000638
Jianing Weid2c3a822014-03-27 18:27:43 -0700639 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700640
Igor Murashkin70725502013-06-25 20:27:06 +0000641 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700642 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700643 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700644 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700645 mRepeatingRequestId = requestId;
Jianing Weid2c3a822014-03-27 18:27:43 -0700646 } else {
647 mFrameNumberRequestPairs.add(
648 new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
Igor Murashkin70725502013-06-25 20:27:06 +0000649 }
650
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700651 if (mIdle) {
652 mDeviceHandler.post(mCallOnActive);
653 }
654 mIdle = false;
655
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700656 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000657 }
658 }
659
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700660 public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700661 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700662 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
663 requestList.add(request);
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700664 return submitCaptureRequest(requestList, callback, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000665 }
666
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700667 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureCallback callback,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700668 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700669 if (requests == null || requests.isEmpty()) {
670 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700671 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700672 return submitCaptureRequest(requests, callback, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000673 }
674
Igor Murashkin70725502013-06-25 20:27:06 +0000675 public void stopRepeating() throws CameraAccessException {
676
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700677 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700678 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700679 if (mRepeatingRequestId != REQUEST_ID_NONE) {
680
681 int requestId = mRepeatingRequestId;
682 mRepeatingRequestId = REQUEST_ID_NONE;
683
684 // Queue for deletion after in-flight requests finish
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700685 if (mCaptureCallbackMap.get(requestId) != null) {
Zhijun He1a9b6462014-03-31 16:11:33 -0700686 mRepeatingRequestIdDeletedList.add(requestId);
687 }
Igor Murashkin70725502013-06-25 20:27:06 +0000688
689 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700690 LongParcelable lastFrameNumberRef = new LongParcelable();
691 mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
692 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700693
694 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
695
Igor Murashkin70725502013-06-25 20:27:06 +0000696 } catch (CameraRuntimeException e) {
697 throw e.asChecked();
698 } catch (RemoteException e) {
699 // impossible
700 return;
701 }
702 }
703 }
704 }
705
Zhijun Hed842fcd2013-12-26 14:14:04 -0800706 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700707
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700708 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700709 checkIfCameraClosedOrInError();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700710
Ruben Brunkdecfe952013-10-29 11:00:32 -0700711 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700712 throw new IllegalStateException("Active repeating request ongoing");
713 }
Zhijun He7f4d3142013-07-23 07:54:38 -0700714 try {
715 mRemoteDevice.waitUntilIdle();
716 } catch (CameraRuntimeException e) {
717 throw e.asChecked();
718 } catch (RemoteException e) {
719 // impossible
720 return;
721 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700722 }
Igor Murashkin70725502013-06-25 20:27:06 +0000723 }
724
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700725 public void flush() throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700726 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700727 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700728
729 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvalac346bbf2014-08-27 17:05:29 -0700730
731 // If already idle, just do a busy->idle transition immediately, don't actually
732 // flush.
733 if (mIdle) {
734 mDeviceHandler.post(mCallOnIdle);
735 return;
736 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700737 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700738 LongParcelable lastFrameNumberRef = new LongParcelable();
739 mRemoteDevice.flush(/*out*/lastFrameNumberRef);
740 if (mRepeatingRequestId != REQUEST_ID_NONE) {
741 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700742 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700743 mRepeatingRequestId = REQUEST_ID_NONE;
744 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700745 } catch (CameraRuntimeException e) {
746 throw e.asChecked();
747 } catch (RemoteException e) {
748 // impossible
749 return;
750 }
751 }
752 }
753
754 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700755 public void close() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700756 synchronized (mInterfaceLock) {
Igor Murashkin70725502013-06-25 20:27:06 +0000757 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700758 if (mRemoteDevice != null) {
759 mRemoteDevice.disconnect();
760 }
Igor Murashkin70725502013-06-25 20:27:06 +0000761 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700762 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000763 } catch (RemoteException e) {
764 // impossible
765 }
766
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700767 // Only want to fire the onClosed callback once;
768 // either a normal close where the remote device is valid
769 // or a close after a startup error (no remote device but in error state)
770 if (mRemoteDevice != null || mInError) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700771 mDeviceHandler.post(mCallOnClosed);
772 }
Igor Murashkin70725502013-06-25 20:27:06 +0000773
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700774 mRemoteDevice = null;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700775 mInError = false;
Igor Murashkin70725502013-06-25 20:27:06 +0000776 }
777 }
778
779 @Override
780 protected void finalize() throws Throwable {
781 try {
782 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000783 }
784 finally {
785 super.finalize();
786 }
787 }
788
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700789 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700790 * <p>A callback for tracking the progress of a {@link CaptureRequest}
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700791 * submitted to the camera device.</p>
792 *
793 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700794 public static abstract class CaptureCallback {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700795
796 /**
797 * This constant is used to indicate that no images were captured for
798 * the request.
799 *
800 * @hide
801 */
802 public static final int NO_FRAMES_CAPTURED = -1;
803
804 /**
805 * This method is called when the camera device has started capturing
806 * the output image for the request, at the beginning of image exposure.
807 *
808 * @see android.media.MediaActionSound
809 */
810 public void onCaptureStarted(CameraDevice camera,
Eino-Ville Talvalae8df3092014-09-08 14:30:50 -0700811 CaptureRequest request, long timestamp, long frameNumber) {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700812 // default empty implementation
813 }
814
815 /**
816 * This method is called when some results from an image capture are
817 * available.
818 *
819 * @hide
820 */
821 public void onCapturePartial(CameraDevice camera,
822 CaptureRequest request, CaptureResult result) {
823 // default empty implementation
824 }
825
826 /**
827 * This method is called when an image capture makes partial forward progress; some
828 * (but not all) results from an image capture are available.
829 *
830 */
831 public void onCaptureProgressed(CameraDevice camera,
832 CaptureRequest request, CaptureResult partialResult) {
833 // default empty implementation
834 }
835
836 /**
837 * This method is called when an image capture has fully completed and all the
838 * result metadata is available.
839 */
840 public void onCaptureCompleted(CameraDevice camera,
841 CaptureRequest request, TotalCaptureResult result) {
842 // default empty implementation
843 }
844
845 /**
846 * This method is called instead of {@link #onCaptureCompleted} when the
847 * camera device failed to produce a {@link CaptureResult} for the
848 * request.
849 */
850 public void onCaptureFailed(CameraDevice camera,
851 CaptureRequest request, CaptureFailure failure) {
852 // default empty implementation
853 }
854
855 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700856 * This method is called independently of the others in CaptureCallback,
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700857 * when a capture sequence finishes and all {@link CaptureResult}
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700858 * or {@link CaptureFailure} for it have been returned via this callback.
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700859 */
860 public void onCaptureSequenceCompleted(CameraDevice camera,
861 int sequenceId, long frameNumber) {
862 // default empty implementation
863 }
864
865 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700866 * This method is called independently of the others in CaptureCallback,
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700867 * when a capture sequence aborts before any {@link CaptureResult}
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700868 * or {@link CaptureFailure} for it have been returned via this callback.
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700869 */
870 public void onCaptureSequenceAborted(CameraDevice camera,
871 int sequenceId) {
872 // default empty implementation
873 }
874 }
875
876 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700877 * A callback for notifications about the state of a camera device, adding in the callbacks that
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700878 * were part of the earlier KK API design, but now only used internally.
879 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700880 public static abstract class StateCallbackKK extends StateCallback {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700881 /**
882 * The method called when a camera device has no outputs configured.
883 *
884 */
885 public void onUnconfigured(CameraDevice camera) {
886 // Default empty implementation
887 }
888
889 /**
890 * The method called when a camera device begins processing
891 * {@link CaptureRequest capture requests}.
892 *
893 */
894 public void onActive(CameraDevice camera) {
895 // Default empty implementation
896 }
897
898 /**
899 * The method called when a camera device is busy.
900 *
901 */
902 public void onBusy(CameraDevice camera) {
903 // Default empty implementation
904 }
905
906 /**
907 * The method called when a camera device has finished processing all
908 * submitted capture requests and has reached an idle state.
909 *
910 */
911 public void onIdle(CameraDevice camera) {
912 // Default empty implementation
913 }
914 }
915
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700916 static class CaptureCallbackHolder {
Igor Murashkin70725502013-06-25 20:27:06 +0000917
918 private final boolean mRepeating;
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700919 private final CaptureCallback mCallback;
Jianing Weid2c3a822014-03-27 18:27:43 -0700920 private final List<CaptureRequest> mRequestList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700921 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000922
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700923 CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList,
Jianing Weid2c3a822014-03-27 18:27:43 -0700924 Handler handler, boolean repeating) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700925 if (callback == null || handler == null) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700926 throw new UnsupportedOperationException(
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700927 "Must have a valid handler and a valid callback");
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700928 }
Igor Murashkin70725502013-06-25 20:27:06 +0000929 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700930 mHandler = handler;
Jianing Weid2c3a822014-03-27 18:27:43 -0700931 mRequestList = new ArrayList<CaptureRequest>(requestList);
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700932 mCallback = callback;
Igor Murashkin70725502013-06-25 20:27:06 +0000933 }
934
935 public boolean isRepeating() {
936 return mRepeating;
937 }
938
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700939 public CaptureCallback getCallback() {
940 return mCallback;
Igor Murashkin70725502013-06-25 20:27:06 +0000941 }
942
Jianing Weid2c3a822014-03-27 18:27:43 -0700943 public CaptureRequest getRequest(int subsequenceId) {
944 if (subsequenceId >= mRequestList.size()) {
945 throw new IllegalArgumentException(
946 String.format(
947 "Requested subsequenceId %d is larger than request list size %d.",
948 subsequenceId, mRequestList.size()));
949 } else {
950 if (subsequenceId < 0) {
951 throw new IllegalArgumentException(String.format(
952 "Requested subsequenceId %d is negative", subsequenceId));
953 } else {
954 return mRequestList.get(subsequenceId);
955 }
956 }
957 }
958
Igor Murashkin70725502013-06-25 20:27:06 +0000959 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700960 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +0000961 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700962
963 public Handler getHandler() {
964 return mHandler;
965 }
966
Igor Murashkin70725502013-06-25 20:27:06 +0000967 }
968
Jianing Weid2c3a822014-03-27 18:27:43 -0700969 /**
970 * This class tracks the last frame number for submitted requests.
971 */
972 public class FrameNumberTracker {
973
974 private long mCompletedFrameNumber = -1;
975 private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
Igor Murashkin1e854c52014-08-28 15:21:49 -0700976 /** Map frame numbers to list of partial results */
977 private final HashMap<Long, List<CaptureResult>> mPartialResults = new HashMap<>();
Jianing Weid2c3a822014-03-27 18:27:43 -0700978
979 private void update() {
980 Iterator<Long> iter = mFutureErrorSet.iterator();
981 while (iter.hasNext()) {
982 long errorFrameNumber = iter.next();
983 if (errorFrameNumber == mCompletedFrameNumber + 1) {
984 mCompletedFrameNumber++;
985 iter.remove();
986 } else {
987 break;
988 }
989 }
990 }
991
992 /**
993 * This function is called every time when a result or an error is received.
Igor Murashkin1e854c52014-08-28 15:21:49 -0700994 * @param frameNumber the frame number corresponding to the result or error
995 * @param isError true if it is an error, false if it is not an error
Jianing Weid2c3a822014-03-27 18:27:43 -0700996 */
997 public void updateTracker(long frameNumber, boolean isError) {
998 if (isError) {
999 mFutureErrorSet.add(frameNumber);
1000 } else {
1001 /**
1002 * HAL cannot send an OnResultReceived for frame N unless it knows for
1003 * sure that all frames prior to N have either errored out or completed.
1004 * So if the current frame is not an error, then all previous frames
1005 * should have arrived. The following line checks whether this holds.
1006 */
1007 if (frameNumber != mCompletedFrameNumber + 1) {
Zhijun He22589b42014-05-01 10:37:36 -07001008 Log.e(TAG, String.format(
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001009 "result frame number %d comes out of order, should be %d + 1",
1010 frameNumber, mCompletedFrameNumber));
Eino-Ville Talvala95037852014-09-14 14:07:05 -07001011 // Continue on to set the completed frame number to this frame anyway,
1012 // to be robust to lower-level errors and allow for clean shutdowns.
Jianing Weid2c3a822014-03-27 18:27:43 -07001013 }
Eino-Ville Talvala95037852014-09-14 14:07:05 -07001014 mCompletedFrameNumber = frameNumber;
Jianing Weid2c3a822014-03-27 18:27:43 -07001015 }
1016 update();
1017 }
1018
Igor Murashkin1e854c52014-08-28 15:21:49 -07001019 /**
1020 * This function is called every time a result has been completed.
1021 *
1022 * <p>It keeps a track of all the partial results already created for a particular
1023 * frame number.</p>
1024 *
1025 * @param frameNumber the frame number corresponding to the result
1026 * @param result the total or partial result
1027 * @param partial {@true} if the result is partial, {@code false} if total
1028 */
1029 public void updateTracker(long frameNumber, CaptureResult result, boolean partial) {
1030
1031 if (!partial) {
1032 // Update the total result's frame status as being successful
1033 updateTracker(frameNumber, /*isError*/false);
1034 // Don't keep a list of total results, we don't need to track them
1035 return;
1036 }
1037
1038 if (result == null) {
1039 // Do not record blank results; this also means there will be no total result
1040 // so it doesn't matter that the partials were not recorded
1041 return;
1042 }
1043
1044 // Partial results must be aggregated in-order for that frame number
1045 List<CaptureResult> partials = mPartialResults.get(frameNumber);
1046 if (partials == null) {
1047 partials = new ArrayList<>();
1048 mPartialResults.put(frameNumber, partials);
1049 }
1050
1051 partials.add(result);
1052 }
1053
1054 /**
1055 * Attempt to pop off all of the partial results seen so far for the {@code frameNumber}.
1056 *
1057 * <p>Once popped-off, the partial results are forgotten (unless {@code updateTracker}
1058 * is called again with new partials for that frame number).</p>
1059 *
1060 * @param frameNumber the frame number corresponding to the result
1061 * @return a list of partial results for that frame with at least 1 element,
1062 * or {@code null} if there were no partials recorded for that frame
1063 */
1064 public List<CaptureResult> popPartialResults(long frameNumber) {
1065 return mPartialResults.remove(frameNumber);
1066 }
1067
Jianing Weid2c3a822014-03-27 18:27:43 -07001068 public long getCompletedFrameNumber() {
1069 return mCompletedFrameNumber;
1070 }
1071
1072 }
1073
1074 private void checkAndFireSequenceComplete() {
1075 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
1076 Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
1077 while (iter.hasNext()) {
1078 final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
1079 if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
1080
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001081 // remove request from mCaptureCallbackMap
Jianing Weid2c3a822014-03-27 18:27:43 -07001082 final int requestId = frameNumberRequestPair.getValue();
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001083 final CaptureCallbackHolder holder;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001084 synchronized(mInterfaceLock) {
1085 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001086 Log.w(TAG, "Camera closed while checking sequences");
1087 return;
1088 }
1089
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001090 int index = mCaptureCallbackMap.indexOfKey(requestId);
1091 holder = (index >= 0) ? mCaptureCallbackMap.valueAt(index)
Jianing Weid2c3a822014-03-27 18:27:43 -07001092 : null;
1093 if (holder != null) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001094 mCaptureCallbackMap.removeAt(index);
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001095 if (DEBUG) {
1096 Log.v(TAG, String.format(
1097 "remove holder for requestId %d, "
1098 + "because lastFrame %d is <= %d",
1099 requestId, frameNumberRequestPair.getKey(),
1100 completedFrameNumber));
1101 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001102 }
1103 }
1104 iter.remove();
1105
1106 // Call onCaptureSequenceCompleted
1107 if (holder != null) {
1108 Runnable resultDispatch = new Runnable() {
1109 @Override
1110 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001111 if (!CameraDeviceImpl.this.isClosed()){
Jianing Weid2c3a822014-03-27 18:27:43 -07001112 if (DEBUG) {
1113 Log.d(TAG, String.format(
1114 "fire sequence complete for request %d",
1115 requestId));
1116 }
1117
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001118 long lastFrameNumber = frameNumberRequestPair.getKey();
1119 if (lastFrameNumber < Integer.MIN_VALUE
1120 || lastFrameNumber > Integer.MAX_VALUE) {
1121 throw new AssertionError(lastFrameNumber
1122 + " cannot be cast to int");
1123 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001124 holder.getCallback().onCaptureSequenceCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -07001125 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -07001126 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -07001127 lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -07001128 }
1129 }
1130 };
1131 holder.getHandler().post(resultDispatch);
1132 }
1133
1134 }
1135 }
1136 }
1137
Zhijun Heecb323e2013-07-31 09:40:27 -07001138 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +00001139
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001140 //
1141 // Constants below need to be kept up-to-date with
1142 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
1143 //
1144
1145 //
1146 // Error codes for onCameraError
1147 //
1148
1149 /**
1150 * Camera has been disconnected
1151 */
1152 static final int ERROR_CAMERA_DISCONNECTED = 0;
1153
1154 /**
1155 * Camera has encountered a device-level error
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001156 * Matches CameraDevice.StateCallback#ERROR_CAMERA_DEVICE
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001157 */
1158 static final int ERROR_CAMERA_DEVICE = 1;
1159
1160 /**
1161 * Camera has encountered a service-level error
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001162 * Matches CameraDevice.StateCallback#ERROR_CAMERA_SERVICE
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001163 */
1164 static final int ERROR_CAMERA_SERVICE = 2;
1165
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001166 /**
1167 * Camera has encountered an error processing a single request.
1168 */
1169 static final int ERROR_CAMERA_REQUEST = 3;
1170
1171 /**
1172 * Camera has encountered an error producing metadata for a single capture
1173 */
1174 static final int ERROR_CAMERA_RESULT = 4;
1175
1176 /**
1177 * Camera has encountered an error producing an image buffer for a single capture
1178 */
1179 static final int ERROR_CAMERA_BUFFER = 5;
1180
Igor Murashkin70725502013-06-25 20:27:06 +00001181 @Override
1182 public IBinder asBinder() {
1183 return this;
1184 }
1185
Igor Murashkin70725502013-06-25 20:27:06 +00001186 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001187 public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) {
1188 if (DEBUG) {
1189 Log.d(TAG, String.format(
1190 "Device error received, code %d, frame number %d, request ID %d, subseq ID %d",
1191 errorCode, resultExtras.getFrameNumber(), resultExtras.getRequestId(),
1192 resultExtras.getSubsequenceId()));
1193 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001194
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001195 synchronized(mInterfaceLock) {
1196 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001197 return; // Camera already closed
1198 }
1199
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001200 switch (errorCode) {
1201 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001202 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnDisconnected);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001203 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001204 default:
1205 Log.e(TAG, "Unknown error from camera device: " + errorCode);
1206 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001207 case ERROR_CAMERA_DEVICE:
1208 case ERROR_CAMERA_SERVICE:
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001209 mInError = true;
1210 Runnable r = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -07001211 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001212 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001213 if (!CameraDeviceImpl.this.isClosed()) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001214 mDeviceCallback.onError(CameraDeviceImpl.this, errorCode);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001215 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001216 }
1217 };
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001218 CameraDeviceImpl.this.mDeviceHandler.post(r);
1219 break;
1220 case ERROR_CAMERA_REQUEST:
1221 case ERROR_CAMERA_RESULT:
1222 case ERROR_CAMERA_BUFFER:
1223 onCaptureErrorLocked(errorCode, resultExtras);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001224 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001225 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001226 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001227 }
1228
1229 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001230 public void onDeviceIdle() {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001231 if (DEBUG) {
1232 Log.d(TAG, "Camera now idle");
1233 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001234 synchronized(mInterfaceLock) {
1235 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07001236
Igor Murashkin21547d62014-06-04 15:21:42 -07001237 if (!CameraDeviceImpl.this.mIdle) {
1238 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnIdle);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001239 }
Igor Murashkin21547d62014-06-04 15:21:42 -07001240 CameraDeviceImpl.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001241 }
1242 }
1243
1244 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001245 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
1246 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae8df3092014-09-08 14:30:50 -07001247 final long frameNumber = resultExtras.getFrameNumber();
1248
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001249 if (DEBUG) {
Eino-Ville Talvalae8df3092014-09-08 14:30:50 -07001250 Log.d(TAG, "Capture started for id " + requestId + " frame number " + frameNumber);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001251 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001252 final CaptureCallbackHolder holder;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001253
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001254 synchronized(mInterfaceLock) {
1255 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07001256
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001257 // Get the callback for this frame ID, if there is one
1258 holder = CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001259
Igor Murashkin49b2b132014-06-18 19:03:00 -07001260 if (holder == null) {
1261 return;
1262 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001263
Igor Murashkin49b2b132014-06-18 19:03:00 -07001264 if (isClosed()) return;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001265
Igor Murashkin49b2b132014-06-18 19:03:00 -07001266 // Dispatch capture start notice
1267 holder.getHandler().post(
1268 new Runnable() {
1269 @Override
1270 public void run() {
1271 if (!CameraDeviceImpl.this.isClosed()) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001272 holder.getCallback().onCaptureStarted(
Igor Murashkin49b2b132014-06-18 19:03:00 -07001273 CameraDeviceImpl.this,
1274 holder.getRequest(resultExtras.getSubsequenceId()),
Eino-Ville Talvalae8df3092014-09-08 14:30:50 -07001275 timestamp, frameNumber);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001276 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001277 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001278 });
1279
1280 }
Igor Murashkin70725502013-06-25 20:27:06 +00001281 }
1282
1283 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001284 public void onResultReceived(CameraMetadataNative result,
1285 CaptureResultExtras resultExtras) throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -07001286
Jianing Weid2c3a822014-03-27 18:27:43 -07001287 int requestId = resultExtras.getRequestId();
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001288 long frameNumber = resultExtras.getFrameNumber();
1289
Zhijun Heecb323e2013-07-31 09:40:27 -07001290 if (DEBUG) {
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001291 Log.v(TAG, "Received result frame " + frameNumber + " for id "
Jianing Weibaf0c652014-04-18 17:35:00 -07001292 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -07001293 }
Ruben Brunk57493682014-05-27 18:58:08 -07001294
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001295 synchronized(mInterfaceLock) {
1296 if (mRemoteDevice == null) return; // Camera already closed
Ruben Brunk57493682014-05-27 18:58:08 -07001297
Igor Murashkin49b2b132014-06-18 19:03:00 -07001298 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
1299 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
1300 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
Ruben Brunk57493682014-05-27 18:58:08 -07001301
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001302 final CaptureCallbackHolder holder =
1303 CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +00001304
Zhijun He83159152014-07-16 11:32:59 -07001305 boolean isPartialResult =
1306 (resultExtras.getPartialResultCount() < mTotalPartialCount);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001307
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001308 // Check if we have a callback for this
Igor Murashkin49b2b132014-06-18 19:03:00 -07001309 if (holder == null) {
1310 if (DEBUG) {
1311 Log.d(TAG,
1312 "holder is null, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001313 + frameNumber);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001314 }
Igor Murashkin1e854c52014-08-28 15:21:49 -07001315
1316 mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult);
1317
Igor Murashkin49b2b132014-06-18 19:03:00 -07001318 return;
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001319 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001320
Igor Murashkin49b2b132014-06-18 19:03:00 -07001321 if (isClosed()) {
1322 if (DEBUG) {
1323 Log.d(TAG,
1324 "camera is closed, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001325 + frameNumber);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001326 }
Igor Murashkin1e854c52014-08-28 15:21:49 -07001327
1328 mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001329 return;
1330 }
Igor Murashkindb075af2014-05-21 10:07:08 -07001331
Igor Murashkin49b2b132014-06-18 19:03:00 -07001332 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
1333
Igor Murashkin49b2b132014-06-18 19:03:00 -07001334 Runnable resultDispatch = null;
1335
Igor Murashkin1e854c52014-08-28 15:21:49 -07001336 CaptureResult finalResult;
1337
Igor Murashkin49b2b132014-06-18 19:03:00 -07001338 // Either send a partial result or the final capture completed result
Zhijun He83159152014-07-16 11:32:59 -07001339 if (isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001340 final CaptureResult resultAsCapture =
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001341 new CaptureResult(result, request, resultExtras);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001342
1343 // Partial result
1344 resultDispatch = new Runnable() {
1345 @Override
1346 public void run() {
1347 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001348 holder.getCallback().onCaptureProgressed(
Igor Murashkin49b2b132014-06-18 19:03:00 -07001349 CameraDeviceImpl.this,
1350 request,
1351 resultAsCapture);
1352 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001353 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001354 };
Igor Murashkin1e854c52014-08-28 15:21:49 -07001355
1356 finalResult = resultAsCapture;
Igor Murashkin49b2b132014-06-18 19:03:00 -07001357 } else {
Igor Murashkin1e854c52014-08-28 15:21:49 -07001358 List<CaptureResult> partialResults =
1359 mFrameNumberTracker.popPartialResults(frameNumber);
1360
Igor Murashkin49b2b132014-06-18 19:03:00 -07001361 final TotalCaptureResult resultAsCapture =
Igor Murashkin1e854c52014-08-28 15:21:49 -07001362 new TotalCaptureResult(result, request, resultExtras, partialResults);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001363
Igor Murashkin49b2b132014-06-18 19:03:00 -07001364 // Final capture result
1365 resultDispatch = new Runnable() {
1366 @Override
1367 public void run() {
1368 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001369 holder.getCallback().onCaptureCompleted(
Igor Murashkin49b2b132014-06-18 19:03:00 -07001370 CameraDeviceImpl.this,
1371 request,
1372 resultAsCapture);
1373 }
1374 }
1375 };
Igor Murashkin1e854c52014-08-28 15:21:49 -07001376
1377 finalResult = resultAsCapture;
Igor Murashkin49b2b132014-06-18 19:03:00 -07001378 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001379
Igor Murashkin49b2b132014-06-18 19:03:00 -07001380 holder.getHandler().post(resultDispatch);
1381
Igor Murashkin1e854c52014-08-28 15:21:49 -07001382 // Collect the partials for a total result; or mark the frame as totally completed
1383 mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult);
1384
Igor Murashkin49b2b132014-06-18 19:03:00 -07001385 // Fire onCaptureSequenceCompleted
Zhijun He83159152014-07-16 11:32:59 -07001386 if (!isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001387 checkAndFireSequenceComplete();
1388 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001389 }
Igor Murashkin70725502013-06-25 20:27:06 +00001390 }
1391
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001392 /**
1393 * Called by onDeviceError for handling single-capture failures.
1394 */
1395 private void onCaptureErrorLocked(int errorCode, CaptureResultExtras resultExtras) {
1396
1397 final int requestId = resultExtras.getRequestId();
1398 final int subsequenceId = resultExtras.getSubsequenceId();
1399 final long frameNumber = resultExtras.getFrameNumber();
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001400 final CaptureCallbackHolder holder =
1401 CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001402
1403 final CaptureRequest request = holder.getRequest(subsequenceId);
1404
1405 // No way to report buffer errors right now
1406 if (errorCode == ERROR_CAMERA_BUFFER) {
1407 Log.e(TAG, String.format("Lost output buffer reported for frame %d", frameNumber));
1408 return;
1409 }
1410
1411 boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
1412
1413 // This is only approximate - exact handling needs the camera service and HAL to
1414 // disambiguate between request failures to due abort and due to real errors.
1415 // For now, assume that if the session believes we're mid-abort, then the error
1416 // is due to abort.
1417 int reason = (mCurrentSession != null && mCurrentSession.isAborting()) ?
1418 CaptureFailure.REASON_FLUSHED :
1419 CaptureFailure.REASON_ERROR;
1420
1421 final CaptureFailure failure = new CaptureFailure(
1422 request,
1423 reason,
1424 /*dropped*/ mayHaveBuffers,
1425 requestId,
1426 frameNumber);
1427
1428 Runnable failureDispatch = new Runnable() {
1429 @Override
1430 public void run() {
1431 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001432 holder.getCallback().onCaptureFailed(
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001433 CameraDeviceImpl.this,
1434 request,
1435 failure);
1436 }
1437 }
1438 };
1439 holder.getHandler().post(failureDispatch);
1440
1441 // Fire onCaptureSequenceCompleted if appropriate
1442 if (DEBUG) {
1443 Log.v(TAG, String.format("got error frame %d", frameNumber));
1444 }
1445 mFrameNumberTracker.updateTracker(frameNumber, /*error*/true);
1446 checkAndFireSequenceComplete();
1447 }
1448
1449 } // public class CameraDeviceCallbacks
Igor Murashkin70725502013-06-25 20:27:06 +00001450
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001451 /**
Igor Murashkin0b27d342014-05-30 09:45:05 -07001452 * Default handler management.
1453 *
1454 * <p>
1455 * If handler is null, get the current thread's
1456 * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
1457 * </p>
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001458 */
Igor Murashkin0b27d342014-05-30 09:45:05 -07001459 static Handler checkHandler(Handler handler) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001460 if (handler == null) {
1461 Looper looper = Looper.myLooper();
1462 if (looper == null) {
1463 throw new IllegalArgumentException(
1464 "No handler given, and current thread has no looper!");
1465 }
1466 handler = new Handler(looper);
1467 }
1468 return handler;
1469 }
1470
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001471 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001472 * Default handler management, conditional on there being a callback.
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001473 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001474 * <p>If the callback isn't null, check the handler, otherwise pass it through.</p>
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001475 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001476 static <T> Handler checkHandler(Handler handler, T callback) {
1477 if (callback != null) {
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001478 return checkHandler(handler);
1479 }
1480 return handler;
1481 }
1482
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001483 private void checkIfCameraClosedOrInError() throws CameraAccessException {
1484 if (mInError) {
1485 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
1486 "The camera device has encountered a serious error");
1487 }
Zhijun He7f4d3142013-07-23 07:54:38 -07001488 if (mRemoteDevice == null) {
1489 throw new IllegalStateException("CameraDevice was already closed");
1490 }
1491 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001492
Igor Murashkin49b2b132014-06-18 19:03:00 -07001493 /** Whether the camera device has started to close (may not yet have finished) */
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001494 private boolean isClosed() {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001495 return mClosing;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001496 }
Ruben Brunk57493682014-05-27 18:58:08 -07001497
1498 private CameraCharacteristics getCharacteristics() {
1499 return mCharacteristics;
1500 }
Igor Murashkin70725502013-06-25 20:27:06 +00001501}