blob: 197b9ca216f8becfee1d244f7d9687c78402c110 [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 Talvala868d9042013-10-03 11:15:21 -070067 private final StateListener mDeviceListener;
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -070068 private volatile StateListenerKK mSessionStateListener;
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
Igor Murashkin21547d62014-06-04 15:21:42 -070075 /** map request IDs to listener/request data */
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070076 private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
77 new SparseArray<CaptureListenerHolder>();
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;
102
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700103 // Runnables for all state transitions, except error, which needs the
104 // error code argument
105
106 private final Runnable mCallOnOpened = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700107 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700108 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700109 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700110 synchronized(mInterfaceLock) {
111 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700112
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700113 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700114 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700115 if (sessionListener != null) {
116 sessionListener.onOpened(CameraDeviceImpl.this);
117 }
118 mDeviceListener.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700119 }
120 };
121
122 private final Runnable mCallOnUnconfigured = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700123 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700124 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700125 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700126 synchronized(mInterfaceLock) {
127 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700128
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700129 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700130 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700131 if (sessionListener != null) {
132 sessionListener.onUnconfigured(CameraDeviceImpl.this);
133 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700134 }
135 };
136
137 private final Runnable mCallOnActive = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700138 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700139 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700140 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700141 synchronized(mInterfaceLock) {
142 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700143
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700144 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700145 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700146 if (sessionListener != null) {
147 sessionListener.onActive(CameraDeviceImpl.this);
148 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700149 }
150 };
151
152 private final Runnable mCallOnBusy = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700153 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700154 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700155 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700156 synchronized(mInterfaceLock) {
157 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700158
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700159 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700160 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700161 if (sessionListener != null) {
162 sessionListener.onBusy(CameraDeviceImpl.this);
163 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700164 }
165 };
166
167 private final Runnable mCallOnClosed = new Runnable() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700168 private boolean mClosedOnce = false;
169
Jianing Weid2c3a822014-03-27 18:27:43 -0700170 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700171 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700172 if (mClosedOnce) {
173 throw new AssertionError("Don't post #onClosed more than once");
174 }
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700175 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700176 synchronized(mInterfaceLock) {
177 sessionListener = mSessionStateListener;
178 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700179 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700180 sessionListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700181 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700182 mDeviceListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin49b2b132014-06-18 19:03:00 -0700183 mClosedOnce = true;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700184 }
185 };
186
187 private final Runnable mCallOnIdle = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700188 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700189 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700190 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700191 synchronized(mInterfaceLock) {
192 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700193
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700194 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700195 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700196 if (sessionListener != null) {
197 sessionListener.onIdle(CameraDeviceImpl.this);
198 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700199 }
200 };
201
202 private final Runnable mCallOnDisconnected = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700203 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700204 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700205 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700206 synchronized(mInterfaceLock) {
207 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700208
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700209 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700210 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700211 if (sessionListener != null) {
212 sessionListener.onDisconnected(CameraDeviceImpl.this);
213 }
214 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700215 }
216 };
217
Igor Murashkin21547d62014-06-04 15:21:42 -0700218 public CameraDeviceImpl(String cameraId, StateListener listener, Handler handler,
Ruben Brunk57493682014-05-27 18:58:08 -0700219 CameraCharacteristics characteristics) {
Zhijun He83159152014-07-16 11:32:59 -0700220 if (cameraId == null || listener == null || handler == null || characteristics == null) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700221 throw new IllegalArgumentException("Null argument given");
222 }
Igor Murashkin70725502013-06-25 20:27:06 +0000223 mCameraId = cameraId;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700224 mDeviceListener = listener;
225 mDeviceHandler = handler;
Ruben Brunk57493682014-05-27 18:58:08 -0700226 mCharacteristics = characteristics;
Eino-Ville Talvalab72d1ef2014-04-28 13:21:18 -0700227
228 final int MAX_TAG_LEN = 23;
229 String tag = String.format("CameraDevice-JV-%s", mCameraId);
230 if (tag.length() > MAX_TAG_LEN) {
231 tag = tag.substring(0, MAX_TAG_LEN);
232 }
233 TAG = tag;
Zhijun Heecb323e2013-07-31 09:40:27 -0700234 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Zhijun He83159152014-07-16 11:32:59 -0700235
236 Integer partialCount =
237 mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
238 if (partialCount == null) {
239 // 1 means partial result is not supported.
240 mTotalPartialCount = 1;
241 } else {
242 mTotalPartialCount = partialCount;
243 }
Igor Murashkin70725502013-06-25 20:27:06 +0000244 }
245
246 public CameraDeviceCallbacks getCallbacks() {
247 return mCallbacks;
248 }
249
Igor Murashkin70725502013-06-25 20:27:06 +0000250 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700251 synchronized(mInterfaceLock) {
252 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700253 // If setRemoteFailure already called, do nothing
254 if (mInError) return;
255
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700256 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
257
258 mDeviceHandler.post(mCallOnOpened);
259 mDeviceHandler.post(mCallOnUnconfigured);
260 }
Igor Murashkin70725502013-06-25 20:27:06 +0000261 }
262
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700263 /**
264 * Call to indicate failed connection to a remote camera device.
265 *
266 * <p>This places the camera device in the error state and informs the listener.
267 * Use in place of setRemoteDevice() when startup fails.</p>
268 */
269 public void setRemoteFailure(final CameraRuntimeException failure) {
270 int failureCode = StateListener.ERROR_CAMERA_DEVICE;
271 boolean failureIsError = true;
272
273 switch (failure.getReason()) {
274 case CameraAccessException.CAMERA_IN_USE:
275 failureCode = StateListener.ERROR_CAMERA_IN_USE;
276 break;
277 case CameraAccessException.MAX_CAMERAS_IN_USE:
278 failureCode = StateListener.ERROR_MAX_CAMERAS_IN_USE;
279 break;
280 case CameraAccessException.CAMERA_DISABLED:
281 failureCode = StateListener.ERROR_CAMERA_DISABLED;
282 break;
283 case CameraAccessException.CAMERA_DISCONNECTED:
284 failureIsError = false;
285 break;
286 case CameraAccessException.CAMERA_ERROR:
287 failureCode = StateListener.ERROR_CAMERA_DEVICE;
288 break;
289 default:
290 Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
291 break;
292 }
293 final int code = failureCode;
294 final boolean isError = failureIsError;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700295 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700296 mInError = true;
297 mDeviceHandler.post(new Runnable() {
Igor Murashkine1442202014-06-09 17:51:24 -0700298 @Override
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700299 public void run() {
300 if (isError) {
301 mDeviceListener.onError(CameraDeviceImpl.this, code);
302 } else {
303 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
304 }
305 }
306 });
307 }
308 }
309
Igor Murashkin70725502013-06-25 20:27:06 +0000310 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700311 public String getId() {
312 return mCameraId;
313 }
314
Igor Murashkin70725502013-06-25 20:27:06 +0000315 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700316 // Leave this here for backwards compatibility with older code using this directly
317 configureOutputsChecked(outputs);
318 }
319
320 /**
321 * Attempt to configure the outputs; the device goes to idle and then configures the
322 * new outputs if possible.
323 *
324 * <p>The configuration may gracefully fail, if there are too many outputs, if the formats
325 * are not supported, or if the sizes for that format is not supported. In this case this
326 * function will return {@code false} and the unconfigured callback will be fired.</p>
327 *
328 * <p>If the configuration succeeds (with 1 or more outputs), then the idle callback is fired.
329 * Unconfiguring the device always fires the idle callback.</p>
330 *
331 * @param outputs a list of one or more surfaces, or {@code null} to unconfigure
332 * @return whether or not the configuration was successful
333 *
334 * @throws CameraAccessException if there were any unexpected problems during configuration
335 */
336 public boolean configureOutputsChecked(List<Surface> outputs) throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700337 // Treat a null input the same an empty list
338 if (outputs == null) {
339 outputs = new ArrayList<Surface>();
340 }
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700341 boolean success = false;
342
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700343 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700344 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700345
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700346 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
347 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
348
349 // Determine which streams need to be created, which to be deleted
350 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
351 int streamId = mConfiguredOutputs.keyAt(i);
352 Surface s = mConfiguredOutputs.valueAt(i);
353
354 if (!outputs.contains(s)) {
355 deleteList.add(streamId);
356 } else {
357 addSet.remove(s); // Don't create a stream previously created
358 }
359 }
360
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700361 mDeviceHandler.post(mCallOnBusy);
362 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700363
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700364 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700365 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700366
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700367 mRemoteDevice.beginConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700368 // Delete all streams first (to free up HW resources)
369 for (Integer streamId : deleteList) {
370 mRemoteDevice.deleteStream(streamId);
371 mConfiguredOutputs.delete(streamId);
372 }
373
374 // Add all new streams
375 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000376 // TODO: remove width,height,format since we are ignoring
377 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700378 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
379 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000380 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700381
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700382 try {
383 mRemoteDevice.endConfigure();
384 }
385 catch (IllegalArgumentException e) {
386 // OK. camera service can reject stream config if it's not supported by HAL
387 // This is only the result of a programmer misusing the camera2 api.
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700388 Log.w(TAG, "Stream configuration failed");
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700389 return false;
390 }
391
392 success = true;
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700393 } catch (CameraRuntimeException e) {
394 if (e.getReason() == CAMERA_IN_USE) {
395 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700396 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700397 }
398
399 throw e.asChecked();
400 } catch (RemoteException e) {
401 // impossible
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700402 return false;
403 } finally {
404 if (success && outputs.size() > 0) {
405 mDeviceHandler.post(mCallOnIdle);
406 } else {
407 // Always return to the 'unconfigured' state if we didn't hit a fatal error
408 mDeviceHandler.post(mCallOnUnconfigured);
409 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700410 }
Igor Murashkin70725502013-06-25 20:27:06 +0000411 }
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700412
413 return success;
Igor Murashkin70725502013-06-25 20:27:06 +0000414 }
415
416 @Override
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700417 public void createCaptureSession(List<Surface> outputs,
418 CameraCaptureSession.StateListener listener, Handler handler)
419 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700420 synchronized(mInterfaceLock) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700421 if (DEBUG) {
422 Log.d(TAG, "createCaptureSession");
423 }
424
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700425 checkIfCameraClosedOrInError();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700426
Eino-Ville Talvalad3b85f62014-08-05 15:02:31 -0700427 // Notify current session that it's going away, before starting camera operations
428 // After this call completes, the session is not allowed to call into CameraDeviceImpl
429 if (mCurrentSession != null) {
430 mCurrentSession.replaceSessionClose();
431 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700432
433 // TODO: dont block for this
434 boolean configureSuccess = true;
435 CameraAccessException pendingException = null;
436 try {
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700437 configureSuccess = configureOutputsChecked(outputs); // and then block until IDLE
Igor Murashkin0b27d342014-05-30 09:45:05 -0700438 } catch (CameraAccessException e) {
439 configureSuccess = false;
440 pendingException = e;
Igor Murashkine1442202014-06-09 17:51:24 -0700441 if (DEBUG) {
442 Log.v(TAG, "createCaptureSession - failed with exception ", e);
443 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700444 }
445
446 // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
447 CameraCaptureSessionImpl newSession =
448 new CameraCaptureSessionImpl(outputs, listener, handler, this, mDeviceHandler,
449 configureSuccess);
450
Igor Murashkin0b27d342014-05-30 09:45:05 -0700451 // TODO: wait until current session closes, then create the new session
452 mCurrentSession = newSession;
453
454 if (pendingException != null) {
455 throw pendingException;
456 }
457
458 mSessionStateListener = mCurrentSession.getDeviceStateListener();
459 }
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700460 }
461
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700462 /**
463 * For use by backwards-compatibility code only.
464 */
465 public void setSessionListener(StateListenerKK sessionListener) {
466 synchronized(mInterfaceLock) {
467 mSessionStateListener = sessionListener;
468 }
469 }
470
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700471 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700472 public CaptureRequest.Builder createCaptureRequest(int templateType)
473 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700474 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700475 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000476
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700477 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000478
479 try {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700480 mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000481 } catch (CameraRuntimeException e) {
482 throw e.asChecked();
483 } catch (RemoteException e) {
484 // impossible
485 return null;
486 }
487
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700488 CaptureRequest.Builder builder =
489 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000490
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700491 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000492 }
493 }
494
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700495 public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000496 throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700497 if (DEBUG) {
498 Log.d(TAG, "calling capture");
499 }
500 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
501 requestList.add(request);
502 return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000503 }
504
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700505 public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700506 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700507 if (requests == null || requests.isEmpty()) {
508 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700509 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700510 return submitCaptureRequest(requests, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000511 }
512
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700513 /**
514 * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
515 * starting and stopping repeating request and flushing.
516 *
517 * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700518 * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700519 * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
520 * is added to the list mFrameNumberRequestPairs.</p>
521 *
522 * @param requestId the request ID of the current repeating request.
523 *
524 * @param lastFrameNumber last frame number returned from binder.
525 */
526 private void checkEarlyTriggerSequenceComplete(
527 final int requestId, final long lastFrameNumber) {
528 // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700529 // was never sent to HAL. Should trigger onCaptureSequenceAborted immediately.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700530 if (lastFrameNumber == CaptureListener.NO_FRAMES_CAPTURED) {
531 final CaptureListenerHolder holder;
532 int index = mCaptureListenerMap.indexOfKey(requestId);
533 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index) : null;
534 if (holder != null) {
535 mCaptureListenerMap.removeAt(index);
Jianing Weibaf0c652014-04-18 17:35:00 -0700536 if (DEBUG) {
537 Log.v(TAG, String.format(
538 "remove holder for requestId %d, "
539 + "because lastFrame is %d.",
540 requestId, lastFrameNumber));
541 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700542 }
543
544 if (holder != null) {
545 if (DEBUG) {
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700546 Log.v(TAG, "immediately trigger onCaptureSequenceAborted because"
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700547 + " request did not reach HAL");
548 }
549
550 Runnable resultDispatch = new Runnable() {
551 @Override
552 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700553 if (!CameraDeviceImpl.this.isClosed()) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700554 if (DEBUG) {
555 Log.d(TAG, String.format(
556 "early trigger sequence complete for request %d",
557 requestId));
558 }
559 if (lastFrameNumber < Integer.MIN_VALUE
560 || lastFrameNumber > Integer.MAX_VALUE) {
561 throw new AssertionError(lastFrameNumber + " cannot be cast to int");
562 }
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700563 holder.getListener().onCaptureSequenceAborted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700564 CameraDeviceImpl.this,
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700565 requestId);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700566 }
567 }
568 };
569 holder.getHandler().post(resultDispatch);
570 } else {
571 Log.w(TAG, String.format(
572 "did not register listener to request %d",
573 requestId));
574 }
575 } else {
576 mFrameNumberRequestPairs.add(
577 new SimpleEntry<Long, Integer>(lastFrameNumber,
578 requestId));
579 }
580 }
581
Jianing Weid2c3a822014-03-27 18:27:43 -0700582 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700583 Handler handler, boolean repeating) throws CameraAccessException {
584
585 // Need a valid handler, or current thread needs to have a looper, if
586 // listener is valid
Eino-Ville Talvala7875a882014-07-31 12:47:07 -0700587 handler = checkHandler(handler, listener);
Igor Murashkin70725502013-06-25 20:27:06 +0000588
Ruben Brunk7f2372b2014-07-02 11:05:08 -0700589 // Make sure that there all requests have at least 1 surface; all surfaces are non-null
590 for (CaptureRequest request : requestList) {
591 if (request.getTargets().isEmpty()) {
592 throw new IllegalArgumentException(
593 "Each request must have at least one Surface target");
594 }
595
596 for (Surface surface : request.getTargets()) {
597 if (surface == null) {
598 throw new IllegalArgumentException("Null Surface targets are not allowed");
599 }
600 }
601 }
602
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700603 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700604 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000605 int requestId;
606
Ruben Brunke73b41b2013-11-07 19:30:43 -0800607 if (repeating) {
608 stopRepeating();
609 }
610
Jianing Weid2c3a822014-03-27 18:27:43 -0700611 LongParcelable lastFrameNumberRef = new LongParcelable();
Igor Murashkin70725502013-06-25 20:27:06 +0000612 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700613 requestId = mRemoteDevice.submitRequestList(requestList, repeating,
614 /*out*/lastFrameNumberRef);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700615 if (DEBUG) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700616 Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
617 }
Igor Murashkin70725502013-06-25 20:27:06 +0000618 } catch (CameraRuntimeException e) {
619 throw e.asChecked();
620 } catch (RemoteException e) {
621 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700622 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000623 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700624
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700625 if (listener != null) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700626 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener,
627 requestList, handler, repeating));
Jianing Weibaf0c652014-04-18 17:35:00 -0700628 } else {
629 if (DEBUG) {
630 Log.d(TAG, "Listen for request " + requestId + " is null");
631 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700632 }
Igor Murashkin70725502013-06-25 20:27:06 +0000633
Jianing Weid2c3a822014-03-27 18:27:43 -0700634 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700635
Igor Murashkin70725502013-06-25 20:27:06 +0000636 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700637 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700638 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700639 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700640 mRepeatingRequestId = requestId;
Jianing Weid2c3a822014-03-27 18:27:43 -0700641 } else {
642 mFrameNumberRequestPairs.add(
643 new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
Igor Murashkin70725502013-06-25 20:27:06 +0000644 }
645
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700646 if (mIdle) {
647 mDeviceHandler.post(mCallOnActive);
648 }
649 mIdle = false;
650
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700651 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000652 }
653 }
654
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700655 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700656 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700657 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
658 requestList.add(request);
659 return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000660 }
661
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700662 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700663 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700664 if (requests == null || requests.isEmpty()) {
665 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700666 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700667 return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000668 }
669
Igor Murashkin70725502013-06-25 20:27:06 +0000670 public void stopRepeating() throws CameraAccessException {
671
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700672 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700673 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700674 if (mRepeatingRequestId != REQUEST_ID_NONE) {
675
676 int requestId = mRepeatingRequestId;
677 mRepeatingRequestId = REQUEST_ID_NONE;
678
679 // Queue for deletion after in-flight requests finish
Zhijun He1a9b6462014-03-31 16:11:33 -0700680 if (mCaptureListenerMap.get(requestId) != null) {
681 mRepeatingRequestIdDeletedList.add(requestId);
682 }
Igor Murashkin70725502013-06-25 20:27:06 +0000683
684 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700685 LongParcelable lastFrameNumberRef = new LongParcelable();
686 mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
687 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700688
689 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
690
Igor Murashkin70725502013-06-25 20:27:06 +0000691 } catch (CameraRuntimeException e) {
692 throw e.asChecked();
693 } catch (RemoteException e) {
694 // impossible
695 return;
696 }
697 }
698 }
699 }
700
Zhijun Hed842fcd2013-12-26 14:14:04 -0800701 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700702
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700703 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700704 checkIfCameraClosedOrInError();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700705
Ruben Brunkdecfe952013-10-29 11:00:32 -0700706 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700707 throw new IllegalStateException("Active repeating request ongoing");
708 }
Zhijun He7f4d3142013-07-23 07:54:38 -0700709 try {
710 mRemoteDevice.waitUntilIdle();
711 } catch (CameraRuntimeException e) {
712 throw e.asChecked();
713 } catch (RemoteException e) {
714 // impossible
715 return;
716 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700717 }
Igor Murashkin70725502013-06-25 20:27:06 +0000718 }
719
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700720 public void flush() throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700721 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700722 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700723
724 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700725 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700726 LongParcelable lastFrameNumberRef = new LongParcelable();
727 mRemoteDevice.flush(/*out*/lastFrameNumberRef);
728 if (mRepeatingRequestId != REQUEST_ID_NONE) {
729 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700730 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700731 mRepeatingRequestId = REQUEST_ID_NONE;
732 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700733 } catch (CameraRuntimeException e) {
734 throw e.asChecked();
735 } catch (RemoteException e) {
736 // impossible
737 return;
738 }
739 }
740 }
741
742 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700743 public void close() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700744 synchronized (mInterfaceLock) {
Igor Murashkin70725502013-06-25 20:27:06 +0000745 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700746 if (mRemoteDevice != null) {
747 mRemoteDevice.disconnect();
748 }
Igor Murashkin70725502013-06-25 20:27:06 +0000749 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700750 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000751 } catch (RemoteException e) {
752 // impossible
753 }
754
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700755 // Only want to fire the onClosed callback once;
756 // either a normal close where the remote device is valid
757 // or a close after a startup error (no remote device but in error state)
758 if (mRemoteDevice != null || mInError) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700759 mDeviceHandler.post(mCallOnClosed);
760 }
Igor Murashkin70725502013-06-25 20:27:06 +0000761
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700762 mRemoteDevice = null;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700763 mInError = false;
Igor Murashkin70725502013-06-25 20:27:06 +0000764 }
765 }
766
767 @Override
768 protected void finalize() throws Throwable {
769 try {
770 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000771 }
772 finally {
773 super.finalize();
774 }
775 }
776
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700777 /**
778 * <p>A listener for tracking the progress of a {@link CaptureRequest}
779 * submitted to the camera device.</p>
780 *
781 */
782 public static abstract class CaptureListener {
783
784 /**
785 * This constant is used to indicate that no images were captured for
786 * the request.
787 *
788 * @hide
789 */
790 public static final int NO_FRAMES_CAPTURED = -1;
791
792 /**
793 * This method is called when the camera device has started capturing
794 * the output image for the request, at the beginning of image exposure.
795 *
796 * @see android.media.MediaActionSound
797 */
798 public void onCaptureStarted(CameraDevice camera,
799 CaptureRequest request, long timestamp) {
800 // default empty implementation
801 }
802
803 /**
804 * This method is called when some results from an image capture are
805 * available.
806 *
807 * @hide
808 */
809 public void onCapturePartial(CameraDevice camera,
810 CaptureRequest request, CaptureResult result) {
811 // default empty implementation
812 }
813
814 /**
815 * This method is called when an image capture makes partial forward progress; some
816 * (but not all) results from an image capture are available.
817 *
818 */
819 public void onCaptureProgressed(CameraDevice camera,
820 CaptureRequest request, CaptureResult partialResult) {
821 // default empty implementation
822 }
823
824 /**
825 * This method is called when an image capture has fully completed and all the
826 * result metadata is available.
827 */
828 public void onCaptureCompleted(CameraDevice camera,
829 CaptureRequest request, TotalCaptureResult result) {
830 // default empty implementation
831 }
832
833 /**
834 * This method is called instead of {@link #onCaptureCompleted} when the
835 * camera device failed to produce a {@link CaptureResult} for the
836 * request.
837 */
838 public void onCaptureFailed(CameraDevice camera,
839 CaptureRequest request, CaptureFailure failure) {
840 // default empty implementation
841 }
842
843 /**
844 * This method is called independently of the others in CaptureListener,
845 * when a capture sequence finishes and all {@link CaptureResult}
846 * or {@link CaptureFailure} for it have been returned via this listener.
847 */
848 public void onCaptureSequenceCompleted(CameraDevice camera,
849 int sequenceId, long frameNumber) {
850 // default empty implementation
851 }
852
853 /**
854 * This method is called independently of the others in CaptureListener,
855 * when a capture sequence aborts before any {@link CaptureResult}
856 * or {@link CaptureFailure} for it have been returned via this listener.
857 */
858 public void onCaptureSequenceAborted(CameraDevice camera,
859 int sequenceId) {
860 // default empty implementation
861 }
862 }
863
864 /**
865 * A listener for notifications about the state of a camera device, adding in the callbacks that
866 * were part of the earlier KK API design, but now only used internally.
867 */
868 public static abstract class StateListenerKK extends StateListener {
869 /**
870 * The method called when a camera device has no outputs configured.
871 *
872 */
873 public void onUnconfigured(CameraDevice camera) {
874 // Default empty implementation
875 }
876
877 /**
878 * The method called when a camera device begins processing
879 * {@link CaptureRequest capture requests}.
880 *
881 */
882 public void onActive(CameraDevice camera) {
883 // Default empty implementation
884 }
885
886 /**
887 * The method called when a camera device is busy.
888 *
889 */
890 public void onBusy(CameraDevice camera) {
891 // Default empty implementation
892 }
893
894 /**
895 * The method called when a camera device has finished processing all
896 * submitted capture requests and has reached an idle state.
897 *
898 */
899 public void onIdle(CameraDevice camera) {
900 // Default empty implementation
901 }
902 }
903
Igor Murashkin70725502013-06-25 20:27:06 +0000904 static class CaptureListenerHolder {
905
906 private final boolean mRepeating;
907 private final CaptureListener mListener;
Jianing Weid2c3a822014-03-27 18:27:43 -0700908 private final List<CaptureRequest> mRequestList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700909 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000910
Jianing Weid2c3a822014-03-27 18:27:43 -0700911 CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList,
912 Handler handler, boolean repeating) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700913 if (listener == null || handler == null) {
914 throw new UnsupportedOperationException(
915 "Must have a valid handler and a valid listener");
916 }
Igor Murashkin70725502013-06-25 20:27:06 +0000917 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700918 mHandler = handler;
Jianing Weid2c3a822014-03-27 18:27:43 -0700919 mRequestList = new ArrayList<CaptureRequest>(requestList);
Igor Murashkin70725502013-06-25 20:27:06 +0000920 mListener = listener;
921 }
922
923 public boolean isRepeating() {
924 return mRepeating;
925 }
926
927 public CaptureListener getListener() {
928 return mListener;
929 }
930
Jianing Weid2c3a822014-03-27 18:27:43 -0700931 public CaptureRequest getRequest(int subsequenceId) {
932 if (subsequenceId >= mRequestList.size()) {
933 throw new IllegalArgumentException(
934 String.format(
935 "Requested subsequenceId %d is larger than request list size %d.",
936 subsequenceId, mRequestList.size()));
937 } else {
938 if (subsequenceId < 0) {
939 throw new IllegalArgumentException(String.format(
940 "Requested subsequenceId %d is negative", subsequenceId));
941 } else {
942 return mRequestList.get(subsequenceId);
943 }
944 }
945 }
946
Igor Murashkin70725502013-06-25 20:27:06 +0000947 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700948 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +0000949 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700950
951 public Handler getHandler() {
952 return mHandler;
953 }
954
Igor Murashkin70725502013-06-25 20:27:06 +0000955 }
956
Jianing Weid2c3a822014-03-27 18:27:43 -0700957 /**
958 * This class tracks the last frame number for submitted requests.
959 */
960 public class FrameNumberTracker {
961
962 private long mCompletedFrameNumber = -1;
963 private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
Igor Murashkin1e854c52014-08-28 15:21:49 -0700964 /** Map frame numbers to list of partial results */
965 private final HashMap<Long, List<CaptureResult>> mPartialResults = new HashMap<>();
Jianing Weid2c3a822014-03-27 18:27:43 -0700966
967 private void update() {
968 Iterator<Long> iter = mFutureErrorSet.iterator();
969 while (iter.hasNext()) {
970 long errorFrameNumber = iter.next();
971 if (errorFrameNumber == mCompletedFrameNumber + 1) {
972 mCompletedFrameNumber++;
973 iter.remove();
974 } else {
975 break;
976 }
977 }
978 }
979
980 /**
981 * This function is called every time when a result or an error is received.
Igor Murashkin1e854c52014-08-28 15:21:49 -0700982 * @param frameNumber the frame number corresponding to the result or error
983 * @param isError true if it is an error, false if it is not an error
Jianing Weid2c3a822014-03-27 18:27:43 -0700984 */
985 public void updateTracker(long frameNumber, boolean isError) {
986 if (isError) {
987 mFutureErrorSet.add(frameNumber);
988 } else {
989 /**
990 * HAL cannot send an OnResultReceived for frame N unless it knows for
991 * sure that all frames prior to N have either errored out or completed.
992 * So if the current frame is not an error, then all previous frames
993 * should have arrived. The following line checks whether this holds.
994 */
995 if (frameNumber != mCompletedFrameNumber + 1) {
Zhijun He22589b42014-05-01 10:37:36 -0700996 Log.e(TAG, String.format(
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700997 "result frame number %d comes out of order, should be %d + 1",
998 frameNumber, mCompletedFrameNumber));
Jianing Weid2c3a822014-03-27 18:27:43 -0700999 }
1000 mCompletedFrameNumber++;
1001 }
1002 update();
1003 }
1004
Igor Murashkin1e854c52014-08-28 15:21:49 -07001005 /**
1006 * This function is called every time a result has been completed.
1007 *
1008 * <p>It keeps a track of all the partial results already created for a particular
1009 * frame number.</p>
1010 *
1011 * @param frameNumber the frame number corresponding to the result
1012 * @param result the total or partial result
1013 * @param partial {@true} if the result is partial, {@code false} if total
1014 */
1015 public void updateTracker(long frameNumber, CaptureResult result, boolean partial) {
1016
1017 if (!partial) {
1018 // Update the total result's frame status as being successful
1019 updateTracker(frameNumber, /*isError*/false);
1020 // Don't keep a list of total results, we don't need to track them
1021 return;
1022 }
1023
1024 if (result == null) {
1025 // Do not record blank results; this also means there will be no total result
1026 // so it doesn't matter that the partials were not recorded
1027 return;
1028 }
1029
1030 // Partial results must be aggregated in-order for that frame number
1031 List<CaptureResult> partials = mPartialResults.get(frameNumber);
1032 if (partials == null) {
1033 partials = new ArrayList<>();
1034 mPartialResults.put(frameNumber, partials);
1035 }
1036
1037 partials.add(result);
1038 }
1039
1040 /**
1041 * Attempt to pop off all of the partial results seen so far for the {@code frameNumber}.
1042 *
1043 * <p>Once popped-off, the partial results are forgotten (unless {@code updateTracker}
1044 * is called again with new partials for that frame number).</p>
1045 *
1046 * @param frameNumber the frame number corresponding to the result
1047 * @return a list of partial results for that frame with at least 1 element,
1048 * or {@code null} if there were no partials recorded for that frame
1049 */
1050 public List<CaptureResult> popPartialResults(long frameNumber) {
1051 return mPartialResults.remove(frameNumber);
1052 }
1053
Jianing Weid2c3a822014-03-27 18:27:43 -07001054 public long getCompletedFrameNumber() {
1055 return mCompletedFrameNumber;
1056 }
1057
1058 }
1059
1060 private void checkAndFireSequenceComplete() {
1061 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
1062 Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
1063 while (iter.hasNext()) {
1064 final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
1065 if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
1066
1067 // remove request from mCaptureListenerMap
1068 final int requestId = frameNumberRequestPair.getValue();
1069 final CaptureListenerHolder holder;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001070 synchronized(mInterfaceLock) {
1071 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001072 Log.w(TAG, "Camera closed while checking sequences");
1073 return;
1074 }
1075
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001076 int index = mCaptureListenerMap.indexOfKey(requestId);
1077 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index)
Jianing Weid2c3a822014-03-27 18:27:43 -07001078 : null;
1079 if (holder != null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001080 mCaptureListenerMap.removeAt(index);
1081 if (DEBUG) {
1082 Log.v(TAG, String.format(
1083 "remove holder for requestId %d, "
1084 + "because lastFrame %d is <= %d",
1085 requestId, frameNumberRequestPair.getKey(),
1086 completedFrameNumber));
1087 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001088 }
1089 }
1090 iter.remove();
1091
1092 // Call onCaptureSequenceCompleted
1093 if (holder != null) {
1094 Runnable resultDispatch = new Runnable() {
1095 @Override
1096 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001097 if (!CameraDeviceImpl.this.isClosed()){
Jianing Weid2c3a822014-03-27 18:27:43 -07001098 if (DEBUG) {
1099 Log.d(TAG, String.format(
1100 "fire sequence complete for request %d",
1101 requestId));
1102 }
1103
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001104 long lastFrameNumber = frameNumberRequestPair.getKey();
1105 if (lastFrameNumber < Integer.MIN_VALUE
1106 || lastFrameNumber > Integer.MAX_VALUE) {
1107 throw new AssertionError(lastFrameNumber
1108 + " cannot be cast to int");
1109 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001110 holder.getListener().onCaptureSequenceCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -07001111 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -07001112 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -07001113 lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -07001114 }
1115 }
1116 };
1117 holder.getHandler().post(resultDispatch);
1118 }
1119
1120 }
1121 }
1122 }
1123
Zhijun Heecb323e2013-07-31 09:40:27 -07001124 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +00001125
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001126 //
1127 // Constants below need to be kept up-to-date with
1128 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
1129 //
1130
1131 //
1132 // Error codes for onCameraError
1133 //
1134
1135 /**
1136 * Camera has been disconnected
1137 */
1138 static final int ERROR_CAMERA_DISCONNECTED = 0;
1139
1140 /**
1141 * Camera has encountered a device-level error
1142 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
1143 */
1144 static final int ERROR_CAMERA_DEVICE = 1;
1145
1146 /**
1147 * Camera has encountered a service-level error
1148 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
1149 */
1150 static final int ERROR_CAMERA_SERVICE = 2;
1151
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001152 /**
1153 * Camera has encountered an error processing a single request.
1154 */
1155 static final int ERROR_CAMERA_REQUEST = 3;
1156
1157 /**
1158 * Camera has encountered an error producing metadata for a single capture
1159 */
1160 static final int ERROR_CAMERA_RESULT = 4;
1161
1162 /**
1163 * Camera has encountered an error producing an image buffer for a single capture
1164 */
1165 static final int ERROR_CAMERA_BUFFER = 5;
1166
Igor Murashkin70725502013-06-25 20:27:06 +00001167 @Override
1168 public IBinder asBinder() {
1169 return this;
1170 }
1171
Igor Murashkin70725502013-06-25 20:27:06 +00001172 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001173 public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) {
1174 if (DEBUG) {
1175 Log.d(TAG, String.format(
1176 "Device error received, code %d, frame number %d, request ID %d, subseq ID %d",
1177 errorCode, resultExtras.getFrameNumber(), resultExtras.getRequestId(),
1178 resultExtras.getSubsequenceId()));
1179 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001180
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001181 synchronized(mInterfaceLock) {
1182 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001183 return; // Camera already closed
1184 }
1185
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001186 switch (errorCode) {
1187 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001188 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnDisconnected);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001189 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001190 default:
1191 Log.e(TAG, "Unknown error from camera device: " + errorCode);
1192 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001193 case ERROR_CAMERA_DEVICE:
1194 case ERROR_CAMERA_SERVICE:
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001195 mInError = true;
1196 Runnable r = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -07001197 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001198 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001199 if (!CameraDeviceImpl.this.isClosed()) {
1200 mDeviceListener.onError(CameraDeviceImpl.this, errorCode);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001201 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001202 }
1203 };
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001204 CameraDeviceImpl.this.mDeviceHandler.post(r);
1205 break;
1206 case ERROR_CAMERA_REQUEST:
1207 case ERROR_CAMERA_RESULT:
1208 case ERROR_CAMERA_BUFFER:
1209 onCaptureErrorLocked(errorCode, resultExtras);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001210 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001211 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001212 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001213 }
1214
1215 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001216 public void onDeviceIdle() {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001217 if (DEBUG) {
1218 Log.d(TAG, "Camera now idle");
1219 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001220 synchronized(mInterfaceLock) {
1221 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07001222
Igor Murashkin21547d62014-06-04 15:21:42 -07001223 if (!CameraDeviceImpl.this.mIdle) {
1224 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnIdle);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001225 }
Igor Murashkin21547d62014-06-04 15:21:42 -07001226 CameraDeviceImpl.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001227 }
1228 }
1229
1230 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001231 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
1232 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001233 if (DEBUG) {
1234 Log.d(TAG, "Capture started for id " + requestId);
1235 }
1236 final CaptureListenerHolder holder;
1237
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001238 synchronized(mInterfaceLock) {
1239 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07001240
1241 // Get the listener for this frame ID, if there is one
Igor Murashkin21547d62014-06-04 15:21:42 -07001242 holder = CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001243
Igor Murashkin49b2b132014-06-18 19:03:00 -07001244 if (holder == null) {
1245 return;
1246 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001247
Igor Murashkin49b2b132014-06-18 19:03:00 -07001248 if (isClosed()) return;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001249
Igor Murashkin49b2b132014-06-18 19:03:00 -07001250 // Dispatch capture start notice
1251 holder.getHandler().post(
1252 new Runnable() {
1253 @Override
1254 public void run() {
1255 if (!CameraDeviceImpl.this.isClosed()) {
1256 holder.getListener().onCaptureStarted(
1257 CameraDeviceImpl.this,
1258 holder.getRequest(resultExtras.getSubsequenceId()),
1259 timestamp);
1260 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001261 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001262 });
1263
1264 }
Igor Murashkin70725502013-06-25 20:27:06 +00001265 }
1266
1267 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001268 public void onResultReceived(CameraMetadataNative result,
1269 CaptureResultExtras resultExtras) throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -07001270
Jianing Weid2c3a822014-03-27 18:27:43 -07001271 int requestId = resultExtras.getRequestId();
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001272 long frameNumber = resultExtras.getFrameNumber();
1273
Zhijun Heecb323e2013-07-31 09:40:27 -07001274 if (DEBUG) {
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001275 Log.v(TAG, "Received result frame " + frameNumber + " for id "
Jianing Weibaf0c652014-04-18 17:35:00 -07001276 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -07001277 }
Ruben Brunk57493682014-05-27 18:58:08 -07001278
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001279 synchronized(mInterfaceLock) {
1280 if (mRemoteDevice == null) return; // Camera already closed
Ruben Brunk57493682014-05-27 18:58:08 -07001281
Igor Murashkin49b2b132014-06-18 19:03:00 -07001282 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
1283 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
1284 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
Ruben Brunk57493682014-05-27 18:58:08 -07001285
Igor Murashkin49b2b132014-06-18 19:03:00 -07001286 final CaptureListenerHolder holder =
1287 CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +00001288
Zhijun He83159152014-07-16 11:32:59 -07001289 boolean isPartialResult =
1290 (resultExtras.getPartialResultCount() < mTotalPartialCount);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001291
Igor Murashkin49b2b132014-06-18 19:03:00 -07001292 // Check if we have a listener for this
1293 if (holder == null) {
1294 if (DEBUG) {
1295 Log.d(TAG,
1296 "holder is null, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001297 + frameNumber);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001298 }
Igor Murashkin1e854c52014-08-28 15:21:49 -07001299
1300 mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult);
1301
Igor Murashkin49b2b132014-06-18 19:03:00 -07001302 return;
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001303 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001304
Igor Murashkin49b2b132014-06-18 19:03:00 -07001305 if (isClosed()) {
1306 if (DEBUG) {
1307 Log.d(TAG,
1308 "camera is closed, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001309 + frameNumber);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001310 }
Igor Murashkin1e854c52014-08-28 15:21:49 -07001311
1312 mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001313 return;
1314 }
Igor Murashkindb075af2014-05-21 10:07:08 -07001315
Igor Murashkin49b2b132014-06-18 19:03:00 -07001316 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
1317
Igor Murashkin49b2b132014-06-18 19:03:00 -07001318 Runnable resultDispatch = null;
1319
Igor Murashkin1e854c52014-08-28 15:21:49 -07001320 CaptureResult finalResult;
1321
Igor Murashkin49b2b132014-06-18 19:03:00 -07001322 // Either send a partial result or the final capture completed result
Zhijun He83159152014-07-16 11:32:59 -07001323 if (isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001324 final CaptureResult resultAsCapture =
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001325 new CaptureResult(result, request, resultExtras);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001326
1327 // Partial result
1328 resultDispatch = new Runnable() {
1329 @Override
1330 public void run() {
1331 if (!CameraDeviceImpl.this.isClosed()){
Zhijun Hefac77c42014-07-18 14:20:48 -07001332 holder.getListener().onCaptureProgressed(
Igor Murashkin49b2b132014-06-18 19:03:00 -07001333 CameraDeviceImpl.this,
1334 request,
1335 resultAsCapture);
1336 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001337 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001338 };
Igor Murashkin1e854c52014-08-28 15:21:49 -07001339
1340 finalResult = resultAsCapture;
Igor Murashkin49b2b132014-06-18 19:03:00 -07001341 } else {
Igor Murashkin1e854c52014-08-28 15:21:49 -07001342 List<CaptureResult> partialResults =
1343 mFrameNumberTracker.popPartialResults(frameNumber);
1344
Igor Murashkin49b2b132014-06-18 19:03:00 -07001345 final TotalCaptureResult resultAsCapture =
Igor Murashkin1e854c52014-08-28 15:21:49 -07001346 new TotalCaptureResult(result, request, resultExtras, partialResults);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001347
Igor Murashkin49b2b132014-06-18 19:03:00 -07001348 // Final capture result
1349 resultDispatch = new Runnable() {
1350 @Override
1351 public void run() {
1352 if (!CameraDeviceImpl.this.isClosed()){
1353 holder.getListener().onCaptureCompleted(
1354 CameraDeviceImpl.this,
1355 request,
1356 resultAsCapture);
1357 }
1358 }
1359 };
Igor Murashkin1e854c52014-08-28 15:21:49 -07001360
1361 finalResult = resultAsCapture;
Igor Murashkin49b2b132014-06-18 19:03:00 -07001362 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001363
Igor Murashkin49b2b132014-06-18 19:03:00 -07001364 holder.getHandler().post(resultDispatch);
1365
Igor Murashkin1e854c52014-08-28 15:21:49 -07001366 // Collect the partials for a total result; or mark the frame as totally completed
1367 mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult);
1368
Igor Murashkin49b2b132014-06-18 19:03:00 -07001369 // Fire onCaptureSequenceCompleted
Zhijun He83159152014-07-16 11:32:59 -07001370 if (!isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001371 checkAndFireSequenceComplete();
1372 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001373 }
Igor Murashkin70725502013-06-25 20:27:06 +00001374 }
1375
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001376 /**
1377 * Called by onDeviceError for handling single-capture failures.
1378 */
1379 private void onCaptureErrorLocked(int errorCode, CaptureResultExtras resultExtras) {
1380
1381 final int requestId = resultExtras.getRequestId();
1382 final int subsequenceId = resultExtras.getSubsequenceId();
1383 final long frameNumber = resultExtras.getFrameNumber();
1384 final CaptureListenerHolder holder =
1385 CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
1386
1387 final CaptureRequest request = holder.getRequest(subsequenceId);
1388
1389 // No way to report buffer errors right now
1390 if (errorCode == ERROR_CAMERA_BUFFER) {
1391 Log.e(TAG, String.format("Lost output buffer reported for frame %d", frameNumber));
1392 return;
1393 }
1394
1395 boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
1396
1397 // This is only approximate - exact handling needs the camera service and HAL to
1398 // disambiguate between request failures to due abort and due to real errors.
1399 // For now, assume that if the session believes we're mid-abort, then the error
1400 // is due to abort.
1401 int reason = (mCurrentSession != null && mCurrentSession.isAborting()) ?
1402 CaptureFailure.REASON_FLUSHED :
1403 CaptureFailure.REASON_ERROR;
1404
1405 final CaptureFailure failure = new CaptureFailure(
1406 request,
1407 reason,
1408 /*dropped*/ mayHaveBuffers,
1409 requestId,
1410 frameNumber);
1411
1412 Runnable failureDispatch = new Runnable() {
1413 @Override
1414 public void run() {
1415 if (!CameraDeviceImpl.this.isClosed()){
1416 holder.getListener().onCaptureFailed(
1417 CameraDeviceImpl.this,
1418 request,
1419 failure);
1420 }
1421 }
1422 };
1423 holder.getHandler().post(failureDispatch);
1424
1425 // Fire onCaptureSequenceCompleted if appropriate
1426 if (DEBUG) {
1427 Log.v(TAG, String.format("got error frame %d", frameNumber));
1428 }
1429 mFrameNumberTracker.updateTracker(frameNumber, /*error*/true);
1430 checkAndFireSequenceComplete();
1431 }
1432
1433 } // public class CameraDeviceCallbacks
Igor Murashkin70725502013-06-25 20:27:06 +00001434
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001435 /**
Igor Murashkin0b27d342014-05-30 09:45:05 -07001436 * Default handler management.
1437 *
1438 * <p>
1439 * If handler is null, get the current thread's
1440 * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
1441 * </p>
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001442 */
Igor Murashkin0b27d342014-05-30 09:45:05 -07001443 static Handler checkHandler(Handler handler) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001444 if (handler == null) {
1445 Looper looper = Looper.myLooper();
1446 if (looper == null) {
1447 throw new IllegalArgumentException(
1448 "No handler given, and current thread has no looper!");
1449 }
1450 handler = new Handler(looper);
1451 }
1452 return handler;
1453 }
1454
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001455 /**
1456 * Default handler management, conditional on there being a listener.
1457 *
1458 * <p>If the listener isn't null, check the handler, otherwise pass it through.</p>
1459 */
1460 static <T> Handler checkHandler(Handler handler, T listener) {
1461 if (listener != null) {
1462 return checkHandler(handler);
1463 }
1464 return handler;
1465 }
1466
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001467 private void checkIfCameraClosedOrInError() throws CameraAccessException {
1468 if (mInError) {
1469 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
1470 "The camera device has encountered a serious error");
1471 }
Zhijun He7f4d3142013-07-23 07:54:38 -07001472 if (mRemoteDevice == null) {
1473 throw new IllegalStateException("CameraDevice was already closed");
1474 }
1475 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001476
Igor Murashkin49b2b132014-06-18 19:03:00 -07001477 /** Whether the camera device has started to close (may not yet have finished) */
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001478 private boolean isClosed() {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001479 return mClosing;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001480 }
Ruben Brunk57493682014-05-27 18:58:08 -07001481
1482 private CameraCharacteristics getCharacteristics() {
1483 return mCharacteristics;
1484 }
Igor Murashkin70725502013-06-25 20:27:06 +00001485}