blob: d75dfe6686d1eef29128c51cbc963e1a13e32787 [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 Murashkin57ea59b2013-08-23 16:55:57 -070044import java.util.HashSet;
Ruben Brunkdecfe952013-10-29 11:00:32 -070045import java.util.Iterator;
Igor Murashkin70725502013-06-25 20:27:06 +000046import java.util.List;
Jianing Weid2c3a822014-03-27 18:27:43 -070047import java.util.TreeSet;
Igor Murashkin70725502013-06-25 20:27:06 +000048
49/**
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070050 * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
Igor Murashkin70725502013-06-25 20:27:06 +000051 */
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -070052public class CameraDeviceImpl extends CameraDevice {
Igor Murashkin70725502013-06-25 20:27:06 +000053
54 private final String TAG;
Zhijun Heecb323e2013-07-31 09:40:27 -070055 private final boolean DEBUG;
Igor Murashkin70725502013-06-25 20:27:06 +000056
Ruben Brunkdecfe952013-10-29 11:00:32 -070057 private static final int REQUEST_ID_NONE = -1;
58
Igor Murashkin70725502013-06-25 20:27:06 +000059 // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
60 private ICameraDeviceUser mRemoteDevice;
61
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070062 // Lock to synchronize cross-thread access to device public interface
63 private final Object mInterfaceLock = new Object();
Igor Murashkin70725502013-06-25 20:27:06 +000064 private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
65
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070066 private final StateListener mDeviceListener;
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -070067 private volatile StateListenerKK mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070068 private final Handler mDeviceHandler;
69
Igor Murashkin49b2b132014-06-18 19:03:00 -070070 private volatile boolean mClosing = false;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -070071 private boolean mInError = false;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070072 private boolean mIdle = true;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070073
Igor Murashkin21547d62014-06-04 15:21:42 -070074 /** map request IDs to listener/request data */
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070075 private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
76 new SparseArray<CaptureListenerHolder>();
Igor Murashkin70725502013-06-25 20:27:06 +000077
Ruben Brunkdecfe952013-10-29 11:00:32 -070078 private int mRepeatingRequestId = REQUEST_ID_NONE;
79 private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>();
Igor Murashkin57ea59b2013-08-23 16:55:57 -070080 // Map stream IDs to Surfaces
81 private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
Igor Murashkin70725502013-06-25 20:27:06 +000082
83 private final String mCameraId;
Ruben Brunk57493682014-05-27 18:58:08 -070084 private final CameraCharacteristics mCharacteristics;
Zhijun He83159152014-07-16 11:32:59 -070085 private final int mTotalPartialCount;
Igor Murashkin70725502013-06-25 20:27:06 +000086
Jianing Weid2c3a822014-03-27 18:27:43 -070087 /**
88 * A list tracking request and its expected last frame.
89 * Updated when calling ICameraDeviceUser methods.
90 */
91 private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>>
92 mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>();
93
94 /**
95 * An object tracking received frame numbers.
96 * Updated when receiving callbacks from ICameraDeviceCallbacks.
97 */
98 private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
99
Igor Murashkin0b27d342014-05-30 09:45:05 -0700100 private CameraCaptureSessionImpl mCurrentSession;
101
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700102 // Runnables for all state transitions, except error, which needs the
103 // error code argument
104
105 private final Runnable mCallOnOpened = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700106 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700107 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700108 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700109 synchronized(mInterfaceLock) {
110 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700111
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700112 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700113 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700114 if (sessionListener != null) {
115 sessionListener.onOpened(CameraDeviceImpl.this);
116 }
117 mDeviceListener.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700118 }
119 };
120
121 private final Runnable mCallOnUnconfigured = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700122 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700123 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700124 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700125 synchronized(mInterfaceLock) {
126 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700127
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700128 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700129 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700130 if (sessionListener != null) {
131 sessionListener.onUnconfigured(CameraDeviceImpl.this);
132 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700133 }
134 };
135
136 private final Runnable mCallOnActive = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700137 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700138 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700139 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700140 synchronized(mInterfaceLock) {
141 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700142
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700143 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700144 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700145 if (sessionListener != null) {
146 sessionListener.onActive(CameraDeviceImpl.this);
147 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700148 }
149 };
150
151 private final Runnable mCallOnBusy = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700152 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700153 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700154 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700155 synchronized(mInterfaceLock) {
156 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700157
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700158 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700159 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700160 if (sessionListener != null) {
161 sessionListener.onBusy(CameraDeviceImpl.this);
162 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700163 }
164 };
165
166 private final Runnable mCallOnClosed = new Runnable() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700167 private boolean mClosedOnce = false;
168
Jianing Weid2c3a822014-03-27 18:27:43 -0700169 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700170 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700171 if (mClosedOnce) {
172 throw new AssertionError("Don't post #onClosed more than once");
173 }
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700174 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700175 synchronized(mInterfaceLock) {
176 sessionListener = mSessionStateListener;
177 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700178 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700179 sessionListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700180 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700181 mDeviceListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin49b2b132014-06-18 19:03:00 -0700182 mClosedOnce = true;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700183 }
184 };
185
186 private final Runnable mCallOnIdle = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700187 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700188 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700189 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700190 synchronized(mInterfaceLock) {
191 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700192
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700193 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700194 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700195 if (sessionListener != null) {
196 sessionListener.onIdle(CameraDeviceImpl.this);
197 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700198 }
199 };
200
201 private final Runnable mCallOnDisconnected = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700202 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700203 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700204 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700205 synchronized(mInterfaceLock) {
206 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700207
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700208 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700209 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700210 if (sessionListener != null) {
211 sessionListener.onDisconnected(CameraDeviceImpl.this);
212 }
213 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700214 }
215 };
216
Igor Murashkin21547d62014-06-04 15:21:42 -0700217 public CameraDeviceImpl(String cameraId, StateListener listener, Handler handler,
Ruben Brunk57493682014-05-27 18:58:08 -0700218 CameraCharacteristics characteristics) {
Zhijun He83159152014-07-16 11:32:59 -0700219 if (cameraId == null || listener == null || handler == null || characteristics == null) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700220 throw new IllegalArgumentException("Null argument given");
221 }
Igor Murashkin70725502013-06-25 20:27:06 +0000222 mCameraId = cameraId;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700223 mDeviceListener = listener;
224 mDeviceHandler = handler;
Ruben Brunk57493682014-05-27 18:58:08 -0700225 mCharacteristics = characteristics;
Eino-Ville Talvalab72d1ef2014-04-28 13:21:18 -0700226
227 final int MAX_TAG_LEN = 23;
228 String tag = String.format("CameraDevice-JV-%s", mCameraId);
229 if (tag.length() > MAX_TAG_LEN) {
230 tag = tag.substring(0, MAX_TAG_LEN);
231 }
232 TAG = tag;
Zhijun Heecb323e2013-07-31 09:40:27 -0700233 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Zhijun He83159152014-07-16 11:32:59 -0700234
235 Integer partialCount =
236 mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
237 if (partialCount == null) {
238 // 1 means partial result is not supported.
239 mTotalPartialCount = 1;
240 } else {
241 mTotalPartialCount = partialCount;
242 }
Igor Murashkin70725502013-06-25 20:27:06 +0000243 }
244
245 public CameraDeviceCallbacks getCallbacks() {
246 return mCallbacks;
247 }
248
Igor Murashkin70725502013-06-25 20:27:06 +0000249 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700250 synchronized(mInterfaceLock) {
251 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700252 // If setRemoteFailure already called, do nothing
253 if (mInError) return;
254
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700255 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
256
257 mDeviceHandler.post(mCallOnOpened);
258 mDeviceHandler.post(mCallOnUnconfigured);
259 }
Igor Murashkin70725502013-06-25 20:27:06 +0000260 }
261
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700262 /**
263 * Call to indicate failed connection to a remote camera device.
264 *
265 * <p>This places the camera device in the error state and informs the listener.
266 * Use in place of setRemoteDevice() when startup fails.</p>
267 */
268 public void setRemoteFailure(final CameraRuntimeException failure) {
269 int failureCode = StateListener.ERROR_CAMERA_DEVICE;
270 boolean failureIsError = true;
271
272 switch (failure.getReason()) {
273 case CameraAccessException.CAMERA_IN_USE:
274 failureCode = StateListener.ERROR_CAMERA_IN_USE;
275 break;
276 case CameraAccessException.MAX_CAMERAS_IN_USE:
277 failureCode = StateListener.ERROR_MAX_CAMERAS_IN_USE;
278 break;
279 case CameraAccessException.CAMERA_DISABLED:
280 failureCode = StateListener.ERROR_CAMERA_DISABLED;
281 break;
282 case CameraAccessException.CAMERA_DISCONNECTED:
283 failureIsError = false;
284 break;
285 case CameraAccessException.CAMERA_ERROR:
286 failureCode = StateListener.ERROR_CAMERA_DEVICE;
287 break;
288 default:
289 Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
290 break;
291 }
292 final int code = failureCode;
293 final boolean isError = failureIsError;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700294 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700295 mInError = true;
296 mDeviceHandler.post(new Runnable() {
Igor Murashkine1442202014-06-09 17:51:24 -0700297 @Override
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700298 public void run() {
299 if (isError) {
300 mDeviceListener.onError(CameraDeviceImpl.this, code);
301 } else {
302 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
303 }
304 }
305 });
306 }
307 }
308
Igor Murashkin70725502013-06-25 20:27:06 +0000309 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700310 public String getId() {
311 return mCameraId;
312 }
313
Igor Murashkin70725502013-06-25 20:27:06 +0000314 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700315 // Leave this here for backwards compatibility with older code using this directly
316 configureOutputsChecked(outputs);
317 }
318
319 /**
320 * Attempt to configure the outputs; the device goes to idle and then configures the
321 * new outputs if possible.
322 *
323 * <p>The configuration may gracefully fail, if there are too many outputs, if the formats
324 * are not supported, or if the sizes for that format is not supported. In this case this
325 * function will return {@code false} and the unconfigured callback will be fired.</p>
326 *
327 * <p>If the configuration succeeds (with 1 or more outputs), then the idle callback is fired.
328 * Unconfiguring the device always fires the idle callback.</p>
329 *
330 * @param outputs a list of one or more surfaces, or {@code null} to unconfigure
331 * @return whether or not the configuration was successful
332 *
333 * @throws CameraAccessException if there were any unexpected problems during configuration
334 */
335 public boolean configureOutputsChecked(List<Surface> outputs) throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700336 // Treat a null input the same an empty list
337 if (outputs == null) {
338 outputs = new ArrayList<Surface>();
339 }
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700340 boolean success = false;
341
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700342 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700343 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700344
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700345 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
346 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
347
348 // Determine which streams need to be created, which to be deleted
349 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
350 int streamId = mConfiguredOutputs.keyAt(i);
351 Surface s = mConfiguredOutputs.valueAt(i);
352
353 if (!outputs.contains(s)) {
354 deleteList.add(streamId);
355 } else {
356 addSet.remove(s); // Don't create a stream previously created
357 }
358 }
359
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700360 mDeviceHandler.post(mCallOnBusy);
361 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700362
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700363 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700364 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700365
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700366 mRemoteDevice.beginConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700367 // Delete all streams first (to free up HW resources)
368 for (Integer streamId : deleteList) {
369 mRemoteDevice.deleteStream(streamId);
370 mConfiguredOutputs.delete(streamId);
371 }
372
373 // Add all new streams
374 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000375 // TODO: remove width,height,format since we are ignoring
376 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700377 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
378 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000379 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700380
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700381 try {
382 mRemoteDevice.endConfigure();
383 }
384 catch (IllegalArgumentException e) {
385 // OK. camera service can reject stream config if it's not supported by HAL
386 // This is only the result of a programmer misusing the camera2 api.
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700387 Log.w(TAG, "Stream configuration failed");
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700388 return false;
389 }
390
391 success = true;
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700392 } catch (CameraRuntimeException e) {
393 if (e.getReason() == CAMERA_IN_USE) {
394 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700395 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700396 }
397
398 throw e.asChecked();
399 } catch (RemoteException e) {
400 // impossible
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700401 return false;
402 } finally {
403 if (success && outputs.size() > 0) {
404 mDeviceHandler.post(mCallOnIdle);
405 } else {
406 // Always return to the 'unconfigured' state if we didn't hit a fatal error
407 mDeviceHandler.post(mCallOnUnconfigured);
408 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700409 }
Igor Murashkin70725502013-06-25 20:27:06 +0000410 }
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700411
412 return success;
Igor Murashkin70725502013-06-25 20:27:06 +0000413 }
414
415 @Override
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700416 public void createCaptureSession(List<Surface> outputs,
417 CameraCaptureSession.StateListener listener, Handler handler)
418 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700419 synchronized(mInterfaceLock) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700420 if (DEBUG) {
421 Log.d(TAG, "createCaptureSession");
422 }
423
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700424 checkIfCameraClosedOrInError();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700425
Eino-Ville Talvalad3b85f62014-08-05 15:02:31 -0700426 // Notify current session that it's going away, before starting camera operations
427 // After this call completes, the session is not allowed to call into CameraDeviceImpl
428 if (mCurrentSession != null) {
429 mCurrentSession.replaceSessionClose();
430 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700431
432 // TODO: dont block for this
433 boolean configureSuccess = true;
434 CameraAccessException pendingException = null;
435 try {
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700436 configureSuccess = configureOutputsChecked(outputs); // and then block until IDLE
Igor Murashkin0b27d342014-05-30 09:45:05 -0700437 } catch (CameraAccessException e) {
438 configureSuccess = false;
439 pendingException = e;
Igor Murashkine1442202014-06-09 17:51:24 -0700440 if (DEBUG) {
441 Log.v(TAG, "createCaptureSession - failed with exception ", e);
442 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700443 }
444
445 // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
446 CameraCaptureSessionImpl newSession =
447 new CameraCaptureSessionImpl(outputs, listener, handler, this, mDeviceHandler,
448 configureSuccess);
449
Igor Murashkin0b27d342014-05-30 09:45:05 -0700450 // TODO: wait until current session closes, then create the new session
451 mCurrentSession = newSession;
452
453 if (pendingException != null) {
454 throw pendingException;
455 }
456
457 mSessionStateListener = mCurrentSession.getDeviceStateListener();
458 }
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700459 }
460
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700461 /**
462 * For use by backwards-compatibility code only.
463 */
464 public void setSessionListener(StateListenerKK sessionListener) {
465 synchronized(mInterfaceLock) {
466 mSessionStateListener = sessionListener;
467 }
468 }
469
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700470 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700471 public CaptureRequest.Builder createCaptureRequest(int templateType)
472 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700473 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700474 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000475
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700476 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000477
478 try {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700479 mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000480 } catch (CameraRuntimeException e) {
481 throw e.asChecked();
482 } catch (RemoteException e) {
483 // impossible
484 return null;
485 }
486
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700487 CaptureRequest.Builder builder =
488 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000489
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700490 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000491 }
492 }
493
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700494 public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000495 throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700496 if (DEBUG) {
497 Log.d(TAG, "calling capture");
498 }
499 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
500 requestList.add(request);
501 return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000502 }
503
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700504 public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700505 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700506 if (requests == null || requests.isEmpty()) {
507 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700508 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700509 return submitCaptureRequest(requests, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000510 }
511
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700512 /**
513 * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
514 * starting and stopping repeating request and flushing.
515 *
516 * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700517 * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700518 * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
519 * is added to the list mFrameNumberRequestPairs.</p>
520 *
521 * @param requestId the request ID of the current repeating request.
522 *
523 * @param lastFrameNumber last frame number returned from binder.
524 */
525 private void checkEarlyTriggerSequenceComplete(
526 final int requestId, final long lastFrameNumber) {
527 // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700528 // was never sent to HAL. Should trigger onCaptureSequenceAborted immediately.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700529 if (lastFrameNumber == CaptureListener.NO_FRAMES_CAPTURED) {
530 final CaptureListenerHolder holder;
531 int index = mCaptureListenerMap.indexOfKey(requestId);
532 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index) : null;
533 if (holder != null) {
534 mCaptureListenerMap.removeAt(index);
Jianing Weibaf0c652014-04-18 17:35:00 -0700535 if (DEBUG) {
536 Log.v(TAG, String.format(
537 "remove holder for requestId %d, "
538 + "because lastFrame is %d.",
539 requestId, lastFrameNumber));
540 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700541 }
542
543 if (holder != null) {
544 if (DEBUG) {
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700545 Log.v(TAG, "immediately trigger onCaptureSequenceAborted because"
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700546 + " request did not reach HAL");
547 }
548
549 Runnable resultDispatch = new Runnable() {
550 @Override
551 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700552 if (!CameraDeviceImpl.this.isClosed()) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700553 if (DEBUG) {
554 Log.d(TAG, String.format(
555 "early trigger sequence complete for request %d",
556 requestId));
557 }
558 if (lastFrameNumber < Integer.MIN_VALUE
559 || lastFrameNumber > Integer.MAX_VALUE) {
560 throw new AssertionError(lastFrameNumber + " cannot be cast to int");
561 }
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700562 holder.getListener().onCaptureSequenceAborted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700563 CameraDeviceImpl.this,
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700564 requestId);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700565 }
566 }
567 };
568 holder.getHandler().post(resultDispatch);
569 } else {
570 Log.w(TAG, String.format(
571 "did not register listener to request %d",
572 requestId));
573 }
574 } else {
575 mFrameNumberRequestPairs.add(
576 new SimpleEntry<Long, Integer>(lastFrameNumber,
577 requestId));
578 }
579 }
580
Jianing Weid2c3a822014-03-27 18:27:43 -0700581 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700582 Handler handler, boolean repeating) throws CameraAccessException {
583
584 // Need a valid handler, or current thread needs to have a looper, if
585 // listener is valid
Eino-Ville Talvala7875a882014-07-31 12:47:07 -0700586 handler = checkHandler(handler, listener);
Igor Murashkin70725502013-06-25 20:27:06 +0000587
Ruben Brunk7f2372b2014-07-02 11:05:08 -0700588 // Make sure that there all requests have at least 1 surface; all surfaces are non-null
589 for (CaptureRequest request : requestList) {
590 if (request.getTargets().isEmpty()) {
591 throw new IllegalArgumentException(
592 "Each request must have at least one Surface target");
593 }
594
595 for (Surface surface : request.getTargets()) {
596 if (surface == null) {
597 throw new IllegalArgumentException("Null Surface targets are not allowed");
598 }
599 }
600 }
601
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700602 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700603 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000604 int requestId;
605
Ruben Brunke73b41b2013-11-07 19:30:43 -0800606 if (repeating) {
607 stopRepeating();
608 }
609
Jianing Weid2c3a822014-03-27 18:27:43 -0700610 LongParcelable lastFrameNumberRef = new LongParcelable();
Igor Murashkin70725502013-06-25 20:27:06 +0000611 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700612 requestId = mRemoteDevice.submitRequestList(requestList, repeating,
613 /*out*/lastFrameNumberRef);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700614 if (DEBUG) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700615 Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
616 }
Igor Murashkin70725502013-06-25 20:27:06 +0000617 } catch (CameraRuntimeException e) {
618 throw e.asChecked();
619 } catch (RemoteException e) {
620 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700621 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000622 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700623
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700624 if (listener != null) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700625 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener,
626 requestList, handler, repeating));
Jianing Weibaf0c652014-04-18 17:35:00 -0700627 } else {
628 if (DEBUG) {
629 Log.d(TAG, "Listen for request " + requestId + " is null");
630 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700631 }
Igor Murashkin70725502013-06-25 20:27:06 +0000632
Jianing Weid2c3a822014-03-27 18:27:43 -0700633 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700634
Igor Murashkin70725502013-06-25 20:27:06 +0000635 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700636 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700637 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700638 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700639 mRepeatingRequestId = requestId;
Jianing Weid2c3a822014-03-27 18:27:43 -0700640 } else {
641 mFrameNumberRequestPairs.add(
642 new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
Igor Murashkin70725502013-06-25 20:27:06 +0000643 }
644
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700645 if (mIdle) {
646 mDeviceHandler.post(mCallOnActive);
647 }
648 mIdle = false;
649
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700650 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000651 }
652 }
653
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700654 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700655 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700656 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
657 requestList.add(request);
658 return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000659 }
660
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700661 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700662 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700663 if (requests == null || requests.isEmpty()) {
664 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700665 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700666 return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000667 }
668
Igor Murashkin70725502013-06-25 20:27:06 +0000669 public void stopRepeating() throws CameraAccessException {
670
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700671 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700672 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700673 if (mRepeatingRequestId != REQUEST_ID_NONE) {
674
675 int requestId = mRepeatingRequestId;
676 mRepeatingRequestId = REQUEST_ID_NONE;
677
678 // Queue for deletion after in-flight requests finish
Zhijun He1a9b6462014-03-31 16:11:33 -0700679 if (mCaptureListenerMap.get(requestId) != null) {
680 mRepeatingRequestIdDeletedList.add(requestId);
681 }
Igor Murashkin70725502013-06-25 20:27:06 +0000682
683 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700684 LongParcelable lastFrameNumberRef = new LongParcelable();
685 mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
686 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700687
688 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
689
Igor Murashkin70725502013-06-25 20:27:06 +0000690 } catch (CameraRuntimeException e) {
691 throw e.asChecked();
692 } catch (RemoteException e) {
693 // impossible
694 return;
695 }
696 }
697 }
698 }
699
Zhijun Hed842fcd2013-12-26 14:14:04 -0800700 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700701
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700702 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700703 checkIfCameraClosedOrInError();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700704
Ruben Brunkdecfe952013-10-29 11:00:32 -0700705 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700706 throw new IllegalStateException("Active repeating request ongoing");
707 }
Zhijun He7f4d3142013-07-23 07:54:38 -0700708 try {
709 mRemoteDevice.waitUntilIdle();
710 } catch (CameraRuntimeException e) {
711 throw e.asChecked();
712 } catch (RemoteException e) {
713 // impossible
714 return;
715 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700716 }
Igor Murashkin70725502013-06-25 20:27:06 +0000717 }
718
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700719 public void flush() throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700720 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700721 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700722
723 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvalac346bbf2014-08-27 17:05:29 -0700724
725 // If already idle, just do a busy->idle transition immediately, don't actually
726 // flush.
727 if (mIdle) {
728 mDeviceHandler.post(mCallOnIdle);
729 return;
730 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700731 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700732 LongParcelable lastFrameNumberRef = new LongParcelable();
733 mRemoteDevice.flush(/*out*/lastFrameNumberRef);
734 if (mRepeatingRequestId != REQUEST_ID_NONE) {
735 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700736 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700737 mRepeatingRequestId = REQUEST_ID_NONE;
738 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700739 } catch (CameraRuntimeException e) {
740 throw e.asChecked();
741 } catch (RemoteException e) {
742 // impossible
743 return;
744 }
745 }
746 }
747
748 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700749 public void close() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700750 synchronized (mInterfaceLock) {
Igor Murashkin70725502013-06-25 20:27:06 +0000751 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700752 if (mRemoteDevice != null) {
753 mRemoteDevice.disconnect();
754 }
Igor Murashkin70725502013-06-25 20:27:06 +0000755 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700756 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000757 } catch (RemoteException e) {
758 // impossible
759 }
760
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700761 // Only want to fire the onClosed callback once;
762 // either a normal close where the remote device is valid
763 // or a close after a startup error (no remote device but in error state)
764 if (mRemoteDevice != null || mInError) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700765 mDeviceHandler.post(mCallOnClosed);
766 }
Igor Murashkin70725502013-06-25 20:27:06 +0000767
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700768 mRemoteDevice = null;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700769 mInError = false;
Igor Murashkin70725502013-06-25 20:27:06 +0000770 }
771 }
772
773 @Override
774 protected void finalize() throws Throwable {
775 try {
776 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000777 }
778 finally {
779 super.finalize();
780 }
781 }
782
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700783 /**
784 * <p>A listener for tracking the progress of a {@link CaptureRequest}
785 * submitted to the camera device.</p>
786 *
787 */
788 public static abstract class CaptureListener {
789
790 /**
791 * This constant is used to indicate that no images were captured for
792 * the request.
793 *
794 * @hide
795 */
796 public static final int NO_FRAMES_CAPTURED = -1;
797
798 /**
799 * This method is called when the camera device has started capturing
800 * the output image for the request, at the beginning of image exposure.
801 *
802 * @see android.media.MediaActionSound
803 */
804 public void onCaptureStarted(CameraDevice camera,
805 CaptureRequest request, long timestamp) {
806 // default empty implementation
807 }
808
809 /**
810 * This method is called when some results from an image capture are
811 * available.
812 *
813 * @hide
814 */
815 public void onCapturePartial(CameraDevice camera,
816 CaptureRequest request, CaptureResult result) {
817 // default empty implementation
818 }
819
820 /**
821 * This method is called when an image capture makes partial forward progress; some
822 * (but not all) results from an image capture are available.
823 *
824 */
825 public void onCaptureProgressed(CameraDevice camera,
826 CaptureRequest request, CaptureResult partialResult) {
827 // default empty implementation
828 }
829
830 /**
831 * This method is called when an image capture has fully completed and all the
832 * result metadata is available.
833 */
834 public void onCaptureCompleted(CameraDevice camera,
835 CaptureRequest request, TotalCaptureResult result) {
836 // default empty implementation
837 }
838
839 /**
840 * This method is called instead of {@link #onCaptureCompleted} when the
841 * camera device failed to produce a {@link CaptureResult} for the
842 * request.
843 */
844 public void onCaptureFailed(CameraDevice camera,
845 CaptureRequest request, CaptureFailure failure) {
846 // default empty implementation
847 }
848
849 /**
850 * This method is called independently of the others in CaptureListener,
851 * when a capture sequence finishes and all {@link CaptureResult}
852 * or {@link CaptureFailure} for it have been returned via this listener.
853 */
854 public void onCaptureSequenceCompleted(CameraDevice camera,
855 int sequenceId, long frameNumber) {
856 // default empty implementation
857 }
858
859 /**
860 * This method is called independently of the others in CaptureListener,
861 * when a capture sequence aborts before any {@link CaptureResult}
862 * or {@link CaptureFailure} for it have been returned via this listener.
863 */
864 public void onCaptureSequenceAborted(CameraDevice camera,
865 int sequenceId) {
866 // default empty implementation
867 }
868 }
869
870 /**
871 * A listener for notifications about the state of a camera device, adding in the callbacks that
872 * were part of the earlier KK API design, but now only used internally.
873 */
874 public static abstract class StateListenerKK extends StateListener {
875 /**
876 * The method called when a camera device has no outputs configured.
877 *
878 */
879 public void onUnconfigured(CameraDevice camera) {
880 // Default empty implementation
881 }
882
883 /**
884 * The method called when a camera device begins processing
885 * {@link CaptureRequest capture requests}.
886 *
887 */
888 public void onActive(CameraDevice camera) {
889 // Default empty implementation
890 }
891
892 /**
893 * The method called when a camera device is busy.
894 *
895 */
896 public void onBusy(CameraDevice camera) {
897 // Default empty implementation
898 }
899
900 /**
901 * The method called when a camera device has finished processing all
902 * submitted capture requests and has reached an idle state.
903 *
904 */
905 public void onIdle(CameraDevice camera) {
906 // Default empty implementation
907 }
908 }
909
Igor Murashkin70725502013-06-25 20:27:06 +0000910 static class CaptureListenerHolder {
911
912 private final boolean mRepeating;
913 private final CaptureListener mListener;
Jianing Weid2c3a822014-03-27 18:27:43 -0700914 private final List<CaptureRequest> mRequestList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700915 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000916
Jianing Weid2c3a822014-03-27 18:27:43 -0700917 CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList,
918 Handler handler, boolean repeating) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700919 if (listener == null || handler == null) {
920 throw new UnsupportedOperationException(
921 "Must have a valid handler and a valid listener");
922 }
Igor Murashkin70725502013-06-25 20:27:06 +0000923 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700924 mHandler = handler;
Jianing Weid2c3a822014-03-27 18:27:43 -0700925 mRequestList = new ArrayList<CaptureRequest>(requestList);
Igor Murashkin70725502013-06-25 20:27:06 +0000926 mListener = listener;
927 }
928
929 public boolean isRepeating() {
930 return mRepeating;
931 }
932
933 public CaptureListener getListener() {
934 return mListener;
935 }
936
Jianing Weid2c3a822014-03-27 18:27:43 -0700937 public CaptureRequest getRequest(int subsequenceId) {
938 if (subsequenceId >= mRequestList.size()) {
939 throw new IllegalArgumentException(
940 String.format(
941 "Requested subsequenceId %d is larger than request list size %d.",
942 subsequenceId, mRequestList.size()));
943 } else {
944 if (subsequenceId < 0) {
945 throw new IllegalArgumentException(String.format(
946 "Requested subsequenceId %d is negative", subsequenceId));
947 } else {
948 return mRequestList.get(subsequenceId);
949 }
950 }
951 }
952
Igor Murashkin70725502013-06-25 20:27:06 +0000953 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700954 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +0000955 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700956
957 public Handler getHandler() {
958 return mHandler;
959 }
960
Igor Murashkin70725502013-06-25 20:27:06 +0000961 }
962
Jianing Weid2c3a822014-03-27 18:27:43 -0700963 /**
964 * This class tracks the last frame number for submitted requests.
965 */
966 public class FrameNumberTracker {
967
968 private long mCompletedFrameNumber = -1;
969 private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
970
971 private void update() {
972 Iterator<Long> iter = mFutureErrorSet.iterator();
973 while (iter.hasNext()) {
974 long errorFrameNumber = iter.next();
975 if (errorFrameNumber == mCompletedFrameNumber + 1) {
976 mCompletedFrameNumber++;
977 iter.remove();
978 } else {
979 break;
980 }
981 }
982 }
983
984 /**
985 * This function is called every time when a result or an error is received.
986 * @param frameNumber: the frame number corresponding to the result or error
987 * @param isError: true if it is an error, false if it is not an error
988 */
989 public void updateTracker(long frameNumber, boolean isError) {
990 if (isError) {
991 mFutureErrorSet.add(frameNumber);
992 } else {
993 /**
994 * HAL cannot send an OnResultReceived for frame N unless it knows for
995 * sure that all frames prior to N have either errored out or completed.
996 * So if the current frame is not an error, then all previous frames
997 * should have arrived. The following line checks whether this holds.
998 */
999 if (frameNumber != mCompletedFrameNumber + 1) {
Zhijun He22589b42014-05-01 10:37:36 -07001000 Log.e(TAG, String.format(
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001001 "result frame number %d comes out of order, should be %d + 1",
1002 frameNumber, mCompletedFrameNumber));
Jianing Weid2c3a822014-03-27 18:27:43 -07001003 }
1004 mCompletedFrameNumber++;
1005 }
1006 update();
1007 }
1008
1009 public long getCompletedFrameNumber() {
1010 return mCompletedFrameNumber;
1011 }
1012
1013 }
1014
1015 private void checkAndFireSequenceComplete() {
1016 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
1017 Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
1018 while (iter.hasNext()) {
1019 final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
1020 if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
1021
1022 // remove request from mCaptureListenerMap
1023 final int requestId = frameNumberRequestPair.getValue();
1024 final CaptureListenerHolder holder;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001025 synchronized(mInterfaceLock) {
1026 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001027 Log.w(TAG, "Camera closed while checking sequences");
1028 return;
1029 }
1030
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001031 int index = mCaptureListenerMap.indexOfKey(requestId);
1032 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index)
Jianing Weid2c3a822014-03-27 18:27:43 -07001033 : null;
1034 if (holder != null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001035 mCaptureListenerMap.removeAt(index);
1036 if (DEBUG) {
1037 Log.v(TAG, String.format(
1038 "remove holder for requestId %d, "
1039 + "because lastFrame %d is <= %d",
1040 requestId, frameNumberRequestPair.getKey(),
1041 completedFrameNumber));
1042 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001043 }
1044 }
1045 iter.remove();
1046
1047 // Call onCaptureSequenceCompleted
1048 if (holder != null) {
1049 Runnable resultDispatch = new Runnable() {
1050 @Override
1051 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001052 if (!CameraDeviceImpl.this.isClosed()){
Jianing Weid2c3a822014-03-27 18:27:43 -07001053 if (DEBUG) {
1054 Log.d(TAG, String.format(
1055 "fire sequence complete for request %d",
1056 requestId));
1057 }
1058
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001059 long lastFrameNumber = frameNumberRequestPair.getKey();
1060 if (lastFrameNumber < Integer.MIN_VALUE
1061 || lastFrameNumber > Integer.MAX_VALUE) {
1062 throw new AssertionError(lastFrameNumber
1063 + " cannot be cast to int");
1064 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001065 holder.getListener().onCaptureSequenceCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -07001066 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -07001067 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -07001068 lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -07001069 }
1070 }
1071 };
1072 holder.getHandler().post(resultDispatch);
1073 }
1074
1075 }
1076 }
1077 }
1078
Zhijun Heecb323e2013-07-31 09:40:27 -07001079 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +00001080
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001081 //
1082 // Constants below need to be kept up-to-date with
1083 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
1084 //
1085
1086 //
1087 // Error codes for onCameraError
1088 //
1089
1090 /**
1091 * Camera has been disconnected
1092 */
1093 static final int ERROR_CAMERA_DISCONNECTED = 0;
1094
1095 /**
1096 * Camera has encountered a device-level error
1097 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
1098 */
1099 static final int ERROR_CAMERA_DEVICE = 1;
1100
1101 /**
1102 * Camera has encountered a service-level error
1103 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
1104 */
1105 static final int ERROR_CAMERA_SERVICE = 2;
1106
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001107 /**
1108 * Camera has encountered an error processing a single request.
1109 */
1110 static final int ERROR_CAMERA_REQUEST = 3;
1111
1112 /**
1113 * Camera has encountered an error producing metadata for a single capture
1114 */
1115 static final int ERROR_CAMERA_RESULT = 4;
1116
1117 /**
1118 * Camera has encountered an error producing an image buffer for a single capture
1119 */
1120 static final int ERROR_CAMERA_BUFFER = 5;
1121
Igor Murashkin70725502013-06-25 20:27:06 +00001122 @Override
1123 public IBinder asBinder() {
1124 return this;
1125 }
1126
Igor Murashkin70725502013-06-25 20:27:06 +00001127 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001128 public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) {
1129 if (DEBUG) {
1130 Log.d(TAG, String.format(
1131 "Device error received, code %d, frame number %d, request ID %d, subseq ID %d",
1132 errorCode, resultExtras.getFrameNumber(), resultExtras.getRequestId(),
1133 resultExtras.getSubsequenceId()));
1134 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001135
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001136 synchronized(mInterfaceLock) {
1137 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001138 return; // Camera already closed
1139 }
1140
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001141 switch (errorCode) {
1142 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001143 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnDisconnected);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001144 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001145 default:
1146 Log.e(TAG, "Unknown error from camera device: " + errorCode);
1147 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001148 case ERROR_CAMERA_DEVICE:
1149 case ERROR_CAMERA_SERVICE:
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001150 mInError = true;
1151 Runnable r = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -07001152 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001153 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001154 if (!CameraDeviceImpl.this.isClosed()) {
1155 mDeviceListener.onError(CameraDeviceImpl.this, errorCode);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001156 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001157 }
1158 };
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001159 CameraDeviceImpl.this.mDeviceHandler.post(r);
1160 break;
1161 case ERROR_CAMERA_REQUEST:
1162 case ERROR_CAMERA_RESULT:
1163 case ERROR_CAMERA_BUFFER:
1164 onCaptureErrorLocked(errorCode, resultExtras);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001165 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001166 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001167 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001168 }
1169
1170 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001171 public void onDeviceIdle() {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001172 if (DEBUG) {
1173 Log.d(TAG, "Camera now idle");
1174 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001175 synchronized(mInterfaceLock) {
1176 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07001177
Igor Murashkin21547d62014-06-04 15:21:42 -07001178 if (!CameraDeviceImpl.this.mIdle) {
1179 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnIdle);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001180 }
Igor Murashkin21547d62014-06-04 15:21:42 -07001181 CameraDeviceImpl.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001182 }
1183 }
1184
1185 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001186 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
1187 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001188 if (DEBUG) {
1189 Log.d(TAG, "Capture started for id " + requestId);
1190 }
1191 final CaptureListenerHolder holder;
1192
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001193 synchronized(mInterfaceLock) {
1194 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07001195
1196 // Get the listener for this frame ID, if there is one
Igor Murashkin21547d62014-06-04 15:21:42 -07001197 holder = CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001198
Igor Murashkin49b2b132014-06-18 19:03:00 -07001199 if (holder == null) {
1200 return;
1201 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001202
Igor Murashkin49b2b132014-06-18 19:03:00 -07001203 if (isClosed()) return;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001204
Igor Murashkin49b2b132014-06-18 19:03:00 -07001205 // Dispatch capture start notice
1206 holder.getHandler().post(
1207 new Runnable() {
1208 @Override
1209 public void run() {
1210 if (!CameraDeviceImpl.this.isClosed()) {
1211 holder.getListener().onCaptureStarted(
1212 CameraDeviceImpl.this,
1213 holder.getRequest(resultExtras.getSubsequenceId()),
1214 timestamp);
1215 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001216 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001217 });
1218
1219 }
Igor Murashkin70725502013-06-25 20:27:06 +00001220 }
1221
1222 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001223 public void onResultReceived(CameraMetadataNative result,
1224 CaptureResultExtras resultExtras) throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -07001225
Jianing Weid2c3a822014-03-27 18:27:43 -07001226 int requestId = resultExtras.getRequestId();
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001227 long frameNumber = resultExtras.getFrameNumber();
1228
Zhijun Heecb323e2013-07-31 09:40:27 -07001229 if (DEBUG) {
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001230 Log.v(TAG, "Received result frame " + frameNumber + " for id "
Jianing Weibaf0c652014-04-18 17:35:00 -07001231 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -07001232 }
Ruben Brunk57493682014-05-27 18:58:08 -07001233
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001234 synchronized(mInterfaceLock) {
1235 if (mRemoteDevice == null) return; // Camera already closed
Ruben Brunk57493682014-05-27 18:58:08 -07001236
Igor Murashkin49b2b132014-06-18 19:03:00 -07001237 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
1238 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
1239 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
Ruben Brunk57493682014-05-27 18:58:08 -07001240
Igor Murashkin49b2b132014-06-18 19:03:00 -07001241 final CaptureListenerHolder holder =
1242 CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +00001243
Zhijun He83159152014-07-16 11:32:59 -07001244 boolean isPartialResult =
1245 (resultExtras.getPartialResultCount() < mTotalPartialCount);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001246
Igor Murashkin49b2b132014-06-18 19:03:00 -07001247 // Update tracker (increment counter) when it's not a partial result.
Zhijun He83159152014-07-16 11:32:59 -07001248 if (!isPartialResult) {
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001249 mFrameNumberTracker.updateTracker(frameNumber,
Igor Murashkin49b2b132014-06-18 19:03:00 -07001250 /*error*/false);
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001251 }
Igor Murashkin70725502013-06-25 20:27:06 +00001252
Igor Murashkin49b2b132014-06-18 19:03:00 -07001253 // Check if we have a listener for this
1254 if (holder == null) {
1255 if (DEBUG) {
1256 Log.d(TAG,
1257 "holder is null, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001258 + frameNumber);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001259 }
1260 return;
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001261 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001262
Igor Murashkin49b2b132014-06-18 19:03:00 -07001263 if (isClosed()) {
1264 if (DEBUG) {
1265 Log.d(TAG,
1266 "camera is closed, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001267 + frameNumber);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001268 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001269 return;
1270 }
Igor Murashkindb075af2014-05-21 10:07:08 -07001271
Igor Murashkin49b2b132014-06-18 19:03:00 -07001272 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
1273
Igor Murashkin49b2b132014-06-18 19:03:00 -07001274 Runnable resultDispatch = null;
1275
1276 // Either send a partial result or the final capture completed result
Zhijun He83159152014-07-16 11:32:59 -07001277 if (isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001278 final CaptureResult resultAsCapture =
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001279 new CaptureResult(result, request, resultExtras);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001280
1281 // Partial result
1282 resultDispatch = new Runnable() {
1283 @Override
1284 public void run() {
1285 if (!CameraDeviceImpl.this.isClosed()){
Zhijun Hefac77c42014-07-18 14:20:48 -07001286 holder.getListener().onCaptureProgressed(
Igor Murashkin49b2b132014-06-18 19:03:00 -07001287 CameraDeviceImpl.this,
1288 request,
1289 resultAsCapture);
1290 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001291 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001292 };
1293 } else {
1294 final TotalCaptureResult resultAsCapture =
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001295 new TotalCaptureResult(result, request, resultExtras);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001296
Igor Murashkin49b2b132014-06-18 19:03:00 -07001297 // Final capture result
1298 resultDispatch = new Runnable() {
1299 @Override
1300 public void run() {
1301 if (!CameraDeviceImpl.this.isClosed()){
1302 holder.getListener().onCaptureCompleted(
1303 CameraDeviceImpl.this,
1304 request,
1305 resultAsCapture);
1306 }
1307 }
1308 };
1309 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001310
Igor Murashkin49b2b132014-06-18 19:03:00 -07001311 holder.getHandler().post(resultDispatch);
1312
1313 // Fire onCaptureSequenceCompleted
Zhijun He83159152014-07-16 11:32:59 -07001314 if (!isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001315 checkAndFireSequenceComplete();
1316 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001317 }
Igor Murashkin70725502013-06-25 20:27:06 +00001318 }
1319
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001320 /**
1321 * Called by onDeviceError for handling single-capture failures.
1322 */
1323 private void onCaptureErrorLocked(int errorCode, CaptureResultExtras resultExtras) {
1324
1325 final int requestId = resultExtras.getRequestId();
1326 final int subsequenceId = resultExtras.getSubsequenceId();
1327 final long frameNumber = resultExtras.getFrameNumber();
1328 final CaptureListenerHolder holder =
1329 CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
1330
1331 final CaptureRequest request = holder.getRequest(subsequenceId);
1332
1333 // No way to report buffer errors right now
1334 if (errorCode == ERROR_CAMERA_BUFFER) {
1335 Log.e(TAG, String.format("Lost output buffer reported for frame %d", frameNumber));
1336 return;
1337 }
1338
1339 boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
1340
1341 // This is only approximate - exact handling needs the camera service and HAL to
1342 // disambiguate between request failures to due abort and due to real errors.
1343 // For now, assume that if the session believes we're mid-abort, then the error
1344 // is due to abort.
1345 int reason = (mCurrentSession != null && mCurrentSession.isAborting()) ?
1346 CaptureFailure.REASON_FLUSHED :
1347 CaptureFailure.REASON_ERROR;
1348
1349 final CaptureFailure failure = new CaptureFailure(
1350 request,
1351 reason,
1352 /*dropped*/ mayHaveBuffers,
1353 requestId,
1354 frameNumber);
1355
1356 Runnable failureDispatch = new Runnable() {
1357 @Override
1358 public void run() {
1359 if (!CameraDeviceImpl.this.isClosed()){
1360 holder.getListener().onCaptureFailed(
1361 CameraDeviceImpl.this,
1362 request,
1363 failure);
1364 }
1365 }
1366 };
1367 holder.getHandler().post(failureDispatch);
1368
1369 // Fire onCaptureSequenceCompleted if appropriate
1370 if (DEBUG) {
1371 Log.v(TAG, String.format("got error frame %d", frameNumber));
1372 }
1373 mFrameNumberTracker.updateTracker(frameNumber, /*error*/true);
1374 checkAndFireSequenceComplete();
1375 }
1376
1377 } // public class CameraDeviceCallbacks
Igor Murashkin70725502013-06-25 20:27:06 +00001378
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001379 /**
Igor Murashkin0b27d342014-05-30 09:45:05 -07001380 * Default handler management.
1381 *
1382 * <p>
1383 * If handler is null, get the current thread's
1384 * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
1385 * </p>
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001386 */
Igor Murashkin0b27d342014-05-30 09:45:05 -07001387 static Handler checkHandler(Handler handler) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001388 if (handler == null) {
1389 Looper looper = Looper.myLooper();
1390 if (looper == null) {
1391 throw new IllegalArgumentException(
1392 "No handler given, and current thread has no looper!");
1393 }
1394 handler = new Handler(looper);
1395 }
1396 return handler;
1397 }
1398
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001399 /**
1400 * Default handler management, conditional on there being a listener.
1401 *
1402 * <p>If the listener isn't null, check the handler, otherwise pass it through.</p>
1403 */
1404 static <T> Handler checkHandler(Handler handler, T listener) {
1405 if (listener != null) {
1406 return checkHandler(handler);
1407 }
1408 return handler;
1409 }
1410
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001411 private void checkIfCameraClosedOrInError() throws CameraAccessException {
1412 if (mInError) {
1413 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
1414 "The camera device has encountered a serious error");
1415 }
Zhijun He7f4d3142013-07-23 07:54:38 -07001416 if (mRemoteDevice == null) {
1417 throw new IllegalStateException("CameraDevice was already closed");
1418 }
1419 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001420
Igor Murashkin49b2b132014-06-18 19:03:00 -07001421 /** Whether the camera device has started to close (may not yet have finished) */
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001422 private boolean isClosed() {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001423 return mClosing;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001424 }
Ruben Brunk57493682014-05-27 18:58:08 -07001425
1426 private CameraCharacteristics getCharacteristics() {
1427 return mCharacteristics;
1428 }
Igor Murashkin70725502013-06-25 20:27:06 +00001429}