blob: f1ce0610b0c74beebc4c3ae26ec0ec6921c3b0f7 [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 Talvala2f1a2e42013-07-25 17:12:05 -070024import android.hardware.camera2.CaptureRequest;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070025import android.hardware.camera2.CaptureResult;
26import android.hardware.camera2.ICameraDeviceCallbacks;
27import android.hardware.camera2.ICameraDeviceUser;
Igor Murashkindb075af2014-05-21 10:07:08 -070028import android.hardware.camera2.TotalCaptureResult;
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -070029import android.hardware.camera2.utils.CameraBinderDecorator;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070030import android.hardware.camera2.utils.CameraRuntimeException;
Igor Murashkin9c595172014-05-12 13:56:20 -070031import android.hardware.camera2.utils.LongParcelable;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070032import android.os.Handler;
Ruben Brunkdecfe952013-10-29 11:00:32 -070033import android.os.IBinder;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070034import android.os.Looper;
Ruben Brunkdecfe952013-10-29 11:00:32 -070035import android.os.RemoteException;
Igor Murashkin70725502013-06-25 20:27:06 +000036import android.util.Log;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070037import android.util.SparseArray;
Igor Murashkin70725502013-06-25 20:27:06 +000038import android.view.Surface;
39
Jianing Weid2c3a822014-03-27 18:27:43 -070040import java.util.AbstractMap.SimpleEntry;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070041import java.util.ArrayList;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070042import java.util.HashSet;
Ruben Brunkdecfe952013-10-29 11:00:32 -070043import java.util.Iterator;
Igor Murashkin70725502013-06-25 20:27:06 +000044import java.util.List;
Jianing Weid2c3a822014-03-27 18:27:43 -070045import java.util.TreeSet;
Igor Murashkin70725502013-06-25 20:27:06 +000046
47/**
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070048 * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
Igor Murashkin70725502013-06-25 20:27:06 +000049 */
Igor Murashkin21547d62014-06-04 15:21:42 -070050public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
Igor Murashkin70725502013-06-25 20:27:06 +000051
52 private final String TAG;
Zhijun Heecb323e2013-07-31 09:40:27 -070053 private final boolean DEBUG;
Igor Murashkin70725502013-06-25 20:27:06 +000054
Ruben Brunkdecfe952013-10-29 11:00:32 -070055 private static final int REQUEST_ID_NONE = -1;
56
Igor Murashkin70725502013-06-25 20:27:06 +000057 // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
58 private ICameraDeviceUser mRemoteDevice;
59
60 private final Object mLock = new Object();
61 private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
62
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070063 private final StateListener mDeviceListener;
Igor Murashkin0b27d342014-05-30 09:45:05 -070064 private volatile StateListener mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070065 private final Handler mDeviceHandler;
66
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -070067 private boolean mInError = false;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070068 private boolean mIdle = true;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070069
Igor Murashkin21547d62014-06-04 15:21:42 -070070 /** map request IDs to listener/request data */
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070071 private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
72 new SparseArray<CaptureListenerHolder>();
Igor Murashkin70725502013-06-25 20:27:06 +000073
Ruben Brunkdecfe952013-10-29 11:00:32 -070074 private int mRepeatingRequestId = REQUEST_ID_NONE;
75 private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>();
Igor Murashkin57ea59b2013-08-23 16:55:57 -070076 // Map stream IDs to Surfaces
77 private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
Igor Murashkin70725502013-06-25 20:27:06 +000078
79 private final String mCameraId;
Ruben Brunk57493682014-05-27 18:58:08 -070080 private final CameraCharacteristics mCharacteristics;
Igor Murashkin70725502013-06-25 20:27:06 +000081
Jianing Weid2c3a822014-03-27 18:27:43 -070082 /**
83 * A list tracking request and its expected last frame.
84 * Updated when calling ICameraDeviceUser methods.
85 */
86 private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>>
87 mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>();
88
89 /**
90 * An object tracking received frame numbers.
91 * Updated when receiving callbacks from ICameraDeviceCallbacks.
92 */
93 private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
94
Igor Murashkin0b27d342014-05-30 09:45:05 -070095 private CameraCaptureSessionImpl mCurrentSession;
96
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070097 // Runnables for all state transitions, except error, which needs the
98 // error code argument
99
100 private final Runnable mCallOnOpened = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700101 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700102 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700103 if (!CameraDeviceImpl.this.isClosed()) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700104 StateListener sessionListener = mSessionStateListener;
105 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700106 sessionListener.onOpened(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700107 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700108 mDeviceListener.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700109 }
110 }
111 };
112
113 private final Runnable mCallOnUnconfigured = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700114 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700115 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700116 if (!CameraDeviceImpl.this.isClosed()) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700117 StateListener sessionListener = mSessionStateListener;
118 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700119 sessionListener.onUnconfigured(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700120 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700121 mDeviceListener.onUnconfigured(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700122 }
123 }
124 };
125
126 private final Runnable mCallOnActive = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700127 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700128 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700129 if (!CameraDeviceImpl.this.isClosed()) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700130 StateListener sessionListener = mSessionStateListener;
131 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700132 sessionListener.onActive(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700133 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700134 mDeviceListener.onActive(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700135 }
136 }
137 };
138
139 private final Runnable mCallOnBusy = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700140 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700141 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700142 if (!CameraDeviceImpl.this.isClosed()) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700143 StateListener sessionListener = mSessionStateListener;
144 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700145 sessionListener.onBusy(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700146 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700147 mDeviceListener.onBusy(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700148 }
149 }
150 };
151
152 private final Runnable mCallOnClosed = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700153 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700154 public void run() {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700155 StateListener sessionListener = mSessionStateListener;
156 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700157 sessionListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700158 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700159 mDeviceListener.onClosed(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700160 }
161 };
162
163 private final Runnable mCallOnIdle = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700164 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700165 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700166 if (!CameraDeviceImpl.this.isClosed()) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700167 StateListener sessionListener = mSessionStateListener;
168 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700169 sessionListener.onIdle(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700170 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700171 mDeviceListener.onIdle(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700172 }
173 }
174 };
175
176 private final Runnable mCallOnDisconnected = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700177 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700178 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700179 if (!CameraDeviceImpl.this.isClosed()) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700180 StateListener sessionListener = mSessionStateListener;
181 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700182 sessionListener.onDisconnected(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700183 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700184 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700185 }
186 }
187 };
188
Igor Murashkin21547d62014-06-04 15:21:42 -0700189 public CameraDeviceImpl(String cameraId, StateListener listener, Handler handler,
Ruben Brunk57493682014-05-27 18:58:08 -0700190 CameraCharacteristics characteristics) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700191 if (cameraId == null || listener == null || handler == null) {
192 throw new IllegalArgumentException("Null argument given");
193 }
Igor Murashkin70725502013-06-25 20:27:06 +0000194 mCameraId = cameraId;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700195 mDeviceListener = listener;
196 mDeviceHandler = handler;
Ruben Brunk57493682014-05-27 18:58:08 -0700197 mCharacteristics = characteristics;
Eino-Ville Talvalab72d1ef2014-04-28 13:21:18 -0700198
199 final int MAX_TAG_LEN = 23;
200 String tag = String.format("CameraDevice-JV-%s", mCameraId);
201 if (tag.length() > MAX_TAG_LEN) {
202 tag = tag.substring(0, MAX_TAG_LEN);
203 }
204 TAG = tag;
Zhijun Heecb323e2013-07-31 09:40:27 -0700205 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Igor Murashkin70725502013-06-25 20:27:06 +0000206 }
207
208 public CameraDeviceCallbacks getCallbacks() {
209 return mCallbacks;
210 }
211
Igor Murashkin70725502013-06-25 20:27:06 +0000212 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -0700213 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700214 synchronized(mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700215 // If setRemoteFailure already called, do nothing
216 if (mInError) return;
217
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700218 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
219
220 mDeviceHandler.post(mCallOnOpened);
221 mDeviceHandler.post(mCallOnUnconfigured);
222 }
Igor Murashkin70725502013-06-25 20:27:06 +0000223 }
224
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700225 /**
226 * Call to indicate failed connection to a remote camera device.
227 *
228 * <p>This places the camera device in the error state and informs the listener.
229 * Use in place of setRemoteDevice() when startup fails.</p>
230 */
231 public void setRemoteFailure(final CameraRuntimeException failure) {
232 int failureCode = StateListener.ERROR_CAMERA_DEVICE;
233 boolean failureIsError = true;
234
235 switch (failure.getReason()) {
236 case CameraAccessException.CAMERA_IN_USE:
237 failureCode = StateListener.ERROR_CAMERA_IN_USE;
238 break;
239 case CameraAccessException.MAX_CAMERAS_IN_USE:
240 failureCode = StateListener.ERROR_MAX_CAMERAS_IN_USE;
241 break;
242 case CameraAccessException.CAMERA_DISABLED:
243 failureCode = StateListener.ERROR_CAMERA_DISABLED;
244 break;
245 case CameraAccessException.CAMERA_DISCONNECTED:
246 failureIsError = false;
247 break;
248 case CameraAccessException.CAMERA_ERROR:
249 failureCode = StateListener.ERROR_CAMERA_DEVICE;
250 break;
251 default:
252 Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
253 break;
254 }
255 final int code = failureCode;
256 final boolean isError = failureIsError;
257 synchronized (mLock) {
258 mInError = true;
259 mDeviceHandler.post(new Runnable() {
Igor Murashkine1442202014-06-09 17:51:24 -0700260 @Override
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700261 public void run() {
262 if (isError) {
263 mDeviceListener.onError(CameraDeviceImpl.this, code);
264 } else {
265 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
266 }
267 }
268 });
269 }
270 }
271
Igor Murashkin70725502013-06-25 20:27:06 +0000272 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700273 public String getId() {
274 return mCameraId;
275 }
276
277 @Override
Igor Murashkin70725502013-06-25 20:27:06 +0000278 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700279 // Treat a null input the same an empty list
280 if (outputs == null) {
281 outputs = new ArrayList<Surface>();
282 }
Igor Murashkin70725502013-06-25 20:27:06 +0000283 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700284 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700285
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700286 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
287 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
288
289 // Determine which streams need to be created, which to be deleted
290 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
291 int streamId = mConfiguredOutputs.keyAt(i);
292 Surface s = mConfiguredOutputs.valueAt(i);
293
294 if (!outputs.contains(s)) {
295 deleteList.add(streamId);
296 } else {
297 addSet.remove(s); // Don't create a stream previously created
298 }
299 }
300
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700301 mDeviceHandler.post(mCallOnBusy);
302 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700303
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700304 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700305 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700306
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700307 mRemoteDevice.beginConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700308 // Delete all streams first (to free up HW resources)
309 for (Integer streamId : deleteList) {
310 mRemoteDevice.deleteStream(streamId);
311 mConfiguredOutputs.delete(streamId);
312 }
313
314 // Add all new streams
315 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000316 // TODO: remove width,height,format since we are ignoring
317 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700318 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
319 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000320 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700321
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700322 mRemoteDevice.endConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700323 } catch (CameraRuntimeException e) {
324 if (e.getReason() == CAMERA_IN_USE) {
325 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700326 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700327 }
328
329 throw e.asChecked();
330 } catch (RemoteException e) {
331 // impossible
332 return;
Igor Murashkin70725502013-06-25 20:27:06 +0000333 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700334
335 if (outputs.size() > 0) {
336 mDeviceHandler.post(mCallOnIdle);
337 } else {
338 mDeviceHandler.post(mCallOnUnconfigured);
339 }
Igor Murashkin70725502013-06-25 20:27:06 +0000340 }
341 }
342
343 @Override
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700344 public void createCaptureSession(List<Surface> outputs,
345 CameraCaptureSession.StateListener listener, Handler handler)
346 throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700347 synchronized (mLock) {
348 if (DEBUG) {
349 Log.d(TAG, "createCaptureSession");
350 }
351
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700352 checkIfCameraClosedOrInError();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700353
354 // TODO: we must be in UNCONFIGURED mode to begin with, or using another session
355
356 // TODO: dont block for this
357 boolean configureSuccess = true;
358 CameraAccessException pendingException = null;
359 try {
360 configureOutputs(outputs); // and then block until IDLE
361 } catch (CameraAccessException e) {
362 configureSuccess = false;
363 pendingException = e;
Igor Murashkine1442202014-06-09 17:51:24 -0700364 if (DEBUG) {
365 Log.v(TAG, "createCaptureSession - failed with exception ", e);
366 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700367 }
368
369 // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
370 CameraCaptureSessionImpl newSession =
371 new CameraCaptureSessionImpl(outputs, listener, handler, this, mDeviceHandler,
372 configureSuccess);
373
374 if (mCurrentSession != null) {
375 mCurrentSession.replaceSessionClose(newSession);
376 }
377
378 // TODO: wait until current session closes, then create the new session
379 mCurrentSession = newSession;
380
381 if (pendingException != null) {
382 throw pendingException;
383 }
384
385 mSessionStateListener = mCurrentSession.getDeviceStateListener();
386 }
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700387 }
388
389 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700390 public CaptureRequest.Builder createCaptureRequest(int templateType)
391 throws CameraAccessException {
Igor Murashkin70725502013-06-25 20:27:06 +0000392 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700393 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000394
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700395 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000396
397 try {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700398 mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000399 } catch (CameraRuntimeException e) {
400 throw e.asChecked();
401 } catch (RemoteException e) {
402 // impossible
403 return null;
404 }
405
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700406 CaptureRequest.Builder builder =
407 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000408
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700409 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000410 }
411 }
412
413 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700414 public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000415 throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700416 if (DEBUG) {
417 Log.d(TAG, "calling capture");
418 }
419 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
420 requestList.add(request);
421 return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000422 }
423
424 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700425 public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700426 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700427 if (requests == null || requests.isEmpty()) {
428 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700429 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700430 return submitCaptureRequest(requests, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000431 }
432
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700433 /**
434 * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
435 * starting and stopping repeating request and flushing.
436 *
437 * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700438 * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700439 * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
440 * is added to the list mFrameNumberRequestPairs.</p>
441 *
442 * @param requestId the request ID of the current repeating request.
443 *
444 * @param lastFrameNumber last frame number returned from binder.
445 */
446 private void checkEarlyTriggerSequenceComplete(
447 final int requestId, final long lastFrameNumber) {
448 // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700449 // was never sent to HAL. Should trigger onCaptureSequenceAborted immediately.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700450 if (lastFrameNumber == CaptureListener.NO_FRAMES_CAPTURED) {
451 final CaptureListenerHolder holder;
452 int index = mCaptureListenerMap.indexOfKey(requestId);
453 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index) : null;
454 if (holder != null) {
455 mCaptureListenerMap.removeAt(index);
Jianing Weibaf0c652014-04-18 17:35:00 -0700456 if (DEBUG) {
457 Log.v(TAG, String.format(
458 "remove holder for requestId %d, "
459 + "because lastFrame is %d.",
460 requestId, lastFrameNumber));
461 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700462 }
463
464 if (holder != null) {
465 if (DEBUG) {
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700466 Log.v(TAG, "immediately trigger onCaptureSequenceAborted because"
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700467 + " request did not reach HAL");
468 }
469
470 Runnable resultDispatch = new Runnable() {
471 @Override
472 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700473 if (!CameraDeviceImpl.this.isClosed()) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700474 if (DEBUG) {
475 Log.d(TAG, String.format(
476 "early trigger sequence complete for request %d",
477 requestId));
478 }
479 if (lastFrameNumber < Integer.MIN_VALUE
480 || lastFrameNumber > Integer.MAX_VALUE) {
481 throw new AssertionError(lastFrameNumber + " cannot be cast to int");
482 }
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700483 holder.getListener().onCaptureSequenceAborted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700484 CameraDeviceImpl.this,
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700485 requestId);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700486 }
487 }
488 };
489 holder.getHandler().post(resultDispatch);
490 } else {
491 Log.w(TAG, String.format(
492 "did not register listener to request %d",
493 requestId));
494 }
495 } else {
496 mFrameNumberRequestPairs.add(
497 new SimpleEntry<Long, Integer>(lastFrameNumber,
498 requestId));
499 }
500 }
501
Jianing Weid2c3a822014-03-27 18:27:43 -0700502 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700503 Handler handler, boolean repeating) throws CameraAccessException {
504
505 // Need a valid handler, or current thread needs to have a looper, if
506 // listener is valid
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700507 if (listener != null) {
508 handler = checkHandler(handler);
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700509 }
Igor Murashkin70725502013-06-25 20:27:06 +0000510
511 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700512 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000513 int requestId;
514
Ruben Brunke73b41b2013-11-07 19:30:43 -0800515 if (repeating) {
516 stopRepeating();
517 }
518
Jianing Weid2c3a822014-03-27 18:27:43 -0700519 LongParcelable lastFrameNumberRef = new LongParcelable();
Igor Murashkin70725502013-06-25 20:27:06 +0000520 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700521 requestId = mRemoteDevice.submitRequestList(requestList, repeating,
522 /*out*/lastFrameNumberRef);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700523 if (DEBUG) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700524 Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
525 }
Igor Murashkin70725502013-06-25 20:27:06 +0000526 } catch (CameraRuntimeException e) {
527 throw e.asChecked();
528 } catch (RemoteException e) {
529 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700530 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000531 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700532
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700533 if (listener != null) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700534 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener,
535 requestList, handler, repeating));
Jianing Weibaf0c652014-04-18 17:35:00 -0700536 } else {
537 if (DEBUG) {
538 Log.d(TAG, "Listen for request " + requestId + " is null");
539 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700540 }
Igor Murashkin70725502013-06-25 20:27:06 +0000541
Jianing Weid2c3a822014-03-27 18:27:43 -0700542 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700543
Igor Murashkin70725502013-06-25 20:27:06 +0000544 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700545 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700546 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700547 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700548 mRepeatingRequestId = requestId;
Jianing Weid2c3a822014-03-27 18:27:43 -0700549 } else {
550 mFrameNumberRequestPairs.add(
551 new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
Igor Murashkin70725502013-06-25 20:27:06 +0000552 }
553
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700554 if (mIdle) {
555 mDeviceHandler.post(mCallOnActive);
556 }
557 mIdle = false;
558
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700559 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000560 }
561 }
562
563 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700564 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700565 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700566 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
567 requestList.add(request);
568 return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000569 }
570
571 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700572 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700573 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700574 if (requests == null || requests.isEmpty()) {
575 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700576 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700577 return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000578 }
579
580 @Override
581 public void stopRepeating() throws CameraAccessException {
582
583 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700584 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700585 if (mRepeatingRequestId != REQUEST_ID_NONE) {
586
587 int requestId = mRepeatingRequestId;
588 mRepeatingRequestId = REQUEST_ID_NONE;
589
590 // Queue for deletion after in-flight requests finish
Zhijun He1a9b6462014-03-31 16:11:33 -0700591 if (mCaptureListenerMap.get(requestId) != null) {
592 mRepeatingRequestIdDeletedList.add(requestId);
593 }
Igor Murashkin70725502013-06-25 20:27:06 +0000594
595 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700596 LongParcelable lastFrameNumberRef = new LongParcelable();
597 mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
598 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700599
600 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
601
Igor Murashkin70725502013-06-25 20:27:06 +0000602 } catch (CameraRuntimeException e) {
603 throw e.asChecked();
604 } catch (RemoteException e) {
605 // impossible
606 return;
607 }
608 }
609 }
610 }
611
Zhijun Hed842fcd2013-12-26 14:14:04 -0800612 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700613
614 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700615 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700616 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700617 throw new IllegalStateException("Active repeating request ongoing");
618 }
619
620 try {
621 mRemoteDevice.waitUntilIdle();
622 } catch (CameraRuntimeException e) {
623 throw e.asChecked();
624 } catch (RemoteException e) {
625 // impossible
626 return;
627 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700628
629 mRepeatingRequestId = REQUEST_ID_NONE;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700630 }
Igor Murashkin70725502013-06-25 20:27:06 +0000631 }
632
633 @Override
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700634 public void flush() throws CameraAccessException {
635 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700636 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700637
638 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700639 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700640 LongParcelable lastFrameNumberRef = new LongParcelable();
641 mRemoteDevice.flush(/*out*/lastFrameNumberRef);
642 if (mRepeatingRequestId != REQUEST_ID_NONE) {
643 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700644 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700645 mRepeatingRequestId = REQUEST_ID_NONE;
646 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700647 } catch (CameraRuntimeException e) {
648 throw e.asChecked();
649 } catch (RemoteException e) {
650 // impossible
651 return;
652 }
653 }
654 }
655
656 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700657 public void close() {
Igor Murashkin70725502013-06-25 20:27:06 +0000658 synchronized (mLock) {
659
660 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700661 if (mRemoteDevice != null) {
662 mRemoteDevice.disconnect();
663 }
Igor Murashkin70725502013-06-25 20:27:06 +0000664 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700665 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000666 } catch (RemoteException e) {
667 // impossible
668 }
669
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700670 // Only want to fire the onClosed callback once;
671 // either a normal close where the remote device is valid
672 // or a close after a startup error (no remote device but in error state)
673 if (mRemoteDevice != null || mInError) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700674 mDeviceHandler.post(mCallOnClosed);
675 }
Igor Murashkin70725502013-06-25 20:27:06 +0000676
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700677 mRemoteDevice = null;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700678 mInError = false;
Igor Murashkin70725502013-06-25 20:27:06 +0000679 }
680 }
681
682 @Override
683 protected void finalize() throws Throwable {
684 try {
685 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000686 }
687 finally {
688 super.finalize();
689 }
690 }
691
692 static class CaptureListenerHolder {
693
694 private final boolean mRepeating;
695 private final CaptureListener mListener;
Jianing Weid2c3a822014-03-27 18:27:43 -0700696 private final List<CaptureRequest> mRequestList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700697 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000698
Jianing Weid2c3a822014-03-27 18:27:43 -0700699 CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList,
700 Handler handler, boolean repeating) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700701 if (listener == null || handler == null) {
702 throw new UnsupportedOperationException(
703 "Must have a valid handler and a valid listener");
704 }
Igor Murashkin70725502013-06-25 20:27:06 +0000705 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700706 mHandler = handler;
Jianing Weid2c3a822014-03-27 18:27:43 -0700707 mRequestList = new ArrayList<CaptureRequest>(requestList);
Igor Murashkin70725502013-06-25 20:27:06 +0000708 mListener = listener;
709 }
710
711 public boolean isRepeating() {
712 return mRepeating;
713 }
714
715 public CaptureListener getListener() {
716 return mListener;
717 }
718
Jianing Weid2c3a822014-03-27 18:27:43 -0700719 public CaptureRequest getRequest(int subsequenceId) {
720 if (subsequenceId >= mRequestList.size()) {
721 throw new IllegalArgumentException(
722 String.format(
723 "Requested subsequenceId %d is larger than request list size %d.",
724 subsequenceId, mRequestList.size()));
725 } else {
726 if (subsequenceId < 0) {
727 throw new IllegalArgumentException(String.format(
728 "Requested subsequenceId %d is negative", subsequenceId));
729 } else {
730 return mRequestList.get(subsequenceId);
731 }
732 }
733 }
734
Igor Murashkin70725502013-06-25 20:27:06 +0000735 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700736 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +0000737 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700738
739 public Handler getHandler() {
740 return mHandler;
741 }
742
Igor Murashkin70725502013-06-25 20:27:06 +0000743 }
744
Jianing Weid2c3a822014-03-27 18:27:43 -0700745 /**
746 * This class tracks the last frame number for submitted requests.
747 */
748 public class FrameNumberTracker {
749
750 private long mCompletedFrameNumber = -1;
751 private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
752
753 private void update() {
754 Iterator<Long> iter = mFutureErrorSet.iterator();
755 while (iter.hasNext()) {
756 long errorFrameNumber = iter.next();
757 if (errorFrameNumber == mCompletedFrameNumber + 1) {
758 mCompletedFrameNumber++;
759 iter.remove();
760 } else {
761 break;
762 }
763 }
764 }
765
766 /**
767 * This function is called every time when a result or an error is received.
768 * @param frameNumber: the frame number corresponding to the result or error
769 * @param isError: true if it is an error, false if it is not an error
770 */
771 public void updateTracker(long frameNumber, boolean isError) {
772 if (isError) {
773 mFutureErrorSet.add(frameNumber);
774 } else {
775 /**
776 * HAL cannot send an OnResultReceived for frame N unless it knows for
777 * sure that all frames prior to N have either errored out or completed.
778 * So if the current frame is not an error, then all previous frames
779 * should have arrived. The following line checks whether this holds.
780 */
781 if (frameNumber != mCompletedFrameNumber + 1) {
Zhijun He22589b42014-05-01 10:37:36 -0700782 Log.e(TAG, String.format(
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700783 "result frame number %d comes out of order, should be %d + 1",
784 frameNumber, mCompletedFrameNumber));
Jianing Weid2c3a822014-03-27 18:27:43 -0700785 }
786 mCompletedFrameNumber++;
787 }
788 update();
789 }
790
791 public long getCompletedFrameNumber() {
792 return mCompletedFrameNumber;
793 }
794
795 }
796
797 private void checkAndFireSequenceComplete() {
798 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
799 Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
800 while (iter.hasNext()) {
801 final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
802 if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
803
804 // remove request from mCaptureListenerMap
805 final int requestId = frameNumberRequestPair.getValue();
806 final CaptureListenerHolder holder;
807 synchronized (mLock) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700808 int index = mCaptureListenerMap.indexOfKey(requestId);
809 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index)
Jianing Weid2c3a822014-03-27 18:27:43 -0700810 : null;
811 if (holder != null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700812 mCaptureListenerMap.removeAt(index);
813 if (DEBUG) {
814 Log.v(TAG, String.format(
815 "remove holder for requestId %d, "
816 + "because lastFrame %d is <= %d",
817 requestId, frameNumberRequestPair.getKey(),
818 completedFrameNumber));
819 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700820 }
821 }
822 iter.remove();
823
824 // Call onCaptureSequenceCompleted
825 if (holder != null) {
826 Runnable resultDispatch = new Runnable() {
827 @Override
828 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700829 if (!CameraDeviceImpl.this.isClosed()){
Jianing Weid2c3a822014-03-27 18:27:43 -0700830 if (DEBUG) {
831 Log.d(TAG, String.format(
832 "fire sequence complete for request %d",
833 requestId));
834 }
835
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700836 long lastFrameNumber = frameNumberRequestPair.getKey();
837 if (lastFrameNumber < Integer.MIN_VALUE
838 || lastFrameNumber > Integer.MAX_VALUE) {
839 throw new AssertionError(lastFrameNumber
840 + " cannot be cast to int");
841 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700842 holder.getListener().onCaptureSequenceCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700843 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -0700844 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -0700845 lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700846 }
847 }
848 };
849 holder.getHandler().post(resultDispatch);
850 }
851
852 }
853 }
854 }
855
Zhijun Heecb323e2013-07-31 09:40:27 -0700856 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +0000857
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700858 //
859 // Constants below need to be kept up-to-date with
860 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
861 //
862
863 //
864 // Error codes for onCameraError
865 //
866
867 /**
868 * Camera has been disconnected
869 */
870 static final int ERROR_CAMERA_DISCONNECTED = 0;
871
872 /**
873 * Camera has encountered a device-level error
874 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
875 */
876 static final int ERROR_CAMERA_DEVICE = 1;
877
878 /**
879 * Camera has encountered a service-level error
880 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
881 */
882 static final int ERROR_CAMERA_SERVICE = 2;
883
Igor Murashkin70725502013-06-25 20:27:06 +0000884 @Override
885 public IBinder asBinder() {
886 return this;
887 }
888
Igor Murashkin70725502013-06-25 20:27:06 +0000889 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700890 public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700891 Runnable r = null;
892 if (isClosed()) return;
893
894 synchronized(mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700895 mInError = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700896 switch (errorCode) {
897 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700898 r = mCallOnDisconnected;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700899 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700900 default:
901 Log.e(TAG, "Unknown error from camera device: " + errorCode);
902 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700903 case ERROR_CAMERA_DEVICE:
904 case ERROR_CAMERA_SERVICE:
905 r = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700906 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700907 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700908 if (!CameraDeviceImpl.this.isClosed()) {
909 mDeviceListener.onError(CameraDeviceImpl.this, errorCode);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700910 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700911 }
912 };
913 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700914 }
Igor Murashkin21547d62014-06-04 15:21:42 -0700915 CameraDeviceImpl.this.mDeviceHandler.post(r);
Zhijun Heecb323e2013-07-31 09:40:27 -0700916 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700917
918 // Fire onCaptureSequenceCompleted
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700919 if (DEBUG) {
920 Log.v(TAG, String.format("got error frame %d", resultExtras.getFrameNumber()));
921 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700922 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true);
923 checkAndFireSequenceComplete();
924
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700925 }
926
927 @Override
928 public void onCameraIdle() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700929 if (isClosed()) return;
930
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700931 if (DEBUG) {
932 Log.d(TAG, "Camera now idle");
933 }
934 synchronized (mLock) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700935 if (!CameraDeviceImpl.this.mIdle) {
936 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnIdle);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700937 }
Igor Murashkin21547d62014-06-04 15:21:42 -0700938 CameraDeviceImpl.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700939 }
940 }
941
942 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700943 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
944 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700945 if (DEBUG) {
946 Log.d(TAG, "Capture started for id " + requestId);
947 }
948 final CaptureListenerHolder holder;
949
950 // Get the listener for this frame ID, if there is one
951 synchronized (mLock) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700952 holder = CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700953 }
954
955 if (holder == null) {
956 return;
957 }
958
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700959 if (isClosed()) return;
960
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700961 // Dispatch capture start notice
962 holder.getHandler().post(
963 new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700964 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700965 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700966 if (!CameraDeviceImpl.this.isClosed()) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700967 holder.getListener().onCaptureStarted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700968 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -0700969 holder.getRequest(resultExtras.getSubsequenceId()),
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700970 timestamp);
971 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700972 }
973 });
Igor Murashkin70725502013-06-25 20:27:06 +0000974 }
975
976 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700977 public void onResultReceived(CameraMetadataNative result,
978 CaptureResultExtras resultExtras) throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -0700979
Jianing Weid2c3a822014-03-27 18:27:43 -0700980 int requestId = resultExtras.getRequestId();
Zhijun Heecb323e2013-07-31 09:40:27 -0700981 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -0700982 Log.v(TAG, "Received result frame " + resultExtras.getFrameNumber() + " for id "
983 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -0700984 }
Ruben Brunk57493682014-05-27 18:58:08 -0700985
986
987 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
988 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
989 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
990
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700991 final CaptureListenerHolder holder;
992 synchronized (mLock) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700993 holder = CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700994 }
Igor Murashkin70725502013-06-25 20:27:06 +0000995
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800996 Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT);
997 boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial);
998
Jianing Weibaf0c652014-04-18 17:35:00 -0700999 // Update tracker (increment counter) when it's not a partial result.
1000 if (!quirkIsPartialResult) {
1001 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/false);
1002 }
1003
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001004 // Check if we have a listener for this
Igor Murashkin70725502013-06-25 20:27:06 +00001005 if (holder == null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001006 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -07001007 Log.d(TAG,
1008 "holder is null, early return at frame "
1009 + resultExtras.getFrameNumber());
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001010 }
Igor Murashkin70725502013-06-25 20:27:06 +00001011 return;
1012 }
1013
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001014 if (isClosed()) {
1015 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -07001016 Log.d(TAG,
1017 "camera is closed, early return at frame "
1018 + resultExtras.getFrameNumber());
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001019 }
1020 return;
1021 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001022
Jianing Weid2c3a822014-03-27 18:27:43 -07001023 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
Igor Murashkindb075af2014-05-21 10:07:08 -07001024
Igor Murashkin70725502013-06-25 20:27:06 +00001025
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001026 Runnable resultDispatch = null;
1027
1028 // Either send a partial result or the final capture completed result
1029 if (quirkIsPartialResult) {
Igor Murashkindb075af2014-05-21 10:07:08 -07001030 final CaptureResult resultAsCapture =
1031 new CaptureResult(result, request, requestId);
1032
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001033 // Partial result
1034 resultDispatch = new Runnable() {
1035 @Override
1036 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001037 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001038 holder.getListener().onCapturePartial(
Igor Murashkin21547d62014-06-04 15:21:42 -07001039 CameraDeviceImpl.this,
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001040 request,
1041 resultAsCapture);
1042 }
1043 }
1044 };
1045 } else {
Igor Murashkindb075af2014-05-21 10:07:08 -07001046 final TotalCaptureResult resultAsCapture =
1047 new TotalCaptureResult(result, request, requestId);
1048
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001049 // Final capture result
1050 resultDispatch = new Runnable() {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -07001051 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001052 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001053 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001054 holder.getListener().onCaptureCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -07001055 CameraDeviceImpl.this,
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001056 request,
1057 resultAsCapture);
1058 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001059 }
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001060 };
1061 }
1062
1063 holder.getHandler().post(resultDispatch);
Jianing Weid2c3a822014-03-27 18:27:43 -07001064
1065 // Fire onCaptureSequenceCompleted
1066 if (!quirkIsPartialResult) {
Jianing Weid2c3a822014-03-27 18:27:43 -07001067 checkAndFireSequenceComplete();
1068 }
Igor Murashkin70725502013-06-25 20:27:06 +00001069 }
1070
1071 }
1072
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001073 /**
Igor Murashkin0b27d342014-05-30 09:45:05 -07001074 * Default handler management.
1075 *
1076 * <p>
1077 * If handler is null, get the current thread's
1078 * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
1079 * </p>
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001080 */
Igor Murashkin0b27d342014-05-30 09:45:05 -07001081 static Handler checkHandler(Handler handler) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001082 if (handler == null) {
1083 Looper looper = Looper.myLooper();
1084 if (looper == null) {
1085 throw new IllegalArgumentException(
1086 "No handler given, and current thread has no looper!");
1087 }
1088 handler = new Handler(looper);
1089 }
1090 return handler;
1091 }
1092
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001093 private void checkIfCameraClosedOrInError() throws CameraAccessException {
1094 if (mInError) {
1095 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
1096 "The camera device has encountered a serious error");
1097 }
Zhijun He7f4d3142013-07-23 07:54:38 -07001098 if (mRemoteDevice == null) {
1099 throw new IllegalStateException("CameraDevice was already closed");
1100 }
1101 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001102
1103 private boolean isClosed() {
1104 synchronized(mLock) {
1105 return (mRemoteDevice == null);
1106 }
1107 }
Ruben Brunk57493682014-05-27 18:58:08 -07001108
1109 private CameraCharacteristics getCharacteristics() {
1110 return mCharacteristics;
1111 }
Igor Murashkin70725502013-06-25 20:27:06 +00001112}