blob: e9d4b0f9d65288e1cd204b9b2835d8ade3f8ed22 [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;
24import android.hardware.camera2.CameraManager;
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;
27import android.hardware.camera2.ICameraDeviceCallbacks;
28import android.hardware.camera2.ICameraDeviceUser;
Igor Murashkindb075af2014-05-21 10:07:08 -070029import android.hardware.camera2.TotalCaptureResult;
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -070030import android.hardware.camera2.utils.CameraBinderDecorator;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070031import android.hardware.camera2.utils.CameraRuntimeException;
Igor Murashkin9c595172014-05-12 13:56:20 -070032import android.hardware.camera2.utils.LongParcelable;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070033import android.os.Handler;
Ruben Brunkdecfe952013-10-29 11:00:32 -070034import android.os.IBinder;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070035import android.os.Looper;
Ruben Brunkdecfe952013-10-29 11:00:32 -070036import android.os.RemoteException;
Igor Murashkin70725502013-06-25 20:27:06 +000037import android.util.Log;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070038import android.util.SparseArray;
Igor Murashkin70725502013-06-25 20:27:06 +000039import android.view.Surface;
40
Jianing Weid2c3a822014-03-27 18:27:43 -070041import java.util.AbstractMap.SimpleEntry;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070042import java.util.ArrayList;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070043import java.util.HashSet;
Ruben Brunkdecfe952013-10-29 11:00:32 -070044import java.util.Iterator;
Igor Murashkin70725502013-06-25 20:27:06 +000045import java.util.List;
Jianing Weid2c3a822014-03-27 18:27:43 -070046import java.util.TreeSet;
Igor Murashkin70725502013-06-25 20:27:06 +000047
48/**
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070049 * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
Igor Murashkin70725502013-06-25 20:27:06 +000050 */
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070051public class CameraDevice implements android.hardware.camera2.CameraDevice {
Igor Murashkin70725502013-06-25 20:27:06 +000052
53 private final String TAG;
Zhijun Heecb323e2013-07-31 09:40:27 -070054 private final boolean DEBUG;
Igor Murashkin70725502013-06-25 20:27:06 +000055
Ruben Brunkdecfe952013-10-29 11:00:32 -070056 private static final int REQUEST_ID_NONE = -1;
57
Igor Murashkin70725502013-06-25 20:27:06 +000058 // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
59 private ICameraDeviceUser mRemoteDevice;
60
61 private final Object mLock = new Object();
62 private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
63
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070064 private final StateListener mDeviceListener;
Igor Murashkin0b27d342014-05-30 09:45:05 -070065 private volatile StateListener mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070066 private final Handler mDeviceHandler;
67
68 private boolean mIdle = true;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070069
70 private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
71 new SparseArray<CaptureListenerHolder>();
Igor Murashkin70725502013-06-25 20:27:06 +000072
Ruben Brunkdecfe952013-10-29 11:00:32 -070073 private int mRepeatingRequestId = REQUEST_ID_NONE;
74 private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>();
Igor Murashkin57ea59b2013-08-23 16:55:57 -070075 // Map stream IDs to Surfaces
76 private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
Igor Murashkin70725502013-06-25 20:27:06 +000077
78 private final String mCameraId;
Ruben Brunk57493682014-05-27 18:58:08 -070079 private final CameraCharacteristics mCharacteristics;
Igor Murashkin70725502013-06-25 20:27:06 +000080
Jianing Weid2c3a822014-03-27 18:27:43 -070081 /**
82 * A list tracking request and its expected last frame.
83 * Updated when calling ICameraDeviceUser methods.
84 */
85 private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>>
86 mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>();
87
88 /**
89 * An object tracking received frame numbers.
90 * Updated when receiving callbacks from ICameraDeviceCallbacks.
91 */
92 private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
93
Igor Murashkin0b27d342014-05-30 09:45:05 -070094 private CameraCaptureSessionImpl mCurrentSession;
95
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070096 // Runnables for all state transitions, except error, which needs the
97 // error code argument
98
99 private final Runnable mCallOnOpened = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700100 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700101 public void run() {
102 if (!CameraDevice.this.isClosed()) {
103 mDeviceListener.onOpened(CameraDevice.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700104 StateListener sessionListener = mSessionStateListener;
105 if (sessionListener != null) {
106 sessionListener.onOpened(CameraDevice.this);
107 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700108 }
109 }
110 };
111
112 private final Runnable mCallOnUnconfigured = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700113 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700114 public void run() {
115 if (!CameraDevice.this.isClosed()) {
116 mDeviceListener.onUnconfigured(CameraDevice.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700117 StateListener sessionListener = mSessionStateListener;
118 if (sessionListener != null) {
119 sessionListener.onUnconfigured(CameraDevice.this);
120 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700121 }
122 }
123 };
124
125 private final Runnable mCallOnActive = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700126 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700127 public void run() {
128 if (!CameraDevice.this.isClosed()) {
129 mDeviceListener.onActive(CameraDevice.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700130 StateListener sessionListener = mSessionStateListener;
131 if (sessionListener != null) {
132 sessionListener.onActive(CameraDevice.this);
133 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700134 }
135 }
136 };
137
138 private final Runnable mCallOnBusy = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700139 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700140 public void run() {
141 if (!CameraDevice.this.isClosed()) {
142 mDeviceListener.onBusy(CameraDevice.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700143 StateListener sessionListener = mSessionStateListener;
144 if (sessionListener != null) {
145 sessionListener.onBusy(CameraDevice.this);
146 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700147 }
148 }
149 };
150
151 private final Runnable mCallOnClosed = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700152 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700153 public void run() {
Zhijun He2db56022014-01-02 15:12:00 -0800154 mDeviceListener.onClosed(CameraDevice.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700155 StateListener sessionListener = mSessionStateListener;
156 if (sessionListener != null) {
157 sessionListener.onClosed(CameraDevice.this);
158 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700159 }
160 };
161
162 private final Runnable mCallOnIdle = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700163 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700164 public void run() {
165 if (!CameraDevice.this.isClosed()) {
166 mDeviceListener.onIdle(CameraDevice.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700167 StateListener sessionListener = mSessionStateListener;
168 if (sessionListener != null) {
169 sessionListener.onIdle(CameraDevice.this);
170 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700171 }
172 }
173 };
174
175 private final Runnable mCallOnDisconnected = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700176 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700177 public void run() {
178 if (!CameraDevice.this.isClosed()) {
179 mDeviceListener.onDisconnected(CameraDevice.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700180 StateListener sessionListener = mSessionStateListener;
181 if (sessionListener != null) {
182 sessionListener.onDisconnected(CameraDevice.this);
183 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700184 }
185 }
186 };
187
Ruben Brunk57493682014-05-27 18:58:08 -0700188 public CameraDevice(String cameraId, StateListener listener, Handler handler,
189 CameraCharacteristics characteristics) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700190 if (cameraId == null || listener == null || handler == null) {
191 throw new IllegalArgumentException("Null argument given");
192 }
Igor Murashkin70725502013-06-25 20:27:06 +0000193 mCameraId = cameraId;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700194 mDeviceListener = listener;
195 mDeviceHandler = handler;
Ruben Brunk57493682014-05-27 18:58:08 -0700196 mCharacteristics = characteristics;
Eino-Ville Talvalab72d1ef2014-04-28 13:21:18 -0700197
198 final int MAX_TAG_LEN = 23;
199 String tag = String.format("CameraDevice-JV-%s", mCameraId);
200 if (tag.length() > MAX_TAG_LEN) {
201 tag = tag.substring(0, MAX_TAG_LEN);
202 }
203 TAG = tag;
Zhijun Heecb323e2013-07-31 09:40:27 -0700204 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Igor Murashkin70725502013-06-25 20:27:06 +0000205 }
206
207 public CameraDeviceCallbacks getCallbacks() {
208 return mCallbacks;
209 }
210
Igor Murashkin70725502013-06-25 20:27:06 +0000211 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -0700212 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700213 synchronized(mLock) {
214 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
215
216 mDeviceHandler.post(mCallOnOpened);
217 mDeviceHandler.post(mCallOnUnconfigured);
218 }
Igor Murashkin70725502013-06-25 20:27:06 +0000219 }
220
221 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700222 public String getId() {
223 return mCameraId;
224 }
225
226 @Override
Igor Murashkin70725502013-06-25 20:27:06 +0000227 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700228 // Treat a null input the same an empty list
229 if (outputs == null) {
230 outputs = new ArrayList<Surface>();
231 }
Igor Murashkin70725502013-06-25 20:27:06 +0000232 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700233 checkIfCameraClosed();
234
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700235 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
236 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
237
238 // Determine which streams need to be created, which to be deleted
239 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
240 int streamId = mConfiguredOutputs.keyAt(i);
241 Surface s = mConfiguredOutputs.valueAt(i);
242
243 if (!outputs.contains(s)) {
244 deleteList.add(streamId);
245 } else {
246 addSet.remove(s); // Don't create a stream previously created
247 }
248 }
249
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700250 mDeviceHandler.post(mCallOnBusy);
251 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700252
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700253 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700254 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700255
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700256 mRemoteDevice.beginConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700257 // Delete all streams first (to free up HW resources)
258 for (Integer streamId : deleteList) {
259 mRemoteDevice.deleteStream(streamId);
260 mConfiguredOutputs.delete(streamId);
261 }
262
263 // Add all new streams
264 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000265 // TODO: remove width,height,format since we are ignoring
266 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700267 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
268 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000269 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700270
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700271 mRemoteDevice.endConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700272 } catch (CameraRuntimeException e) {
273 if (e.getReason() == CAMERA_IN_USE) {
274 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700275 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700276 }
277
278 throw e.asChecked();
279 } catch (RemoteException e) {
280 // impossible
281 return;
Igor Murashkin70725502013-06-25 20:27:06 +0000282 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700283
284 if (outputs.size() > 0) {
285 mDeviceHandler.post(mCallOnIdle);
286 } else {
287 mDeviceHandler.post(mCallOnUnconfigured);
288 }
Igor Murashkin70725502013-06-25 20:27:06 +0000289 }
290 }
291
292 @Override
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700293 public void createCaptureSession(List<Surface> outputs,
294 CameraCaptureSession.StateListener listener, Handler handler)
295 throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700296 synchronized (mLock) {
297 if (DEBUG) {
298 Log.d(TAG, "createCaptureSession");
299 }
300
301 checkIfCameraClosed();
302
303 // TODO: we must be in UNCONFIGURED mode to begin with, or using another session
304
305 // TODO: dont block for this
306 boolean configureSuccess = true;
307 CameraAccessException pendingException = null;
308 try {
309 configureOutputs(outputs); // and then block until IDLE
310 } catch (CameraAccessException e) {
311 configureSuccess = false;
312 pendingException = e;
313 }
314
315 // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
316 CameraCaptureSessionImpl newSession =
317 new CameraCaptureSessionImpl(outputs, listener, handler, this, mDeviceHandler,
318 configureSuccess);
319
320 if (mCurrentSession != null) {
321 mCurrentSession.replaceSessionClose(newSession);
322 }
323
324 // TODO: wait until current session closes, then create the new session
325 mCurrentSession = newSession;
326
327 if (pendingException != null) {
328 throw pendingException;
329 }
330
331 mSessionStateListener = mCurrentSession.getDeviceStateListener();
332 }
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700333 }
334
335 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700336 public CaptureRequest.Builder createCaptureRequest(int templateType)
337 throws CameraAccessException {
Igor Murashkin70725502013-06-25 20:27:06 +0000338 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700339 checkIfCameraClosed();
Igor Murashkin70725502013-06-25 20:27:06 +0000340
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700341 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000342
343 try {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700344 mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000345 } catch (CameraRuntimeException e) {
346 throw e.asChecked();
347 } catch (RemoteException e) {
348 // impossible
349 return null;
350 }
351
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700352 CaptureRequest.Builder builder =
353 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000354
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700355 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000356 }
357 }
358
359 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700360 public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000361 throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700362 if (DEBUG) {
363 Log.d(TAG, "calling capture");
364 }
365 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
366 requestList.add(request);
367 return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000368 }
369
370 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700371 public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700372 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700373 if (requests == null || requests.isEmpty()) {
374 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700375 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700376 return submitCaptureRequest(requests, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000377 }
378
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700379 /**
380 * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
381 * starting and stopping repeating request and flushing.
382 *
383 * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
384 * sent to HAL. Then onCaptureSequenceCompleted is immediately triggered.
385 * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
386 * is added to the list mFrameNumberRequestPairs.</p>
387 *
388 * @param requestId the request ID of the current repeating request.
389 *
390 * @param lastFrameNumber last frame number returned from binder.
391 */
392 private void checkEarlyTriggerSequenceComplete(
393 final int requestId, final long lastFrameNumber) {
394 // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
395 // was never sent to HAL. Should trigger onCaptureSequenceCompleted immediately.
396 if (lastFrameNumber == CaptureListener.NO_FRAMES_CAPTURED) {
397 final CaptureListenerHolder holder;
398 int index = mCaptureListenerMap.indexOfKey(requestId);
399 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index) : null;
400 if (holder != null) {
401 mCaptureListenerMap.removeAt(index);
Jianing Weibaf0c652014-04-18 17:35:00 -0700402 if (DEBUG) {
403 Log.v(TAG, String.format(
404 "remove holder for requestId %d, "
405 + "because lastFrame is %d.",
406 requestId, lastFrameNumber));
407 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700408 }
409
410 if (holder != null) {
411 if (DEBUG) {
412 Log.v(TAG, "immediately trigger onCaptureSequenceCompleted because"
413 + " request did not reach HAL");
414 }
415
416 Runnable resultDispatch = new Runnable() {
417 @Override
418 public void run() {
419 if (!CameraDevice.this.isClosed()) {
420 if (DEBUG) {
421 Log.d(TAG, String.format(
422 "early trigger sequence complete for request %d",
423 requestId));
424 }
425 if (lastFrameNumber < Integer.MIN_VALUE
426 || lastFrameNumber > Integer.MAX_VALUE) {
427 throw new AssertionError(lastFrameNumber + " cannot be cast to int");
428 }
429 holder.getListener().onCaptureSequenceCompleted(
430 CameraDevice.this,
431 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -0700432 lastFrameNumber);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700433 }
434 }
435 };
436 holder.getHandler().post(resultDispatch);
437 } else {
438 Log.w(TAG, String.format(
439 "did not register listener to request %d",
440 requestId));
441 }
442 } else {
443 mFrameNumberRequestPairs.add(
444 new SimpleEntry<Long, Integer>(lastFrameNumber,
445 requestId));
446 }
447 }
448
Jianing Weid2c3a822014-03-27 18:27:43 -0700449 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700450 Handler handler, boolean repeating) throws CameraAccessException {
451
452 // Need a valid handler, or current thread needs to have a looper, if
453 // listener is valid
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700454 if (listener != null) {
455 handler = checkHandler(handler);
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700456 }
Igor Murashkin70725502013-06-25 20:27:06 +0000457
458 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700459 checkIfCameraClosed();
Igor Murashkin70725502013-06-25 20:27:06 +0000460 int requestId;
461
Ruben Brunke73b41b2013-11-07 19:30:43 -0800462 if (repeating) {
463 stopRepeating();
464 }
465
Jianing Weid2c3a822014-03-27 18:27:43 -0700466 LongParcelable lastFrameNumberRef = new LongParcelable();
Igor Murashkin70725502013-06-25 20:27:06 +0000467 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700468 requestId = mRemoteDevice.submitRequestList(requestList, repeating,
469 /*out*/lastFrameNumberRef);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700470 if (DEBUG) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700471 Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
472 }
Igor Murashkin70725502013-06-25 20:27:06 +0000473 } catch (CameraRuntimeException e) {
474 throw e.asChecked();
475 } catch (RemoteException e) {
476 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700477 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000478 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700479
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700480 if (listener != null) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700481 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener,
482 requestList, handler, repeating));
Jianing Weibaf0c652014-04-18 17:35:00 -0700483 } else {
484 if (DEBUG) {
485 Log.d(TAG, "Listen for request " + requestId + " is null");
486 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700487 }
Igor Murashkin70725502013-06-25 20:27:06 +0000488
Jianing Weid2c3a822014-03-27 18:27:43 -0700489 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700490
Igor Murashkin70725502013-06-25 20:27:06 +0000491 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700492 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700493 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700494 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700495 mRepeatingRequestId = requestId;
Jianing Weid2c3a822014-03-27 18:27:43 -0700496 } else {
497 mFrameNumberRequestPairs.add(
498 new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
Igor Murashkin70725502013-06-25 20:27:06 +0000499 }
500
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700501 if (mIdle) {
502 mDeviceHandler.post(mCallOnActive);
503 }
504 mIdle = false;
505
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700506 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000507 }
508 }
509
510 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700511 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700512 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700513 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
514 requestList.add(request);
515 return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000516 }
517
518 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700519 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700520 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700521 if (requests == null || requests.isEmpty()) {
522 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700523 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700524 return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000525 }
526
527 @Override
528 public void stopRepeating() throws CameraAccessException {
529
530 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700531 checkIfCameraClosed();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700532 if (mRepeatingRequestId != REQUEST_ID_NONE) {
533
534 int requestId = mRepeatingRequestId;
535 mRepeatingRequestId = REQUEST_ID_NONE;
536
537 // Queue for deletion after in-flight requests finish
Zhijun He1a9b6462014-03-31 16:11:33 -0700538 if (mCaptureListenerMap.get(requestId) != null) {
539 mRepeatingRequestIdDeletedList.add(requestId);
540 }
Igor Murashkin70725502013-06-25 20:27:06 +0000541
542 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700543 LongParcelable lastFrameNumberRef = new LongParcelable();
544 mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
545 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700546
547 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
548
Igor Murashkin70725502013-06-25 20:27:06 +0000549 } catch (CameraRuntimeException e) {
550 throw e.asChecked();
551 } catch (RemoteException e) {
552 // impossible
553 return;
554 }
555 }
556 }
557 }
558
Zhijun Hed842fcd2013-12-26 14:14:04 -0800559 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700560
561 synchronized (mLock) {
562 checkIfCameraClosed();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700563 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700564 throw new IllegalStateException("Active repeating request ongoing");
565 }
566
567 try {
568 mRemoteDevice.waitUntilIdle();
569 } catch (CameraRuntimeException e) {
570 throw e.asChecked();
571 } catch (RemoteException e) {
572 // impossible
573 return;
574 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700575
576 mRepeatingRequestId = REQUEST_ID_NONE;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700577 }
Igor Murashkin70725502013-06-25 20:27:06 +0000578 }
579
580 @Override
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700581 public void flush() throws CameraAccessException {
582 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700583 checkIfCameraClosed();
584
585 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700586 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700587 LongParcelable lastFrameNumberRef = new LongParcelable();
588 mRemoteDevice.flush(/*out*/lastFrameNumberRef);
589 if (mRepeatingRequestId != REQUEST_ID_NONE) {
590 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700591 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700592 mRepeatingRequestId = REQUEST_ID_NONE;
593 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700594 } catch (CameraRuntimeException e) {
595 throw e.asChecked();
596 } catch (RemoteException e) {
597 // impossible
598 return;
599 }
600 }
601 }
602
603 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700604 public void close() {
Igor Murashkin70725502013-06-25 20:27:06 +0000605 synchronized (mLock) {
606
607 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700608 if (mRemoteDevice != null) {
609 mRemoteDevice.disconnect();
610 }
Igor Murashkin70725502013-06-25 20:27:06 +0000611 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700612 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000613 } catch (RemoteException e) {
614 // impossible
615 }
616
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700617 if (mRemoteDevice != null) {
618 mDeviceHandler.post(mCallOnClosed);
619 }
Igor Murashkin70725502013-06-25 20:27:06 +0000620
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700621 mRemoteDevice = null;
Igor Murashkin70725502013-06-25 20:27:06 +0000622 }
623 }
624
625 @Override
626 protected void finalize() throws Throwable {
627 try {
628 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000629 }
630 finally {
631 super.finalize();
632 }
633 }
634
635 static class CaptureListenerHolder {
636
637 private final boolean mRepeating;
638 private final CaptureListener mListener;
Jianing Weid2c3a822014-03-27 18:27:43 -0700639 private final List<CaptureRequest> mRequestList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700640 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000641
Jianing Weid2c3a822014-03-27 18:27:43 -0700642 CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList,
643 Handler handler, boolean repeating) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700644 if (listener == null || handler == null) {
645 throw new UnsupportedOperationException(
646 "Must have a valid handler and a valid listener");
647 }
Igor Murashkin70725502013-06-25 20:27:06 +0000648 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700649 mHandler = handler;
Jianing Weid2c3a822014-03-27 18:27:43 -0700650 mRequestList = new ArrayList<CaptureRequest>(requestList);
Igor Murashkin70725502013-06-25 20:27:06 +0000651 mListener = listener;
652 }
653
654 public boolean isRepeating() {
655 return mRepeating;
656 }
657
658 public CaptureListener getListener() {
659 return mListener;
660 }
661
Jianing Weid2c3a822014-03-27 18:27:43 -0700662 public CaptureRequest getRequest(int subsequenceId) {
663 if (subsequenceId >= mRequestList.size()) {
664 throw new IllegalArgumentException(
665 String.format(
666 "Requested subsequenceId %d is larger than request list size %d.",
667 subsequenceId, mRequestList.size()));
668 } else {
669 if (subsequenceId < 0) {
670 throw new IllegalArgumentException(String.format(
671 "Requested subsequenceId %d is negative", subsequenceId));
672 } else {
673 return mRequestList.get(subsequenceId);
674 }
675 }
676 }
677
Igor Murashkin70725502013-06-25 20:27:06 +0000678 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700679 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +0000680 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700681
682 public Handler getHandler() {
683 return mHandler;
684 }
685
Igor Murashkin70725502013-06-25 20:27:06 +0000686 }
687
Jianing Weid2c3a822014-03-27 18:27:43 -0700688 /**
689 * This class tracks the last frame number for submitted requests.
690 */
691 public class FrameNumberTracker {
692
693 private long mCompletedFrameNumber = -1;
694 private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
695
696 private void update() {
697 Iterator<Long> iter = mFutureErrorSet.iterator();
698 while (iter.hasNext()) {
699 long errorFrameNumber = iter.next();
700 if (errorFrameNumber == mCompletedFrameNumber + 1) {
701 mCompletedFrameNumber++;
702 iter.remove();
703 } else {
704 break;
705 }
706 }
707 }
708
709 /**
710 * This function is called every time when a result or an error is received.
711 * @param frameNumber: the frame number corresponding to the result or error
712 * @param isError: true if it is an error, false if it is not an error
713 */
714 public void updateTracker(long frameNumber, boolean isError) {
715 if (isError) {
716 mFutureErrorSet.add(frameNumber);
717 } else {
718 /**
719 * HAL cannot send an OnResultReceived for frame N unless it knows for
720 * sure that all frames prior to N have either errored out or completed.
721 * So if the current frame is not an error, then all previous frames
722 * should have arrived. The following line checks whether this holds.
723 */
724 if (frameNumber != mCompletedFrameNumber + 1) {
Zhijun He22589b42014-05-01 10:37:36 -0700725 Log.e(TAG, String.format(
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700726 "result frame number %d comes out of order, should be %d + 1",
727 frameNumber, mCompletedFrameNumber));
Jianing Weid2c3a822014-03-27 18:27:43 -0700728 }
729 mCompletedFrameNumber++;
730 }
731 update();
732 }
733
734 public long getCompletedFrameNumber() {
735 return mCompletedFrameNumber;
736 }
737
738 }
739
740 private void checkAndFireSequenceComplete() {
741 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
742 Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
743 while (iter.hasNext()) {
744 final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
745 if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
746
747 // remove request from mCaptureListenerMap
748 final int requestId = frameNumberRequestPair.getValue();
749 final CaptureListenerHolder holder;
750 synchronized (mLock) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700751 int index = mCaptureListenerMap.indexOfKey(requestId);
752 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index)
Jianing Weid2c3a822014-03-27 18:27:43 -0700753 : null;
754 if (holder != null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700755 mCaptureListenerMap.removeAt(index);
756 if (DEBUG) {
757 Log.v(TAG, String.format(
758 "remove holder for requestId %d, "
759 + "because lastFrame %d is <= %d",
760 requestId, frameNumberRequestPair.getKey(),
761 completedFrameNumber));
762 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700763 }
764 }
765 iter.remove();
766
767 // Call onCaptureSequenceCompleted
768 if (holder != null) {
769 Runnable resultDispatch = new Runnable() {
770 @Override
771 public void run() {
772 if (!CameraDevice.this.isClosed()){
773 if (DEBUG) {
774 Log.d(TAG, String.format(
775 "fire sequence complete for request %d",
776 requestId));
777 }
778
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700779 long lastFrameNumber = frameNumberRequestPair.getKey();
780 if (lastFrameNumber < Integer.MIN_VALUE
781 || lastFrameNumber > Integer.MAX_VALUE) {
782 throw new AssertionError(lastFrameNumber
783 + " cannot be cast to int");
784 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700785 holder.getListener().onCaptureSequenceCompleted(
786 CameraDevice.this,
787 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -0700788 lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700789 }
790 }
791 };
792 holder.getHandler().post(resultDispatch);
793 }
794
795 }
796 }
797 }
798
Zhijun Heecb323e2013-07-31 09:40:27 -0700799 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +0000800
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700801 //
802 // Constants below need to be kept up-to-date with
803 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
804 //
805
806 //
807 // Error codes for onCameraError
808 //
809
810 /**
811 * Camera has been disconnected
812 */
813 static final int ERROR_CAMERA_DISCONNECTED = 0;
814
815 /**
816 * Camera has encountered a device-level error
817 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
818 */
819 static final int ERROR_CAMERA_DEVICE = 1;
820
821 /**
822 * Camera has encountered a service-level error
823 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
824 */
825 static final int ERROR_CAMERA_SERVICE = 2;
826
Igor Murashkin70725502013-06-25 20:27:06 +0000827 @Override
828 public IBinder asBinder() {
829 return this;
830 }
831
Igor Murashkin70725502013-06-25 20:27:06 +0000832 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700833 public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700834 Runnable r = null;
835 if (isClosed()) return;
836
837 synchronized(mLock) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700838 switch (errorCode) {
839 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700840 r = mCallOnDisconnected;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700841 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700842 default:
843 Log.e(TAG, "Unknown error from camera device: " + errorCode);
844 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700845 case ERROR_CAMERA_DEVICE:
846 case ERROR_CAMERA_SERVICE:
847 r = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700848 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700849 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700850 if (!CameraDevice.this.isClosed()) {
851 mDeviceListener.onError(CameraDevice.this, errorCode);
852 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700853 }
854 };
855 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700856 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700857 CameraDevice.this.mDeviceHandler.post(r);
Zhijun Heecb323e2013-07-31 09:40:27 -0700858 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700859
860 // Fire onCaptureSequenceCompleted
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700861 if (DEBUG) {
862 Log.v(TAG, String.format("got error frame %d", resultExtras.getFrameNumber()));
863 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700864 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true);
865 checkAndFireSequenceComplete();
866
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700867 }
868
869 @Override
870 public void onCameraIdle() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700871 if (isClosed()) return;
872
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700873 if (DEBUG) {
874 Log.d(TAG, "Camera now idle");
875 }
876 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700877 if (!CameraDevice.this.mIdle) {
878 CameraDevice.this.mDeviceHandler.post(mCallOnIdle);
879 }
880 CameraDevice.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700881 }
882 }
883
884 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700885 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
886 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700887 if (DEBUG) {
888 Log.d(TAG, "Capture started for id " + requestId);
889 }
890 final CaptureListenerHolder holder;
891
892 // Get the listener for this frame ID, if there is one
893 synchronized (mLock) {
894 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
895 }
896
897 if (holder == null) {
898 return;
899 }
900
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700901 if (isClosed()) return;
902
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700903 // Dispatch capture start notice
904 holder.getHandler().post(
905 new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700906 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700907 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700908 if (!CameraDevice.this.isClosed()) {
909 holder.getListener().onCaptureStarted(
910 CameraDevice.this,
Jianing Weid2c3a822014-03-27 18:27:43 -0700911 holder.getRequest(resultExtras.getSubsequenceId()),
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700912 timestamp);
913 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700914 }
915 });
Igor Murashkin70725502013-06-25 20:27:06 +0000916 }
917
918 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700919 public void onResultReceived(CameraMetadataNative result,
920 CaptureResultExtras resultExtras) throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -0700921
Jianing Weid2c3a822014-03-27 18:27:43 -0700922 int requestId = resultExtras.getRequestId();
Zhijun Heecb323e2013-07-31 09:40:27 -0700923 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -0700924 Log.v(TAG, "Received result frame " + resultExtras.getFrameNumber() + " for id "
925 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -0700926 }
Ruben Brunk57493682014-05-27 18:58:08 -0700927
928
929 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
930 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
931 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
932
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700933 final CaptureListenerHolder holder;
934 synchronized (mLock) {
935 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
936 }
Igor Murashkin70725502013-06-25 20:27:06 +0000937
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800938 Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT);
939 boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial);
940
Jianing Weibaf0c652014-04-18 17:35:00 -0700941 // Update tracker (increment counter) when it's not a partial result.
942 if (!quirkIsPartialResult) {
943 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/false);
944 }
945
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700946 // Check if we have a listener for this
Igor Murashkin70725502013-06-25 20:27:06 +0000947 if (holder == null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700948 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -0700949 Log.d(TAG,
950 "holder is null, early return at frame "
951 + resultExtras.getFrameNumber());
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700952 }
Igor Murashkin70725502013-06-25 20:27:06 +0000953 return;
954 }
955
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700956 if (isClosed()) {
957 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -0700958 Log.d(TAG,
959 "camera is closed, early return at frame "
960 + resultExtras.getFrameNumber());
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700961 }
962 return;
963 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700964
Jianing Weid2c3a822014-03-27 18:27:43 -0700965 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
Igor Murashkindb075af2014-05-21 10:07:08 -0700966
Igor Murashkin70725502013-06-25 20:27:06 +0000967
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800968 Runnable resultDispatch = null;
969
970 // Either send a partial result or the final capture completed result
971 if (quirkIsPartialResult) {
Igor Murashkindb075af2014-05-21 10:07:08 -0700972 final CaptureResult resultAsCapture =
973 new CaptureResult(result, request, requestId);
974
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800975 // Partial result
976 resultDispatch = new Runnable() {
977 @Override
978 public void run() {
979 if (!CameraDevice.this.isClosed()){
980 holder.getListener().onCapturePartial(
981 CameraDevice.this,
982 request,
983 resultAsCapture);
984 }
985 }
986 };
987 } else {
Igor Murashkindb075af2014-05-21 10:07:08 -0700988 final TotalCaptureResult resultAsCapture =
989 new TotalCaptureResult(result, request, requestId);
990
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800991 // Final capture result
992 resultDispatch = new Runnable() {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700993 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700994 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700995 if (!CameraDevice.this.isClosed()){
996 holder.getListener().onCaptureCompleted(
997 CameraDevice.this,
998 request,
999 resultAsCapture);
1000 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001001 }
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001002 };
1003 }
1004
1005 holder.getHandler().post(resultDispatch);
Jianing Weid2c3a822014-03-27 18:27:43 -07001006
1007 // Fire onCaptureSequenceCompleted
1008 if (!quirkIsPartialResult) {
Jianing Weid2c3a822014-03-27 18:27:43 -07001009 checkAndFireSequenceComplete();
1010 }
Igor Murashkin70725502013-06-25 20:27:06 +00001011 }
1012
1013 }
1014
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001015 /**
Igor Murashkin0b27d342014-05-30 09:45:05 -07001016 * Default handler management.
1017 *
1018 * <p>
1019 * If handler is null, get the current thread's
1020 * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
1021 * </p>
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001022 */
Igor Murashkin0b27d342014-05-30 09:45:05 -07001023 static Handler checkHandler(Handler handler) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001024 if (handler == null) {
1025 Looper looper = Looper.myLooper();
1026 if (looper == null) {
1027 throw new IllegalArgumentException(
1028 "No handler given, and current thread has no looper!");
1029 }
1030 handler = new Handler(looper);
1031 }
1032 return handler;
1033 }
1034
Zhijun He7f4d3142013-07-23 07:54:38 -07001035 private void checkIfCameraClosed() {
1036 if (mRemoteDevice == null) {
1037 throw new IllegalStateException("CameraDevice was already closed");
1038 }
1039 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001040
1041 private boolean isClosed() {
1042 synchronized(mLock) {
1043 return (mRemoteDevice == null);
1044 }
1045 }
Ruben Brunk57493682014-05-27 18:58:08 -07001046
1047 private CameraCharacteristics getCharacteristics() {
1048 return mCharacteristics;
1049 }
Igor Murashkin70725502013-06-25 20:27:06 +00001050}