blob: 97950827b6882b0678a5e50b314af2bae093f04d [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()) {
104 mDeviceListener.onOpened(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700105 StateListener sessionListener = mSessionStateListener;
106 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700107 sessionListener.onOpened(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700108 }
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()) {
117 mDeviceListener.onUnconfigured(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700118 StateListener sessionListener = mSessionStateListener;
119 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700120 sessionListener.onUnconfigured(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700121 }
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()) {
130 mDeviceListener.onActive(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700131 StateListener sessionListener = mSessionStateListener;
132 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700133 sessionListener.onActive(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700134 }
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()) {
143 mDeviceListener.onBusy(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700144 StateListener sessionListener = mSessionStateListener;
145 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700146 sessionListener.onBusy(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700147 }
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 Murashkin21547d62014-06-04 15:21:42 -0700155 mDeviceListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700156 StateListener sessionListener = mSessionStateListener;
157 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700158 sessionListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700159 }
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()) {
167 mDeviceListener.onIdle(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700168 StateListener sessionListener = mSessionStateListener;
169 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700170 sessionListener.onIdle(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700171 }
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()) {
180 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700181 StateListener sessionListener = mSessionStateListener;
182 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700183 sessionListener.onDisconnected(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700184 }
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() {
260 public void run() {
261 if (isError) {
262 mDeviceListener.onError(CameraDeviceImpl.this, code);
263 } else {
264 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
265 }
266 }
267 });
268 }
269 }
270
Igor Murashkin70725502013-06-25 20:27:06 +0000271 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700272 public String getId() {
273 return mCameraId;
274 }
275
276 @Override
Igor Murashkin70725502013-06-25 20:27:06 +0000277 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700278 // Treat a null input the same an empty list
279 if (outputs == null) {
280 outputs = new ArrayList<Surface>();
281 }
Igor Murashkin70725502013-06-25 20:27:06 +0000282 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700283 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700284
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700285 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
286 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
287
288 // Determine which streams need to be created, which to be deleted
289 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
290 int streamId = mConfiguredOutputs.keyAt(i);
291 Surface s = mConfiguredOutputs.valueAt(i);
292
293 if (!outputs.contains(s)) {
294 deleteList.add(streamId);
295 } else {
296 addSet.remove(s); // Don't create a stream previously created
297 }
298 }
299
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700300 mDeviceHandler.post(mCallOnBusy);
301 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700302
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700303 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700304 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700305
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700306 mRemoteDevice.beginConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700307 // Delete all streams first (to free up HW resources)
308 for (Integer streamId : deleteList) {
309 mRemoteDevice.deleteStream(streamId);
310 mConfiguredOutputs.delete(streamId);
311 }
312
313 // Add all new streams
314 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000315 // TODO: remove width,height,format since we are ignoring
316 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700317 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
318 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000319 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700320
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700321 mRemoteDevice.endConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700322 } catch (CameraRuntimeException e) {
323 if (e.getReason() == CAMERA_IN_USE) {
324 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700325 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700326 }
327
328 throw e.asChecked();
329 } catch (RemoteException e) {
330 // impossible
331 return;
Igor Murashkin70725502013-06-25 20:27:06 +0000332 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700333
334 if (outputs.size() > 0) {
335 mDeviceHandler.post(mCallOnIdle);
336 } else {
337 mDeviceHandler.post(mCallOnUnconfigured);
338 }
Igor Murashkin70725502013-06-25 20:27:06 +0000339 }
340 }
341
342 @Override
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700343 public void createCaptureSession(List<Surface> outputs,
344 CameraCaptureSession.StateListener listener, Handler handler)
345 throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700346 synchronized (mLock) {
347 if (DEBUG) {
348 Log.d(TAG, "createCaptureSession");
349 }
350
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700351 checkIfCameraClosedOrInError();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700352
353 // TODO: we must be in UNCONFIGURED mode to begin with, or using another session
354
355 // TODO: dont block for this
356 boolean configureSuccess = true;
357 CameraAccessException pendingException = null;
358 try {
359 configureOutputs(outputs); // and then block until IDLE
360 } catch (CameraAccessException e) {
361 configureSuccess = false;
362 pendingException = e;
363 }
364
365 // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
366 CameraCaptureSessionImpl newSession =
367 new CameraCaptureSessionImpl(outputs, listener, handler, this, mDeviceHandler,
368 configureSuccess);
369
370 if (mCurrentSession != null) {
371 mCurrentSession.replaceSessionClose(newSession);
372 }
373
374 // TODO: wait until current session closes, then create the new session
375 mCurrentSession = newSession;
376
377 if (pendingException != null) {
378 throw pendingException;
379 }
380
381 mSessionStateListener = mCurrentSession.getDeviceStateListener();
382 }
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700383 }
384
385 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700386 public CaptureRequest.Builder createCaptureRequest(int templateType)
387 throws CameraAccessException {
Igor Murashkin70725502013-06-25 20:27:06 +0000388 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700389 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000390
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700391 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000392
393 try {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700394 mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000395 } catch (CameraRuntimeException e) {
396 throw e.asChecked();
397 } catch (RemoteException e) {
398 // impossible
399 return null;
400 }
401
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700402 CaptureRequest.Builder builder =
403 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000404
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700405 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000406 }
407 }
408
409 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700410 public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000411 throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700412 if (DEBUG) {
413 Log.d(TAG, "calling capture");
414 }
415 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
416 requestList.add(request);
417 return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000418 }
419
420 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700421 public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700422 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700423 if (requests == null || requests.isEmpty()) {
424 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700425 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700426 return submitCaptureRequest(requests, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000427 }
428
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700429 /**
430 * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
431 * starting and stopping repeating request and flushing.
432 *
433 * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
434 * sent to HAL. Then onCaptureSequenceCompleted is immediately triggered.
435 * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
436 * is added to the list mFrameNumberRequestPairs.</p>
437 *
438 * @param requestId the request ID of the current repeating request.
439 *
440 * @param lastFrameNumber last frame number returned from binder.
441 */
442 private void checkEarlyTriggerSequenceComplete(
443 final int requestId, final long lastFrameNumber) {
444 // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
445 // was never sent to HAL. Should trigger onCaptureSequenceCompleted immediately.
446 if (lastFrameNumber == CaptureListener.NO_FRAMES_CAPTURED) {
447 final CaptureListenerHolder holder;
448 int index = mCaptureListenerMap.indexOfKey(requestId);
449 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index) : null;
450 if (holder != null) {
451 mCaptureListenerMap.removeAt(index);
Jianing Weibaf0c652014-04-18 17:35:00 -0700452 if (DEBUG) {
453 Log.v(TAG, String.format(
454 "remove holder for requestId %d, "
455 + "because lastFrame is %d.",
456 requestId, lastFrameNumber));
457 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700458 }
459
460 if (holder != null) {
461 if (DEBUG) {
462 Log.v(TAG, "immediately trigger onCaptureSequenceCompleted because"
463 + " request did not reach HAL");
464 }
465
466 Runnable resultDispatch = new Runnable() {
467 @Override
468 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700469 if (!CameraDeviceImpl.this.isClosed()) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700470 if (DEBUG) {
471 Log.d(TAG, String.format(
472 "early trigger sequence complete for request %d",
473 requestId));
474 }
475 if (lastFrameNumber < Integer.MIN_VALUE
476 || lastFrameNumber > Integer.MAX_VALUE) {
477 throw new AssertionError(lastFrameNumber + " cannot be cast to int");
478 }
479 holder.getListener().onCaptureSequenceCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700480 CameraDeviceImpl.this,
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700481 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -0700482 lastFrameNumber);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700483 }
484 }
485 };
486 holder.getHandler().post(resultDispatch);
487 } else {
488 Log.w(TAG, String.format(
489 "did not register listener to request %d",
490 requestId));
491 }
492 } else {
493 mFrameNumberRequestPairs.add(
494 new SimpleEntry<Long, Integer>(lastFrameNumber,
495 requestId));
496 }
497 }
498
Jianing Weid2c3a822014-03-27 18:27:43 -0700499 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700500 Handler handler, boolean repeating) throws CameraAccessException {
501
502 // Need a valid handler, or current thread needs to have a looper, if
503 // listener is valid
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700504 if (listener != null) {
505 handler = checkHandler(handler);
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700506 }
Igor Murashkin70725502013-06-25 20:27:06 +0000507
508 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700509 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000510 int requestId;
511
Ruben Brunke73b41b2013-11-07 19:30:43 -0800512 if (repeating) {
513 stopRepeating();
514 }
515
Jianing Weid2c3a822014-03-27 18:27:43 -0700516 LongParcelable lastFrameNumberRef = new LongParcelable();
Igor Murashkin70725502013-06-25 20:27:06 +0000517 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700518 requestId = mRemoteDevice.submitRequestList(requestList, repeating,
519 /*out*/lastFrameNumberRef);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700520 if (DEBUG) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700521 Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
522 }
Igor Murashkin70725502013-06-25 20:27:06 +0000523 } catch (CameraRuntimeException e) {
524 throw e.asChecked();
525 } catch (RemoteException e) {
526 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700527 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000528 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700529
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700530 if (listener != null) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700531 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener,
532 requestList, handler, repeating));
Jianing Weibaf0c652014-04-18 17:35:00 -0700533 } else {
534 if (DEBUG) {
535 Log.d(TAG, "Listen for request " + requestId + " is null");
536 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700537 }
Igor Murashkin70725502013-06-25 20:27:06 +0000538
Jianing Weid2c3a822014-03-27 18:27:43 -0700539 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700540
Igor Murashkin70725502013-06-25 20:27:06 +0000541 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700542 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700543 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700544 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700545 mRepeatingRequestId = requestId;
Jianing Weid2c3a822014-03-27 18:27:43 -0700546 } else {
547 mFrameNumberRequestPairs.add(
548 new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
Igor Murashkin70725502013-06-25 20:27:06 +0000549 }
550
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700551 if (mIdle) {
552 mDeviceHandler.post(mCallOnActive);
553 }
554 mIdle = false;
555
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700556 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000557 }
558 }
559
560 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700561 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700562 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700563 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
564 requestList.add(request);
565 return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000566 }
567
568 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700569 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700570 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700571 if (requests == null || requests.isEmpty()) {
572 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700573 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700574 return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000575 }
576
577 @Override
578 public void stopRepeating() throws CameraAccessException {
579
580 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700581 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700582 if (mRepeatingRequestId != REQUEST_ID_NONE) {
583
584 int requestId = mRepeatingRequestId;
585 mRepeatingRequestId = REQUEST_ID_NONE;
586
587 // Queue for deletion after in-flight requests finish
Zhijun He1a9b6462014-03-31 16:11:33 -0700588 if (mCaptureListenerMap.get(requestId) != null) {
589 mRepeatingRequestIdDeletedList.add(requestId);
590 }
Igor Murashkin70725502013-06-25 20:27:06 +0000591
592 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700593 LongParcelable lastFrameNumberRef = new LongParcelable();
594 mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
595 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700596
597 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
598
Igor Murashkin70725502013-06-25 20:27:06 +0000599 } catch (CameraRuntimeException e) {
600 throw e.asChecked();
601 } catch (RemoteException e) {
602 // impossible
603 return;
604 }
605 }
606 }
607 }
608
Zhijun Hed842fcd2013-12-26 14:14:04 -0800609 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700610
611 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700612 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700613 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700614 throw new IllegalStateException("Active repeating request ongoing");
615 }
616
617 try {
618 mRemoteDevice.waitUntilIdle();
619 } catch (CameraRuntimeException e) {
620 throw e.asChecked();
621 } catch (RemoteException e) {
622 // impossible
623 return;
624 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700625
626 mRepeatingRequestId = REQUEST_ID_NONE;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700627 }
Igor Murashkin70725502013-06-25 20:27:06 +0000628 }
629
630 @Override
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700631 public void flush() throws CameraAccessException {
632 synchronized (mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700633 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700634
635 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700636 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700637 LongParcelable lastFrameNumberRef = new LongParcelable();
638 mRemoteDevice.flush(/*out*/lastFrameNumberRef);
639 if (mRepeatingRequestId != REQUEST_ID_NONE) {
640 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700641 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700642 mRepeatingRequestId = REQUEST_ID_NONE;
643 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700644 } catch (CameraRuntimeException e) {
645 throw e.asChecked();
646 } catch (RemoteException e) {
647 // impossible
648 return;
649 }
650 }
651 }
652
653 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700654 public void close() {
Igor Murashkin70725502013-06-25 20:27:06 +0000655 synchronized (mLock) {
656
657 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700658 if (mRemoteDevice != null) {
659 mRemoteDevice.disconnect();
660 }
Igor Murashkin70725502013-06-25 20:27:06 +0000661 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700662 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000663 } catch (RemoteException e) {
664 // impossible
665 }
666
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700667 // Only want to fire the onClosed callback once;
668 // either a normal close where the remote device is valid
669 // or a close after a startup error (no remote device but in error state)
670 if (mRemoteDevice != null || mInError) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700671 mDeviceHandler.post(mCallOnClosed);
672 }
Igor Murashkin70725502013-06-25 20:27:06 +0000673
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700674 mRemoteDevice = null;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700675 mInError = false;
Igor Murashkin70725502013-06-25 20:27:06 +0000676 }
677 }
678
679 @Override
680 protected void finalize() throws Throwable {
681 try {
682 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000683 }
684 finally {
685 super.finalize();
686 }
687 }
688
689 static class CaptureListenerHolder {
690
691 private final boolean mRepeating;
692 private final CaptureListener mListener;
Jianing Weid2c3a822014-03-27 18:27:43 -0700693 private final List<CaptureRequest> mRequestList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700694 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000695
Jianing Weid2c3a822014-03-27 18:27:43 -0700696 CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList,
697 Handler handler, boolean repeating) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700698 if (listener == null || handler == null) {
699 throw new UnsupportedOperationException(
700 "Must have a valid handler and a valid listener");
701 }
Igor Murashkin70725502013-06-25 20:27:06 +0000702 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700703 mHandler = handler;
Jianing Weid2c3a822014-03-27 18:27:43 -0700704 mRequestList = new ArrayList<CaptureRequest>(requestList);
Igor Murashkin70725502013-06-25 20:27:06 +0000705 mListener = listener;
706 }
707
708 public boolean isRepeating() {
709 return mRepeating;
710 }
711
712 public CaptureListener getListener() {
713 return mListener;
714 }
715
Jianing Weid2c3a822014-03-27 18:27:43 -0700716 public CaptureRequest getRequest(int subsequenceId) {
717 if (subsequenceId >= mRequestList.size()) {
718 throw new IllegalArgumentException(
719 String.format(
720 "Requested subsequenceId %d is larger than request list size %d.",
721 subsequenceId, mRequestList.size()));
722 } else {
723 if (subsequenceId < 0) {
724 throw new IllegalArgumentException(String.format(
725 "Requested subsequenceId %d is negative", subsequenceId));
726 } else {
727 return mRequestList.get(subsequenceId);
728 }
729 }
730 }
731
Igor Murashkin70725502013-06-25 20:27:06 +0000732 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700733 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +0000734 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700735
736 public Handler getHandler() {
737 return mHandler;
738 }
739
Igor Murashkin70725502013-06-25 20:27:06 +0000740 }
741
Jianing Weid2c3a822014-03-27 18:27:43 -0700742 /**
743 * This class tracks the last frame number for submitted requests.
744 */
745 public class FrameNumberTracker {
746
747 private long mCompletedFrameNumber = -1;
748 private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
749
750 private void update() {
751 Iterator<Long> iter = mFutureErrorSet.iterator();
752 while (iter.hasNext()) {
753 long errorFrameNumber = iter.next();
754 if (errorFrameNumber == mCompletedFrameNumber + 1) {
755 mCompletedFrameNumber++;
756 iter.remove();
757 } else {
758 break;
759 }
760 }
761 }
762
763 /**
764 * This function is called every time when a result or an error is received.
765 * @param frameNumber: the frame number corresponding to the result or error
766 * @param isError: true if it is an error, false if it is not an error
767 */
768 public void updateTracker(long frameNumber, boolean isError) {
769 if (isError) {
770 mFutureErrorSet.add(frameNumber);
771 } else {
772 /**
773 * HAL cannot send an OnResultReceived for frame N unless it knows for
774 * sure that all frames prior to N have either errored out or completed.
775 * So if the current frame is not an error, then all previous frames
776 * should have arrived. The following line checks whether this holds.
777 */
778 if (frameNumber != mCompletedFrameNumber + 1) {
Zhijun He22589b42014-05-01 10:37:36 -0700779 Log.e(TAG, String.format(
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700780 "result frame number %d comes out of order, should be %d + 1",
781 frameNumber, mCompletedFrameNumber));
Jianing Weid2c3a822014-03-27 18:27:43 -0700782 }
783 mCompletedFrameNumber++;
784 }
785 update();
786 }
787
788 public long getCompletedFrameNumber() {
789 return mCompletedFrameNumber;
790 }
791
792 }
793
794 private void checkAndFireSequenceComplete() {
795 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
796 Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
797 while (iter.hasNext()) {
798 final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
799 if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
800
801 // remove request from mCaptureListenerMap
802 final int requestId = frameNumberRequestPair.getValue();
803 final CaptureListenerHolder holder;
804 synchronized (mLock) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700805 int index = mCaptureListenerMap.indexOfKey(requestId);
806 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index)
Jianing Weid2c3a822014-03-27 18:27:43 -0700807 : null;
808 if (holder != null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700809 mCaptureListenerMap.removeAt(index);
810 if (DEBUG) {
811 Log.v(TAG, String.format(
812 "remove holder for requestId %d, "
813 + "because lastFrame %d is <= %d",
814 requestId, frameNumberRequestPair.getKey(),
815 completedFrameNumber));
816 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700817 }
818 }
819 iter.remove();
820
821 // Call onCaptureSequenceCompleted
822 if (holder != null) {
823 Runnable resultDispatch = new Runnable() {
824 @Override
825 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700826 if (!CameraDeviceImpl.this.isClosed()){
Jianing Weid2c3a822014-03-27 18:27:43 -0700827 if (DEBUG) {
828 Log.d(TAG, String.format(
829 "fire sequence complete for request %d",
830 requestId));
831 }
832
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700833 long lastFrameNumber = frameNumberRequestPair.getKey();
834 if (lastFrameNumber < Integer.MIN_VALUE
835 || lastFrameNumber > Integer.MAX_VALUE) {
836 throw new AssertionError(lastFrameNumber
837 + " cannot be cast to int");
838 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700839 holder.getListener().onCaptureSequenceCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700840 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -0700841 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -0700842 lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700843 }
844 }
845 };
846 holder.getHandler().post(resultDispatch);
847 }
848
849 }
850 }
851 }
852
Zhijun Heecb323e2013-07-31 09:40:27 -0700853 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +0000854
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700855 //
856 // Constants below need to be kept up-to-date with
857 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
858 //
859
860 //
861 // Error codes for onCameraError
862 //
863
864 /**
865 * Camera has been disconnected
866 */
867 static final int ERROR_CAMERA_DISCONNECTED = 0;
868
869 /**
870 * Camera has encountered a device-level error
871 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
872 */
873 static final int ERROR_CAMERA_DEVICE = 1;
874
875 /**
876 * Camera has encountered a service-level error
877 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
878 */
879 static final int ERROR_CAMERA_SERVICE = 2;
880
Igor Murashkin70725502013-06-25 20:27:06 +0000881 @Override
882 public IBinder asBinder() {
883 return this;
884 }
885
Igor Murashkin70725502013-06-25 20:27:06 +0000886 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700887 public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700888 Runnable r = null;
889 if (isClosed()) return;
890
891 synchronized(mLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700892 mInError = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700893 switch (errorCode) {
894 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700895 r = mCallOnDisconnected;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700896 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700897 default:
898 Log.e(TAG, "Unknown error from camera device: " + errorCode);
899 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700900 case ERROR_CAMERA_DEVICE:
901 case ERROR_CAMERA_SERVICE:
902 r = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700903 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700904 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700905 if (!CameraDeviceImpl.this.isClosed()) {
906 mDeviceListener.onError(CameraDeviceImpl.this, errorCode);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700907 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700908 }
909 };
910 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700911 }
Igor Murashkin21547d62014-06-04 15:21:42 -0700912 CameraDeviceImpl.this.mDeviceHandler.post(r);
Zhijun Heecb323e2013-07-31 09:40:27 -0700913 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700914
915 // Fire onCaptureSequenceCompleted
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700916 if (DEBUG) {
917 Log.v(TAG, String.format("got error frame %d", resultExtras.getFrameNumber()));
918 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700919 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true);
920 checkAndFireSequenceComplete();
921
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700922 }
923
924 @Override
925 public void onCameraIdle() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700926 if (isClosed()) return;
927
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700928 if (DEBUG) {
929 Log.d(TAG, "Camera now idle");
930 }
931 synchronized (mLock) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700932 if (!CameraDeviceImpl.this.mIdle) {
933 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnIdle);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700934 }
Igor Murashkin21547d62014-06-04 15:21:42 -0700935 CameraDeviceImpl.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700936 }
937 }
938
939 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700940 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
941 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700942 if (DEBUG) {
943 Log.d(TAG, "Capture started for id " + requestId);
944 }
945 final CaptureListenerHolder holder;
946
947 // Get the listener for this frame ID, if there is one
948 synchronized (mLock) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700949 holder = CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700950 }
951
952 if (holder == null) {
953 return;
954 }
955
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700956 if (isClosed()) return;
957
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700958 // Dispatch capture start notice
959 holder.getHandler().post(
960 new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700961 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700962 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700963 if (!CameraDeviceImpl.this.isClosed()) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700964 holder.getListener().onCaptureStarted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700965 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -0700966 holder.getRequest(resultExtras.getSubsequenceId()),
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700967 timestamp);
968 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700969 }
970 });
Igor Murashkin70725502013-06-25 20:27:06 +0000971 }
972
973 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -0700974 public void onResultReceived(CameraMetadataNative result,
975 CaptureResultExtras resultExtras) throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -0700976
Jianing Weid2c3a822014-03-27 18:27:43 -0700977 int requestId = resultExtras.getRequestId();
Zhijun Heecb323e2013-07-31 09:40:27 -0700978 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -0700979 Log.v(TAG, "Received result frame " + resultExtras.getFrameNumber() + " for id "
980 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -0700981 }
Ruben Brunk57493682014-05-27 18:58:08 -0700982
983
984 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
985 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
986 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
987
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700988 final CaptureListenerHolder holder;
989 synchronized (mLock) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700990 holder = CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700991 }
Igor Murashkin70725502013-06-25 20:27:06 +0000992
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800993 Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT);
994 boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial);
995
Jianing Weibaf0c652014-04-18 17:35:00 -0700996 // Update tracker (increment counter) when it's not a partial result.
997 if (!quirkIsPartialResult) {
998 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/false);
999 }
1000
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001001 // Check if we have a listener for this
Igor Murashkin70725502013-06-25 20:27:06 +00001002 if (holder == null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001003 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -07001004 Log.d(TAG,
1005 "holder is null, early return at frame "
1006 + resultExtras.getFrameNumber());
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001007 }
Igor Murashkin70725502013-06-25 20:27:06 +00001008 return;
1009 }
1010
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001011 if (isClosed()) {
1012 if (DEBUG) {
Jianing Weibaf0c652014-04-18 17:35:00 -07001013 Log.d(TAG,
1014 "camera is closed, early return at frame "
1015 + resultExtras.getFrameNumber());
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001016 }
1017 return;
1018 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001019
Jianing Weid2c3a822014-03-27 18:27:43 -07001020 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
Igor Murashkindb075af2014-05-21 10:07:08 -07001021
Igor Murashkin70725502013-06-25 20:27:06 +00001022
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001023 Runnable resultDispatch = null;
1024
1025 // Either send a partial result or the final capture completed result
1026 if (quirkIsPartialResult) {
Igor Murashkindb075af2014-05-21 10:07:08 -07001027 final CaptureResult resultAsCapture =
1028 new CaptureResult(result, request, requestId);
1029
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001030 // Partial result
1031 resultDispatch = new Runnable() {
1032 @Override
1033 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001034 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001035 holder.getListener().onCapturePartial(
Igor Murashkin21547d62014-06-04 15:21:42 -07001036 CameraDeviceImpl.this,
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001037 request,
1038 resultAsCapture);
1039 }
1040 }
1041 };
1042 } else {
Igor Murashkindb075af2014-05-21 10:07:08 -07001043 final TotalCaptureResult resultAsCapture =
1044 new TotalCaptureResult(result, request, requestId);
1045
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001046 // Final capture result
1047 resultDispatch = new Runnable() {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -07001048 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001049 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001050 if (!CameraDeviceImpl.this.isClosed()){
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001051 holder.getListener().onCaptureCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -07001052 CameraDeviceImpl.this,
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001053 request,
1054 resultAsCapture);
1055 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001056 }
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001057 };
1058 }
1059
1060 holder.getHandler().post(resultDispatch);
Jianing Weid2c3a822014-03-27 18:27:43 -07001061
1062 // Fire onCaptureSequenceCompleted
1063 if (!quirkIsPartialResult) {
Jianing Weid2c3a822014-03-27 18:27:43 -07001064 checkAndFireSequenceComplete();
1065 }
Igor Murashkin70725502013-06-25 20:27:06 +00001066 }
1067
1068 }
1069
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001070 /**
Igor Murashkin0b27d342014-05-30 09:45:05 -07001071 * Default handler management.
1072 *
1073 * <p>
1074 * If handler is null, get the current thread's
1075 * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
1076 * </p>
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001077 */
Igor Murashkin0b27d342014-05-30 09:45:05 -07001078 static Handler checkHandler(Handler handler) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001079 if (handler == null) {
1080 Looper looper = Looper.myLooper();
1081 if (looper == null) {
1082 throw new IllegalArgumentException(
1083 "No handler given, and current thread has no looper!");
1084 }
1085 handler = new Handler(looper);
1086 }
1087 return handler;
1088 }
1089
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001090 private void checkIfCameraClosedOrInError() throws CameraAccessException {
1091 if (mInError) {
1092 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
1093 "The camera device has encountered a serious error");
1094 }
Zhijun He7f4d3142013-07-23 07:54:38 -07001095 if (mRemoteDevice == null) {
1096 throw new IllegalStateException("CameraDevice was already closed");
1097 }
1098 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001099
1100 private boolean isClosed() {
1101 synchronized(mLock) {
1102 return (mRemoteDevice == null);
1103 }
1104 }
Ruben Brunk57493682014-05-27 18:58:08 -07001105
1106 private CameraCharacteristics getCharacteristics() {
1107 return mCharacteristics;
1108 }
Igor Murashkin70725502013-06-25 20:27:06 +00001109}