blob: d9f3af4f0151096db51cfbd0eff984eca09fcb78 [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
438 * sent to HAL. Then onCaptureSequenceCompleted is immediately triggered.
439 * 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
449 // was never sent to HAL. Should trigger onCaptureSequenceCompleted immediately.
450 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) {
466 Log.v(TAG, "immediately trigger onCaptureSequenceCompleted because"
467 + " 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 }
483 holder.getListener().onCaptureSequenceCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700484 CameraDeviceImpl.this,
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700485 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -0700486 lastFrameNumber);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700487 }
488 }
489 };
490 holder.getHandler().post(resultDispatch);
491 } else {
492 Log.w(TAG, String.format(
493 "did not register listener to request %d",
494 requestId));
495 }
496 } else {
497 mFrameNumberRequestPairs.add(
498 new SimpleEntry<Long, Integer>(lastFrameNumber,
499 requestId));
500 }
501 }
502
Jianing Weid2c3a822014-03-27 18:27:43 -0700503 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700504 Handler handler, boolean repeating) throws CameraAccessException {
505
506 // Need a valid handler, or current thread needs to have a looper, if
507 // listener is valid
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700508 if (listener != null) {
509 handler = checkHandler(handler);
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700510 }
Igor Murashkin70725502013-06-25 20:27:06 +0000511
512 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700513 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000514 int requestId;
515
Ruben Brunke73b41b2013-11-07 19:30:43 -0800516 if (repeating) {
517 stopRepeating();
518 }
519
Jianing Weid2c3a822014-03-27 18:27:43 -0700520 LongParcelable lastFrameNumberRef = new LongParcelable();
Igor Murashkin70725502013-06-25 20:27:06 +0000521 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700522 requestId = mRemoteDevice.submitRequestList(requestList, repeating,
523 /*out*/lastFrameNumberRef);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700524 if (DEBUG) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700525 Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
526 }
Igor Murashkin70725502013-06-25 20:27:06 +0000527 } catch (CameraRuntimeException e) {
528 throw e.asChecked();
529 } catch (RemoteException e) {
530 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700531 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000532 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700533
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700534 if (listener != null) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700535 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener,
536 requestList, handler, repeating));
Jianing Weibaf0c652014-04-18 17:35:00 -0700537 } else {
538 if (DEBUG) {
539 Log.d(TAG, "Listen for request " + requestId + " is null");
540 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700541 }
Igor Murashkin70725502013-06-25 20:27:06 +0000542
Jianing Weid2c3a822014-03-27 18:27:43 -0700543 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700544
Igor Murashkin70725502013-06-25 20:27:06 +0000545 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700546 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700547 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700548 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700549 mRepeatingRequestId = requestId;
Jianing Weid2c3a822014-03-27 18:27:43 -0700550 } else {
551 mFrameNumberRequestPairs.add(
552 new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
Igor Murashkin70725502013-06-25 20:27:06 +0000553 }
554
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700555 if (mIdle) {
556 mDeviceHandler.post(mCallOnActive);
557 }
558 mIdle = false;
559
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700560 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000561 }
562 }
563
564 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700565 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700566 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700567 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
568 requestList.add(request);
569 return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000570 }
571
572 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700573 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700574 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700575 if (requests == null || requests.isEmpty()) {
576 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700577 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700578 return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000579 }
580
581 @Override
582 public void stopRepeating() throws CameraAccessException {
583
584 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700585 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700586 if (mRepeatingRequestId != REQUEST_ID_NONE) {
587
588 int requestId = mRepeatingRequestId;
589 mRepeatingRequestId = REQUEST_ID_NONE;
590
591 // Queue for deletion after in-flight requests finish
Zhijun He1a9b6462014-03-31 16:11:33 -0700592 if (mCaptureListenerMap.get(requestId) != null) {
593 mRepeatingRequestIdDeletedList.add(requestId);
594 }
Igor Murashkin70725502013-06-25 20:27:06 +0000595
596 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700597 LongParcelable lastFrameNumberRef = new LongParcelable();
598 mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
599 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700600
601 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
602
Igor Murashkin70725502013-06-25 20:27:06 +0000603 } catch (CameraRuntimeException e) {
604 throw e.asChecked();
605 } catch (RemoteException e) {
606 // impossible
607 return;
608 }
609 }
610 }
611 }
612
Zhijun Hed842fcd2013-12-26 14:14:04 -0800613 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700614
615 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700616 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700617 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700618 throw new IllegalStateException("Active repeating request ongoing");
619 }
620
621 try {
622 mRemoteDevice.waitUntilIdle();
623 } catch (CameraRuntimeException e) {
624 throw e.asChecked();
625 } catch (RemoteException e) {
626 // impossible
627 return;
628 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700629
630 mRepeatingRequestId = REQUEST_ID_NONE;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700631 }
Igor Murashkin70725502013-06-25 20:27:06 +0000632 }
633
634 @Override
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700635 public void flush() throws CameraAccessException {
636 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700637 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700638
639 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700640 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700641 LongParcelable lastFrameNumberRef = new LongParcelable();
642 mRemoteDevice.flush(/*out*/lastFrameNumberRef);
643 if (mRepeatingRequestId != REQUEST_ID_NONE) {
644 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700645 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700646 mRepeatingRequestId = REQUEST_ID_NONE;
647 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700648 } catch (CameraRuntimeException e) {
649 throw e.asChecked();
650 } catch (RemoteException e) {
651 // impossible
652 return;
653 }
654 }
655 }
656
657 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700658 public void close() {
Igor Murashkin70725502013-06-25 20:27:06 +0000659 synchronized (mLock) {
660
661 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700662 if (mRemoteDevice != null) {
663 mRemoteDevice.disconnect();
664 }
Igor Murashkin70725502013-06-25 20:27:06 +0000665 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700666 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000667 } catch (RemoteException e) {
668 // impossible
669 }
670
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700671 // Only want to fire the onClosed callback once;
672 // either a normal close where the remote device is valid
673 // or a close after a startup error (no remote device but in error state)
674 if (mRemoteDevice != null || mInError) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700675 mDeviceHandler.post(mCallOnClosed);
676 }
Igor Murashkin70725502013-06-25 20:27:06 +0000677
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700678 mRemoteDevice = null;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700679 mInError = false;
Igor Murashkin70725502013-06-25 20:27:06 +0000680 }
681 }
682
683 @Override
684 protected void finalize() throws Throwable {
685 try {
686 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000687 }
688 finally {
689 super.finalize();
690 }
691 }
692
693 static class CaptureListenerHolder {
694
695 private final boolean mRepeating;
696 private final CaptureListener mListener;
Jianing Weid2c3a822014-03-27 18:27:43 -0700697 private final List<CaptureRequest> mRequestList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700698 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000699
Jianing Weid2c3a822014-03-27 18:27:43 -0700700 CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList,
701 Handler handler, boolean repeating) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700702 if (listener == null || handler == null) {
703 throw new UnsupportedOperationException(
704 "Must have a valid handler and a valid listener");
705 }
Igor Murashkin70725502013-06-25 20:27:06 +0000706 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700707 mHandler = handler;
Jianing Weid2c3a822014-03-27 18:27:43 -0700708 mRequestList = new ArrayList<CaptureRequest>(requestList);
Igor Murashkin70725502013-06-25 20:27:06 +0000709 mListener = listener;
710 }
711
712 public boolean isRepeating() {
713 return mRepeating;
714 }
715
716 public CaptureListener getListener() {
717 return mListener;
718 }
719
Jianing Weid2c3a822014-03-27 18:27:43 -0700720 public CaptureRequest getRequest(int subsequenceId) {
721 if (subsequenceId >= mRequestList.size()) {
722 throw new IllegalArgumentException(
723 String.format(
724 "Requested subsequenceId %d is larger than request list size %d.",
725 subsequenceId, mRequestList.size()));
726 } else {
727 if (subsequenceId < 0) {
728 throw new IllegalArgumentException(String.format(
729 "Requested subsequenceId %d is negative", subsequenceId));
730 } else {
731 return mRequestList.get(subsequenceId);
732 }
733 }
734 }
735
Igor Murashkin70725502013-06-25 20:27:06 +0000736 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700737 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +0000738 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700739
740 public Handler getHandler() {
741 return mHandler;
742 }
743
Igor Murashkin70725502013-06-25 20:27:06 +0000744 }
745
Jianing Weid2c3a822014-03-27 18:27:43 -0700746 /**
747 * This class tracks the last frame number for submitted requests.
748 */
749 public class FrameNumberTracker {
750
751 private long mCompletedFrameNumber = -1;
752 private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
753
754 private void update() {
755 Iterator<Long> iter = mFutureErrorSet.iterator();
756 while (iter.hasNext()) {
757 long errorFrameNumber = iter.next();
758 if (errorFrameNumber == mCompletedFrameNumber + 1) {
759 mCompletedFrameNumber++;
760 iter.remove();
761 } else {
762 break;
763 }
764 }
765 }
766
767 /**
768 * This function is called every time when a result or an error is received.
769 * @param frameNumber: the frame number corresponding to the result or error
770 * @param isError: true if it is an error, false if it is not an error
771 */
772 public void updateTracker(long frameNumber, boolean isError) {
773 if (isError) {
774 mFutureErrorSet.add(frameNumber);
775 } else {
776 /**
777 * HAL cannot send an OnResultReceived for frame N unless it knows for
778 * sure that all frames prior to N have either errored out or completed.
779 * So if the current frame is not an error, then all previous frames
780 * should have arrived. The following line checks whether this holds.
781 */
782 if (frameNumber != mCompletedFrameNumber + 1) {
Zhijun He22589b42014-05-01 10:37:36 -0700783 Log.e(TAG, String.format(
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700784 "result frame number %d comes out of order, should be %d + 1",
785 frameNumber, mCompletedFrameNumber));
Jianing Weid2c3a822014-03-27 18:27:43 -0700786 }
787 mCompletedFrameNumber++;
788 }
789 update();
790 }
791
792 public long getCompletedFrameNumber() {
793 return mCompletedFrameNumber;
794 }
795
796 }
797
798 private void checkAndFireSequenceComplete() {
799 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
800 Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
801 while (iter.hasNext()) {
802 final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
803 if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
804
805 // remove request from mCaptureListenerMap
806 final int requestId = frameNumberRequestPair.getValue();
807 final CaptureListenerHolder holder;
808 synchronized (mLock) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700809 int index = mCaptureListenerMap.indexOfKey(requestId);
810 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index)
Jianing Weid2c3a822014-03-27 18:27:43 -0700811 : null;
812 if (holder != null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700813 mCaptureListenerMap.removeAt(index);
814 if (DEBUG) {
815 Log.v(TAG, String.format(
816 "remove holder for requestId %d, "
817 + "because lastFrame %d is <= %d",
818 requestId, frameNumberRequestPair.getKey(),
819 completedFrameNumber));
820 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700821 }
822 }
823 iter.remove();
824
825 // Call onCaptureSequenceCompleted
826 if (holder != null) {
827 Runnable resultDispatch = new Runnable() {
828 @Override
829 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700830 if (!CameraDeviceImpl.this.isClosed()){
Jianing Weid2c3a822014-03-27 18:27:43 -0700831 if (DEBUG) {
832 Log.d(TAG, String.format(
833 "fire sequence complete for request %d",
834 requestId));
835 }
836
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700837 long lastFrameNumber = frameNumberRequestPair.getKey();
838 if (lastFrameNumber < Integer.MIN_VALUE
839 || lastFrameNumber > Integer.MAX_VALUE) {
840 throw new AssertionError(lastFrameNumber
841 + " cannot be cast to int");
842 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700843 holder.getListener().onCaptureSequenceCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700844 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -0700845 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -0700846 lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700847 }
848 }
849 };
850 holder.getHandler().post(resultDispatch);
851 }
852
853 }
854 }
855 }
856
Zhijun Heecb323e2013-07-31 09:40:27 -0700857 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +0000858
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700859 //
860 // Constants below need to be kept up-to-date with
861 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
862 //
863
864 //
865 // Error codes for onCameraError
866 //
867
868 /**
869 * Camera has been disconnected
870 */
871 static final int ERROR_CAMERA_DISCONNECTED = 0;
872
873 /**
874 * Camera has encountered a device-level error
875 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
876 */
877 static final int ERROR_CAMERA_DEVICE = 1;
878
879 /**
880 * Camera has encountered a service-level error
881 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
882 */
883 static final int ERROR_CAMERA_SERVICE = 2;
884
Igor Murashkin70725502013-06-25 20:27:06 +0000885 @Override
886 public IBinder asBinder() {
887 return this;
888 }
889
Igor Murashkin70725502013-06-25 20:27:06 +0000890 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700891 public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700892 Runnable r = null;
893 if (isClosed()) return;
894
895 synchronized(mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700896 mInError = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700897 switch (errorCode) {
898 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700899 r = mCallOnDisconnected;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700900 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700901 default:
902 Log.e(TAG, "Unknown error from camera device: " + errorCode);
903 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700904 case ERROR_CAMERA_DEVICE:
905 case ERROR_CAMERA_SERVICE:
906 r = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700907 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700908 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700909 if (!CameraDeviceImpl.this.isClosed()) {
910 mDeviceListener.onError(CameraDeviceImpl.this, errorCode);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700911 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700912 }
913 };
914 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700915 }
Igor Murashkin21547d62014-06-04 15:21:42 -0700916 CameraDeviceImpl.this.mDeviceHandler.post(r);
Zhijun Heecb323e2013-07-31 09:40:27 -0700917 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700918
919 // Fire onCaptureSequenceCompleted
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700920 if (DEBUG) {
921 Log.v(TAG, String.format("got error frame %d", resultExtras.getFrameNumber()));
922 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700923 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true);
924 checkAndFireSequenceComplete();
925
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700926 }
927
928 @Override
929 public void onCameraIdle() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700930 if (isClosed()) return;
931
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700932 if (DEBUG) {
933 Log.d(TAG, "Camera now idle");
934 }
935 synchronized (mLock) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700936 if (!CameraDeviceImpl.this.mIdle) {
937 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnIdle);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700938 }
Igor Murashkin21547d62014-06-04 15:21:42 -0700939 CameraDeviceImpl.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700940 }
941 }
942
943 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700944 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
945 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700946 if (DEBUG) {
947 Log.d(TAG, "Capture started for id " + requestId);
948 }
949 final CaptureListenerHolder holder;
950
951 // Get the listener for this frame ID, if there is one
952 synchronized (mLock) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700953 holder = CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700954 }
955
956 if (holder == null) {
957 return;
958 }
959
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700960 if (isClosed()) return;
961
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700962 // Dispatch capture start notice
963 holder.getHandler().post(
964 new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700965 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700966 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700967 if (!CameraDeviceImpl.this.isClosed()) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700968 holder.getListener().onCaptureStarted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700969 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -0700970 holder.getRequest(resultExtras.getSubsequenceId()),
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700971 timestamp);
972 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700973 }
974 });
Igor Murashkin70725502013-06-25 20:27:06 +0000975 }
976
977 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700978 public void onResultReceived(CameraMetadataNative result,
979 CaptureResultExtras resultExtras) throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -0700980
Jianing Weid2c3a822014-03-27 18:27:43 -0700981 int requestId = resultExtras.getRequestId();
Zhijun Heecb323e2013-07-31 09:40:27 -0700982 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -0700983 Log.v(TAG, "Received result frame " + resultExtras.getFrameNumber() + " for id "
984 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -0700985 }
Ruben Brunk57493682014-05-27 18:58:08 -0700986
987
988 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
989 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
990 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
991
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700992 final CaptureListenerHolder holder;
993 synchronized (mLock) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700994 holder = CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700995 }
Igor Murashkin70725502013-06-25 20:27:06 +0000996
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800997 Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT);
998 boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial);
999
Jianing Weibaf0c652014-04-18 17:35:00 -07001000 // Update tracker (increment counter) when it's not a partial result.
1001 if (!quirkIsPartialResult) {
1002 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/false);
1003 }
1004
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001005 // Check if we have a listener for this
Igor Murashkin70725502013-06-25 20:27:06 +00001006 if (holder == null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001007 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -07001008 Log.d(TAG,
1009 "holder is null, early return at frame "
1010 + resultExtras.getFrameNumber());
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001011 }
Igor Murashkin70725502013-06-25 20:27:06 +00001012 return;
1013 }
1014
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001015 if (isClosed()) {
1016 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -07001017 Log.d(TAG,
1018 "camera is closed, early return at frame "
1019 + resultExtras.getFrameNumber());
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001020 }
1021 return;
1022 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001023
Jianing Weid2c3a822014-03-27 18:27:43 -07001024 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
Igor Murashkindb075af2014-05-21 10:07:08 -07001025
Igor Murashkin70725502013-06-25 20:27:06 +00001026
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001027 Runnable resultDispatch = null;
1028
1029 // Either send a partial result or the final capture completed result
1030 if (quirkIsPartialResult) {
Igor Murashkindb075af2014-05-21 10:07:08 -07001031 final CaptureResult resultAsCapture =
1032 new CaptureResult(result, request, requestId);
1033
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001034 // Partial result
1035 resultDispatch = new Runnable() {
1036 @Override
1037 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001038 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001039 holder.getListener().onCapturePartial(
Igor Murashkin21547d62014-06-04 15:21:42 -07001040 CameraDeviceImpl.this,
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001041 request,
1042 resultAsCapture);
1043 }
1044 }
1045 };
1046 } else {
Igor Murashkindb075af2014-05-21 10:07:08 -07001047 final TotalCaptureResult resultAsCapture =
1048 new TotalCaptureResult(result, request, requestId);
1049
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001050 // Final capture result
1051 resultDispatch = new Runnable() {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -07001052 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001053 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001054 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001055 holder.getListener().onCaptureCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -07001056 CameraDeviceImpl.this,
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001057 request,
1058 resultAsCapture);
1059 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001060 }
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001061 };
1062 }
1063
1064 holder.getHandler().post(resultDispatch);
Jianing Weid2c3a822014-03-27 18:27:43 -07001065
1066 // Fire onCaptureSequenceCompleted
1067 if (!quirkIsPartialResult) {
Jianing Weid2c3a822014-03-27 18:27:43 -07001068 checkAndFireSequenceComplete();
1069 }
Igor Murashkin70725502013-06-25 20:27:06 +00001070 }
1071
1072 }
1073
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001074 /**
Igor Murashkin0b27d342014-05-30 09:45:05 -07001075 * Default handler management.
1076 *
1077 * <p>
1078 * If handler is null, get the current thread's
1079 * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
1080 * </p>
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001081 */
Igor Murashkin0b27d342014-05-30 09:45:05 -07001082 static Handler checkHandler(Handler handler) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001083 if (handler == null) {
1084 Looper looper = Looper.myLooper();
1085 if (looper == null) {
1086 throw new IllegalArgumentException(
1087 "No handler given, and current thread has no looper!");
1088 }
1089 handler = new Handler(looper);
1090 }
1091 return handler;
1092 }
1093
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001094 private void checkIfCameraClosedOrInError() throws CameraAccessException {
1095 if (mInError) {
1096 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
1097 "The camera device has encountered a serious error");
1098 }
Zhijun He7f4d3142013-07-23 07:54:38 -07001099 if (mRemoteDevice == null) {
1100 throw new IllegalStateException("CameraDevice was already closed");
1101 }
1102 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001103
1104 private boolean isClosed() {
1105 synchronized(mLock) {
1106 return (mRemoteDevice == null);
1107 }
1108 }
Ruben Brunk57493682014-05-27 18:58:08 -07001109
1110 private CameraCharacteristics getCharacteristics() {
1111 return mCharacteristics;
1112 }
Igor Murashkin70725502013-06-25 20:27:06 +00001113}