blob: 9a4c53155704e2c974206d03e5e3767489eb1890 [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;
65 private final Handler mDeviceHandler;
66
67 private boolean mIdle = true;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070068
69 private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
70 new SparseArray<CaptureListenerHolder>();
Igor Murashkin70725502013-06-25 20:27:06 +000071
Ruben Brunkdecfe952013-10-29 11:00:32 -070072 private int mRepeatingRequestId = REQUEST_ID_NONE;
73 private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>();
Igor Murashkin57ea59b2013-08-23 16:55:57 -070074 // Map stream IDs to Surfaces
75 private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
Igor Murashkin70725502013-06-25 20:27:06 +000076
77 private final String mCameraId;
Ruben Brunk57493682014-05-27 18:58:08 -070078 private final CameraCharacteristics mCharacteristics;
Igor Murashkin70725502013-06-25 20:27:06 +000079
Jianing Weid2c3a822014-03-27 18:27:43 -070080 /**
81 * A list tracking request and its expected last frame.
82 * Updated when calling ICameraDeviceUser methods.
83 */
84 private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>>
85 mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>();
86
87 /**
88 * An object tracking received frame numbers.
89 * Updated when receiving callbacks from ICameraDeviceCallbacks.
90 */
91 private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
92
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070093 // Runnables for all state transitions, except error, which needs the
94 // error code argument
95
96 private final Runnable mCallOnOpened = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -070097 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070098 public void run() {
99 if (!CameraDevice.this.isClosed()) {
100 mDeviceListener.onOpened(CameraDevice.this);
101 }
102 }
103 };
104
105 private final Runnable mCallOnUnconfigured = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700106 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700107 public void run() {
108 if (!CameraDevice.this.isClosed()) {
109 mDeviceListener.onUnconfigured(CameraDevice.this);
110 }
111 }
112 };
113
114 private final Runnable mCallOnActive = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700115 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700116 public void run() {
117 if (!CameraDevice.this.isClosed()) {
118 mDeviceListener.onActive(CameraDevice.this);
119 }
120 }
121 };
122
123 private final Runnable mCallOnBusy = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700124 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700125 public void run() {
126 if (!CameraDevice.this.isClosed()) {
127 mDeviceListener.onBusy(CameraDevice.this);
128 }
129 }
130 };
131
132 private final Runnable mCallOnClosed = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700133 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700134 public void run() {
Zhijun He2db56022014-01-02 15:12:00 -0800135 mDeviceListener.onClosed(CameraDevice.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700136 }
137 };
138
139 private final Runnable mCallOnIdle = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700140 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700141 public void run() {
142 if (!CameraDevice.this.isClosed()) {
143 mDeviceListener.onIdle(CameraDevice.this);
144 }
145 }
146 };
147
148 private final Runnable mCallOnDisconnected = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700149 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700150 public void run() {
151 if (!CameraDevice.this.isClosed()) {
152 mDeviceListener.onDisconnected(CameraDevice.this);
153 }
154 }
155 };
156
Ruben Brunk57493682014-05-27 18:58:08 -0700157 public CameraDevice(String cameraId, StateListener listener, Handler handler,
158 CameraCharacteristics characteristics) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700159 if (cameraId == null || listener == null || handler == null) {
160 throw new IllegalArgumentException("Null argument given");
161 }
Igor Murashkin70725502013-06-25 20:27:06 +0000162 mCameraId = cameraId;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700163 mDeviceListener = listener;
164 mDeviceHandler = handler;
Ruben Brunk57493682014-05-27 18:58:08 -0700165 mCharacteristics = characteristics;
Eino-Ville Talvalab72d1ef2014-04-28 13:21:18 -0700166
167 final int MAX_TAG_LEN = 23;
168 String tag = String.format("CameraDevice-JV-%s", mCameraId);
169 if (tag.length() > MAX_TAG_LEN) {
170 tag = tag.substring(0, MAX_TAG_LEN);
171 }
172 TAG = tag;
173
Zhijun Heecb323e2013-07-31 09:40:27 -0700174 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Igor Murashkin70725502013-06-25 20:27:06 +0000175 }
176
177 public CameraDeviceCallbacks getCallbacks() {
178 return mCallbacks;
179 }
180
Igor Murashkin70725502013-06-25 20:27:06 +0000181 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -0700182 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700183 synchronized(mLock) {
184 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
185
186 mDeviceHandler.post(mCallOnOpened);
187 mDeviceHandler.post(mCallOnUnconfigured);
188 }
Igor Murashkin70725502013-06-25 20:27:06 +0000189 }
190
191 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700192 public String getId() {
193 return mCameraId;
194 }
195
196 @Override
Igor Murashkin70725502013-06-25 20:27:06 +0000197 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700198 // Treat a null input the same an empty list
199 if (outputs == null) {
200 outputs = new ArrayList<Surface>();
201 }
Igor Murashkin70725502013-06-25 20:27:06 +0000202 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700203 checkIfCameraClosed();
204
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700205 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
206 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
207
208 // Determine which streams need to be created, which to be deleted
209 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
210 int streamId = mConfiguredOutputs.keyAt(i);
211 Surface s = mConfiguredOutputs.valueAt(i);
212
213 if (!outputs.contains(s)) {
214 deleteList.add(streamId);
215 } else {
216 addSet.remove(s); // Don't create a stream previously created
217 }
218 }
219
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700220 mDeviceHandler.post(mCallOnBusy);
221 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700222
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700223 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700224 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700225
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700226 mRemoteDevice.beginConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700227 // Delete all streams first (to free up HW resources)
228 for (Integer streamId : deleteList) {
229 mRemoteDevice.deleteStream(streamId);
230 mConfiguredOutputs.delete(streamId);
231 }
232
233 // Add all new streams
234 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000235 // TODO: remove width,height,format since we are ignoring
236 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700237 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
238 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000239 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700240
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700241 mRemoteDevice.endConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700242 } catch (CameraRuntimeException e) {
243 if (e.getReason() == CAMERA_IN_USE) {
244 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700245 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700246 }
247
248 throw e.asChecked();
249 } catch (RemoteException e) {
250 // impossible
251 return;
Igor Murashkin70725502013-06-25 20:27:06 +0000252 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700253
254 if (outputs.size() > 0) {
255 mDeviceHandler.post(mCallOnIdle);
256 } else {
257 mDeviceHandler.post(mCallOnUnconfigured);
258 }
Igor Murashkin70725502013-06-25 20:27:06 +0000259 }
260 }
261
262 @Override
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700263 public void createCaptureSession(List<Surface> outputs,
264 CameraCaptureSession.StateListener listener, Handler handler)
265 throws CameraAccessException {
266 // TODO
267 }
268
269 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700270 public CaptureRequest.Builder createCaptureRequest(int templateType)
271 throws CameraAccessException {
Igor Murashkin70725502013-06-25 20:27:06 +0000272 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700273 checkIfCameraClosed();
Igor Murashkin70725502013-06-25 20:27:06 +0000274
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700275 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000276
277 try {
278 mRemoteDevice.createDefaultRequest(templateType, /* out */templatedRequest);
279 } catch (CameraRuntimeException e) {
280 throw e.asChecked();
281 } catch (RemoteException e) {
282 // impossible
283 return null;
284 }
285
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700286 CaptureRequest.Builder builder =
287 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000288
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700289 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000290 }
291 }
292
293 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700294 public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000295 throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700296 if (DEBUG) {
297 Log.d(TAG, "calling capture");
298 }
299 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
300 requestList.add(request);
301 return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000302 }
303
304 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700305 public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700306 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700307 // TODO: remove this. Throw IAE if the request is null or empty. Need to update API doc.
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700308 if (requests.isEmpty()) {
309 Log.w(TAG, "Capture burst request list is empty, do nothing!");
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700310 return -1;
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700311 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700312 return submitCaptureRequest(requests, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000313 }
314
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700315 /**
316 * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
317 * starting and stopping repeating request and flushing.
318 *
319 * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
320 * sent to HAL. Then onCaptureSequenceCompleted is immediately triggered.
321 * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
322 * is added to the list mFrameNumberRequestPairs.</p>
323 *
324 * @param requestId the request ID of the current repeating request.
325 *
326 * @param lastFrameNumber last frame number returned from binder.
327 */
328 private void checkEarlyTriggerSequenceComplete(
329 final int requestId, final long lastFrameNumber) {
330 // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
331 // was never sent to HAL. Should trigger onCaptureSequenceCompleted immediately.
332 if (lastFrameNumber == CaptureListener.NO_FRAMES_CAPTURED) {
333 final CaptureListenerHolder holder;
334 int index = mCaptureListenerMap.indexOfKey(requestId);
335 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index) : null;
336 if (holder != null) {
337 mCaptureListenerMap.removeAt(index);
Jianing Weibaf0c652014-04-18 17:35:00 -0700338 if (DEBUG) {
339 Log.v(TAG, String.format(
340 "remove holder for requestId %d, "
341 + "because lastFrame is %d.",
342 requestId, lastFrameNumber));
343 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700344 }
345
346 if (holder != null) {
347 if (DEBUG) {
348 Log.v(TAG, "immediately trigger onCaptureSequenceCompleted because"
349 + " request did not reach HAL");
350 }
351
352 Runnable resultDispatch = new Runnable() {
353 @Override
354 public void run() {
355 if (!CameraDevice.this.isClosed()) {
356 if (DEBUG) {
357 Log.d(TAG, String.format(
358 "early trigger sequence complete for request %d",
359 requestId));
360 }
361 if (lastFrameNumber < Integer.MIN_VALUE
362 || lastFrameNumber > Integer.MAX_VALUE) {
363 throw new AssertionError(lastFrameNumber + " cannot be cast to int");
364 }
365 holder.getListener().onCaptureSequenceCompleted(
366 CameraDevice.this,
367 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -0700368 lastFrameNumber);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700369 }
370 }
371 };
372 holder.getHandler().post(resultDispatch);
373 } else {
374 Log.w(TAG, String.format(
375 "did not register listener to request %d",
376 requestId));
377 }
378 } else {
379 mFrameNumberRequestPairs.add(
380 new SimpleEntry<Long, Integer>(lastFrameNumber,
381 requestId));
382 }
383 }
384
Jianing Weid2c3a822014-03-27 18:27:43 -0700385 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700386 Handler handler, boolean repeating) throws CameraAccessException {
387
388 // Need a valid handler, or current thread needs to have a looper, if
389 // listener is valid
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700390 if (listener != null) {
391 handler = checkHandler(handler);
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700392 }
Igor Murashkin70725502013-06-25 20:27:06 +0000393
394 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700395 checkIfCameraClosed();
Igor Murashkin70725502013-06-25 20:27:06 +0000396 int requestId;
397
Ruben Brunke73b41b2013-11-07 19:30:43 -0800398 if (repeating) {
399 stopRepeating();
400 }
401
Jianing Weid2c3a822014-03-27 18:27:43 -0700402 LongParcelable lastFrameNumberRef = new LongParcelable();
Igor Murashkin70725502013-06-25 20:27:06 +0000403 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700404 requestId = mRemoteDevice.submitRequestList(requestList, repeating,
405 /*out*/lastFrameNumberRef);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700406 if (DEBUG) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700407 Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
408 }
Igor Murashkin70725502013-06-25 20:27:06 +0000409 } catch (CameraRuntimeException e) {
410 throw e.asChecked();
411 } catch (RemoteException e) {
412 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700413 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000414 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700415
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700416 if (listener != null) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700417 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener,
418 requestList, handler, repeating));
Jianing Weibaf0c652014-04-18 17:35:00 -0700419 } else {
420 if (DEBUG) {
421 Log.d(TAG, "Listen for request " + requestId + " is null");
422 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700423 }
Igor Murashkin70725502013-06-25 20:27:06 +0000424
Jianing Weid2c3a822014-03-27 18:27:43 -0700425 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700426
Igor Murashkin70725502013-06-25 20:27:06 +0000427 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700428 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700429 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700430 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700431 mRepeatingRequestId = requestId;
Jianing Weid2c3a822014-03-27 18:27:43 -0700432 } else {
433 mFrameNumberRequestPairs.add(
434 new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
Igor Murashkin70725502013-06-25 20:27:06 +0000435 }
436
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700437 if (mIdle) {
438 mDeviceHandler.post(mCallOnActive);
439 }
440 mIdle = false;
441
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700442 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000443 }
444 }
445
446 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700447 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700448 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700449 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
450 requestList.add(request);
451 return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000452 }
453
454 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700455 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700456 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700457 // TODO: remove this. Throw IAE if the request is null or empty. Need to update API doc.
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700458 if (requests.isEmpty()) {
459 Log.w(TAG, "Set Repeating burst request list is empty, do nothing!");
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700460 return -1;
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700461 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700462 return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000463 }
464
465 @Override
466 public void stopRepeating() throws CameraAccessException {
467
468 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700469 checkIfCameraClosed();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700470 if (mRepeatingRequestId != REQUEST_ID_NONE) {
471
472 int requestId = mRepeatingRequestId;
473 mRepeatingRequestId = REQUEST_ID_NONE;
474
475 // Queue for deletion after in-flight requests finish
Zhijun He1a9b6462014-03-31 16:11:33 -0700476 if (mCaptureListenerMap.get(requestId) != null) {
477 mRepeatingRequestIdDeletedList.add(requestId);
478 }
Igor Murashkin70725502013-06-25 20:27:06 +0000479
480 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700481 LongParcelable lastFrameNumberRef = new LongParcelable();
482 mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
483 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700484
485 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
486
Igor Murashkin70725502013-06-25 20:27:06 +0000487 } catch (CameraRuntimeException e) {
488 throw e.asChecked();
489 } catch (RemoteException e) {
490 // impossible
491 return;
492 }
493 }
494 }
495 }
496
Zhijun Hed842fcd2013-12-26 14:14:04 -0800497 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700498
499 synchronized (mLock) {
500 checkIfCameraClosed();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700501 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700502 throw new IllegalStateException("Active repeating request ongoing");
503 }
504
505 try {
506 mRemoteDevice.waitUntilIdle();
507 } catch (CameraRuntimeException e) {
508 throw e.asChecked();
509 } catch (RemoteException e) {
510 // impossible
511 return;
512 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700513
514 mRepeatingRequestId = REQUEST_ID_NONE;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700515 }
Igor Murashkin70725502013-06-25 20:27:06 +0000516 }
517
518 @Override
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700519 public void flush() throws CameraAccessException {
520 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700521 checkIfCameraClosed();
522
523 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700524 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700525 LongParcelable lastFrameNumberRef = new LongParcelable();
526 mRemoteDevice.flush(/*out*/lastFrameNumberRef);
527 if (mRepeatingRequestId != REQUEST_ID_NONE) {
528 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700529 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700530 mRepeatingRequestId = REQUEST_ID_NONE;
531 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700532 } catch (CameraRuntimeException e) {
533 throw e.asChecked();
534 } catch (RemoteException e) {
535 // impossible
536 return;
537 }
538 }
539 }
540
541 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700542 public void close() {
Igor Murashkin70725502013-06-25 20:27:06 +0000543 synchronized (mLock) {
544
545 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700546 if (mRemoteDevice != null) {
547 mRemoteDevice.disconnect();
548 }
Igor Murashkin70725502013-06-25 20:27:06 +0000549 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700550 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000551 } catch (RemoteException e) {
552 // impossible
553 }
554
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700555 if (mRemoteDevice != null) {
556 mDeviceHandler.post(mCallOnClosed);
557 }
Igor Murashkin70725502013-06-25 20:27:06 +0000558
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700559 mRemoteDevice = null;
Igor Murashkin70725502013-06-25 20:27:06 +0000560 }
561 }
562
563 @Override
564 protected void finalize() throws Throwable {
565 try {
566 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000567 }
568 finally {
569 super.finalize();
570 }
571 }
572
573 static class CaptureListenerHolder {
574
575 private final boolean mRepeating;
576 private final CaptureListener mListener;
Jianing Weid2c3a822014-03-27 18:27:43 -0700577 private final List<CaptureRequest> mRequestList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700578 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000579
Jianing Weid2c3a822014-03-27 18:27:43 -0700580 CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList,
581 Handler handler, boolean repeating) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700582 if (listener == null || handler == null) {
583 throw new UnsupportedOperationException(
584 "Must have a valid handler and a valid listener");
585 }
Igor Murashkin70725502013-06-25 20:27:06 +0000586 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700587 mHandler = handler;
Jianing Weid2c3a822014-03-27 18:27:43 -0700588 mRequestList = new ArrayList<CaptureRequest>(requestList);
Igor Murashkin70725502013-06-25 20:27:06 +0000589 mListener = listener;
590 }
591
592 public boolean isRepeating() {
593 return mRepeating;
594 }
595
596 public CaptureListener getListener() {
597 return mListener;
598 }
599
Jianing Weid2c3a822014-03-27 18:27:43 -0700600 public CaptureRequest getRequest(int subsequenceId) {
601 if (subsequenceId >= mRequestList.size()) {
602 throw new IllegalArgumentException(
603 String.format(
604 "Requested subsequenceId %d is larger than request list size %d.",
605 subsequenceId, mRequestList.size()));
606 } else {
607 if (subsequenceId < 0) {
608 throw new IllegalArgumentException(String.format(
609 "Requested subsequenceId %d is negative", subsequenceId));
610 } else {
611 return mRequestList.get(subsequenceId);
612 }
613 }
614 }
615
Igor Murashkin70725502013-06-25 20:27:06 +0000616 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700617 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +0000618 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700619
620 public Handler getHandler() {
621 return mHandler;
622 }
623
Igor Murashkin70725502013-06-25 20:27:06 +0000624 }
625
Jianing Weid2c3a822014-03-27 18:27:43 -0700626 /**
627 * This class tracks the last frame number for submitted requests.
628 */
629 public class FrameNumberTracker {
630
631 private long mCompletedFrameNumber = -1;
632 private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
633
634 private void update() {
635 Iterator<Long> iter = mFutureErrorSet.iterator();
636 while (iter.hasNext()) {
637 long errorFrameNumber = iter.next();
638 if (errorFrameNumber == mCompletedFrameNumber + 1) {
639 mCompletedFrameNumber++;
640 iter.remove();
641 } else {
642 break;
643 }
644 }
645 }
646
647 /**
648 * This function is called every time when a result or an error is received.
649 * @param frameNumber: the frame number corresponding to the result or error
650 * @param isError: true if it is an error, false if it is not an error
651 */
652 public void updateTracker(long frameNumber, boolean isError) {
653 if (isError) {
654 mFutureErrorSet.add(frameNumber);
655 } else {
656 /**
657 * HAL cannot send an OnResultReceived for frame N unless it knows for
658 * sure that all frames prior to N have either errored out or completed.
659 * So if the current frame is not an error, then all previous frames
660 * should have arrived. The following line checks whether this holds.
661 */
662 if (frameNumber != mCompletedFrameNumber + 1) {
Zhijun He22589b42014-05-01 10:37:36 -0700663 Log.e(TAG, String.format(
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700664 "result frame number %d comes out of order, should be %d + 1",
665 frameNumber, mCompletedFrameNumber));
Jianing Weid2c3a822014-03-27 18:27:43 -0700666 }
667 mCompletedFrameNumber++;
668 }
669 update();
670 }
671
672 public long getCompletedFrameNumber() {
673 return mCompletedFrameNumber;
674 }
675
676 }
677
678 private void checkAndFireSequenceComplete() {
679 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
680 Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
681 while (iter.hasNext()) {
682 final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
683 if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
684
685 // remove request from mCaptureListenerMap
686 final int requestId = frameNumberRequestPair.getValue();
687 final CaptureListenerHolder holder;
688 synchronized (mLock) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700689 int index = mCaptureListenerMap.indexOfKey(requestId);
690 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index)
Jianing Weid2c3a822014-03-27 18:27:43 -0700691 : null;
692 if (holder != null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700693 mCaptureListenerMap.removeAt(index);
694 if (DEBUG) {
695 Log.v(TAG, String.format(
696 "remove holder for requestId %d, "
697 + "because lastFrame %d is <= %d",
698 requestId, frameNumberRequestPair.getKey(),
699 completedFrameNumber));
700 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700701 }
702 }
703 iter.remove();
704
705 // Call onCaptureSequenceCompleted
706 if (holder != null) {
707 Runnable resultDispatch = new Runnable() {
708 @Override
709 public void run() {
710 if (!CameraDevice.this.isClosed()){
711 if (DEBUG) {
712 Log.d(TAG, String.format(
713 "fire sequence complete for request %d",
714 requestId));
715 }
716
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700717 long lastFrameNumber = frameNumberRequestPair.getKey();
718 if (lastFrameNumber < Integer.MIN_VALUE
719 || lastFrameNumber > Integer.MAX_VALUE) {
720 throw new AssertionError(lastFrameNumber
721 + " cannot be cast to int");
722 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700723 holder.getListener().onCaptureSequenceCompleted(
724 CameraDevice.this,
725 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -0700726 lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700727 }
728 }
729 };
730 holder.getHandler().post(resultDispatch);
731 }
732
733 }
734 }
735 }
736
Zhijun Heecb323e2013-07-31 09:40:27 -0700737 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +0000738
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700739 //
740 // Constants below need to be kept up-to-date with
741 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
742 //
743
744 //
745 // Error codes for onCameraError
746 //
747
748 /**
749 * Camera has been disconnected
750 */
751 static final int ERROR_CAMERA_DISCONNECTED = 0;
752
753 /**
754 * Camera has encountered a device-level error
755 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
756 */
757 static final int ERROR_CAMERA_DEVICE = 1;
758
759 /**
760 * Camera has encountered a service-level error
761 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
762 */
763 static final int ERROR_CAMERA_SERVICE = 2;
764
Igor Murashkin70725502013-06-25 20:27:06 +0000765 @Override
766 public IBinder asBinder() {
767 return this;
768 }
769
Igor Murashkin70725502013-06-25 20:27:06 +0000770 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700771 public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700772 Runnable r = null;
773 if (isClosed()) return;
774
775 synchronized(mLock) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700776 switch (errorCode) {
777 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700778 r = mCallOnDisconnected;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700779 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700780 default:
781 Log.e(TAG, "Unknown error from camera device: " + errorCode);
782 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700783 case ERROR_CAMERA_DEVICE:
784 case ERROR_CAMERA_SERVICE:
785 r = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700786 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700787 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700788 if (!CameraDevice.this.isClosed()) {
789 mDeviceListener.onError(CameraDevice.this, errorCode);
790 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700791 }
792 };
793 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700794 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700795 CameraDevice.this.mDeviceHandler.post(r);
Zhijun Heecb323e2013-07-31 09:40:27 -0700796 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700797
798 // Fire onCaptureSequenceCompleted
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700799 if (DEBUG) {
800 Log.v(TAG, String.format("got error frame %d", resultExtras.getFrameNumber()));
801 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700802 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true);
803 checkAndFireSequenceComplete();
804
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700805 }
806
807 @Override
808 public void onCameraIdle() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700809 if (isClosed()) return;
810
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700811 if (DEBUG) {
812 Log.d(TAG, "Camera now idle");
813 }
814 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700815 if (!CameraDevice.this.mIdle) {
816 CameraDevice.this.mDeviceHandler.post(mCallOnIdle);
817 }
818 CameraDevice.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700819 }
820 }
821
822 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700823 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
824 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700825 if (DEBUG) {
826 Log.d(TAG, "Capture started for id " + requestId);
827 }
828 final CaptureListenerHolder holder;
829
830 // Get the listener for this frame ID, if there is one
831 synchronized (mLock) {
832 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
833 }
834
835 if (holder == null) {
836 return;
837 }
838
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700839 if (isClosed()) return;
840
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700841 // Dispatch capture start notice
842 holder.getHandler().post(
843 new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700844 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700845 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700846 if (!CameraDevice.this.isClosed()) {
847 holder.getListener().onCaptureStarted(
848 CameraDevice.this,
Jianing Weid2c3a822014-03-27 18:27:43 -0700849 holder.getRequest(resultExtras.getSubsequenceId()),
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700850 timestamp);
851 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700852 }
853 });
Igor Murashkin70725502013-06-25 20:27:06 +0000854 }
855
856 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700857 public void onResultReceived(CameraMetadataNative result,
858 CaptureResultExtras resultExtras) throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -0700859
Jianing Weid2c3a822014-03-27 18:27:43 -0700860 int requestId = resultExtras.getRequestId();
Zhijun Heecb323e2013-07-31 09:40:27 -0700861 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -0700862 Log.v(TAG, "Received result frame " + resultExtras.getFrameNumber() + " for id "
863 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -0700864 }
Ruben Brunk57493682014-05-27 18:58:08 -0700865
866
867 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
868 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
869 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
870
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700871 final CaptureListenerHolder holder;
872 synchronized (mLock) {
873 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
874 }
Igor Murashkin70725502013-06-25 20:27:06 +0000875
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800876 Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT);
877 boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial);
878
Jianing Weibaf0c652014-04-18 17:35:00 -0700879 // Update tracker (increment counter) when it's not a partial result.
880 if (!quirkIsPartialResult) {
881 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/false);
882 }
883
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700884 // Check if we have a listener for this
Igor Murashkin70725502013-06-25 20:27:06 +0000885 if (holder == null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700886 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -0700887 Log.d(TAG,
888 "holder is null, early return at frame "
889 + resultExtras.getFrameNumber());
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700890 }
Igor Murashkin70725502013-06-25 20:27:06 +0000891 return;
892 }
893
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700894 if (isClosed()) {
895 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -0700896 Log.d(TAG,
897 "camera is closed, early return at frame "
898 + resultExtras.getFrameNumber());
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700899 }
900 return;
901 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700902
Jianing Weid2c3a822014-03-27 18:27:43 -0700903 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
Igor Murashkindb075af2014-05-21 10:07:08 -0700904
Igor Murashkin70725502013-06-25 20:27:06 +0000905
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800906 Runnable resultDispatch = null;
907
908 // Either send a partial result or the final capture completed result
909 if (quirkIsPartialResult) {
Igor Murashkindb075af2014-05-21 10:07:08 -0700910 final CaptureResult resultAsCapture =
911 new CaptureResult(result, request, requestId);
912
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800913 // Partial result
914 resultDispatch = new Runnable() {
915 @Override
916 public void run() {
917 if (!CameraDevice.this.isClosed()){
918 holder.getListener().onCapturePartial(
919 CameraDevice.this,
920 request,
921 resultAsCapture);
922 }
923 }
924 };
925 } else {
Igor Murashkindb075af2014-05-21 10:07:08 -0700926 final TotalCaptureResult resultAsCapture =
927 new TotalCaptureResult(result, request, requestId);
928
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800929 // Final capture result
930 resultDispatch = new Runnable() {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700931 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700932 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700933 if (!CameraDevice.this.isClosed()){
934 holder.getListener().onCaptureCompleted(
935 CameraDevice.this,
936 request,
937 resultAsCapture);
938 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700939 }
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800940 };
941 }
942
943 holder.getHandler().post(resultDispatch);
Jianing Weid2c3a822014-03-27 18:27:43 -0700944
945 // Fire onCaptureSequenceCompleted
946 if (!quirkIsPartialResult) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700947 checkAndFireSequenceComplete();
948 }
Igor Murashkin70725502013-06-25 20:27:06 +0000949 }
950
951 }
952
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700953 /**
954 * Default handler management. If handler is null, get the current thread's
955 * Looper to create a Handler with. If no looper exists, throw exception.
956 */
957 private Handler checkHandler(Handler handler) {
958 if (handler == null) {
959 Looper looper = Looper.myLooper();
960 if (looper == null) {
961 throw new IllegalArgumentException(
962 "No handler given, and current thread has no looper!");
963 }
964 handler = new Handler(looper);
965 }
966 return handler;
967 }
968
Zhijun He7f4d3142013-07-23 07:54:38 -0700969 private void checkIfCameraClosed() {
970 if (mRemoteDevice == null) {
971 throw new IllegalStateException("CameraDevice was already closed");
972 }
973 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700974
975 private boolean isClosed() {
976 synchronized(mLock) {
977 return (mRemoteDevice == null);
978 }
979 }
Ruben Brunk57493682014-05-27 18:58:08 -0700980
981 private CameraCharacteristics getCharacteristics() {
982 return mCharacteristics;
983 }
Igor Murashkin70725502013-06-25 20:27:06 +0000984}