blob: 79ce9df7d51dbcd41b8a7f39c7182fcc09a0d047 [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 Talvalaa6b5ba52014-07-02 16:30:53 -070024import android.hardware.camera2.CameraDevice;
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070025import android.hardware.camera2.CaptureRequest;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070026import android.hardware.camera2.CaptureResult;
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -070027import android.hardware.camera2.CaptureFailure;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070028import android.hardware.camera2.ICameraDeviceCallbacks;
29import android.hardware.camera2.ICameraDeviceUser;
Igor Murashkindb075af2014-05-21 10:07:08 -070030import android.hardware.camera2.TotalCaptureResult;
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -070031import android.hardware.camera2.utils.CameraBinderDecorator;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070032import android.hardware.camera2.utils.CameraRuntimeException;
Igor Murashkin9c595172014-05-12 13:56:20 -070033import android.hardware.camera2.utils.LongParcelable;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070034import android.os.Handler;
Ruben Brunkdecfe952013-10-29 11:00:32 -070035import android.os.IBinder;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070036import android.os.Looper;
Ruben Brunkdecfe952013-10-29 11:00:32 -070037import android.os.RemoteException;
Igor Murashkin70725502013-06-25 20:27:06 +000038import android.util.Log;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070039import android.util.SparseArray;
Igor Murashkin70725502013-06-25 20:27:06 +000040import android.view.Surface;
41
Jianing Weid2c3a822014-03-27 18:27:43 -070042import java.util.AbstractMap.SimpleEntry;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070043import java.util.ArrayList;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070044import java.util.HashSet;
Ruben Brunkdecfe952013-10-29 11:00:32 -070045import java.util.Iterator;
Igor Murashkin70725502013-06-25 20:27:06 +000046import java.util.List;
Jianing Weid2c3a822014-03-27 18:27:43 -070047import java.util.TreeSet;
Igor Murashkin70725502013-06-25 20:27:06 +000048
49/**
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070050 * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
Igor Murashkin70725502013-06-25 20:27:06 +000051 */
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -070052public class CameraDeviceImpl extends CameraDevice {
Igor Murashkin70725502013-06-25 20:27:06 +000053
54 private final String TAG;
Zhijun Heecb323e2013-07-31 09:40:27 -070055 private final boolean DEBUG;
Igor Murashkin70725502013-06-25 20:27:06 +000056
Ruben Brunkdecfe952013-10-29 11:00:32 -070057 private static final int REQUEST_ID_NONE = -1;
58
Igor Murashkin70725502013-06-25 20:27:06 +000059 // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
60 private ICameraDeviceUser mRemoteDevice;
61
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070062 // Lock to synchronize cross-thread access to device public interface
63 private final Object mInterfaceLock = new Object();
Igor Murashkin70725502013-06-25 20:27:06 +000064 private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
65
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070066 private final StateListener mDeviceListener;
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -070067 private volatile StateListenerKK mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070068 private final Handler mDeviceHandler;
69
Igor Murashkin49b2b132014-06-18 19:03:00 -070070 private volatile boolean mClosing = false;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -070071 private boolean mInError = false;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070072 private boolean mIdle = true;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070073
Igor Murashkin21547d62014-06-04 15:21:42 -070074 /** map request IDs to listener/request data */
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070075 private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
76 new SparseArray<CaptureListenerHolder>();
Igor Murashkin70725502013-06-25 20:27:06 +000077
Ruben Brunkdecfe952013-10-29 11:00:32 -070078 private int mRepeatingRequestId = REQUEST_ID_NONE;
79 private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>();
Igor Murashkin57ea59b2013-08-23 16:55:57 -070080 // Map stream IDs to Surfaces
81 private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
Igor Murashkin70725502013-06-25 20:27:06 +000082
83 private final String mCameraId;
Ruben Brunk57493682014-05-27 18:58:08 -070084 private final CameraCharacteristics mCharacteristics;
Zhijun He83159152014-07-16 11:32:59 -070085 private final int mTotalPartialCount;
Igor Murashkin70725502013-06-25 20:27:06 +000086
Jianing Weid2c3a822014-03-27 18:27:43 -070087 /**
88 * A list tracking request and its expected last frame.
89 * Updated when calling ICameraDeviceUser methods.
90 */
91 private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>>
92 mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>();
93
94 /**
95 * An object tracking received frame numbers.
96 * Updated when receiving callbacks from ICameraDeviceCallbacks.
97 */
98 private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
99
Igor Murashkin0b27d342014-05-30 09:45:05 -0700100 private CameraCaptureSessionImpl mCurrentSession;
101
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700102 // Runnables for all state transitions, except error, which needs the
103 // error code argument
104
105 private final Runnable mCallOnOpened = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700106 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700107 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700108 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700109 synchronized(mInterfaceLock) {
110 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700111
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700112 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700113 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700114 if (sessionListener != null) {
115 sessionListener.onOpened(CameraDeviceImpl.this);
116 }
117 mDeviceListener.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700118 }
119 };
120
121 private final Runnable mCallOnUnconfigured = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700122 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700123 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700124 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700125 synchronized(mInterfaceLock) {
126 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700127
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700128 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700129 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700130 if (sessionListener != null) {
131 sessionListener.onUnconfigured(CameraDeviceImpl.this);
132 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700133 }
134 };
135
136 private final Runnable mCallOnActive = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700137 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700138 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700139 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700140 synchronized(mInterfaceLock) {
141 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700142
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700143 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700144 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700145 if (sessionListener != null) {
146 sessionListener.onActive(CameraDeviceImpl.this);
147 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700148 }
149 };
150
151 private final Runnable mCallOnBusy = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700152 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700153 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700154 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700155 synchronized(mInterfaceLock) {
156 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700157
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700158 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700159 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700160 if (sessionListener != null) {
161 sessionListener.onBusy(CameraDeviceImpl.this);
162 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700163 }
164 };
165
166 private final Runnable mCallOnClosed = new Runnable() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700167 private boolean mClosedOnce = false;
168
Jianing Weid2c3a822014-03-27 18:27:43 -0700169 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700170 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700171 if (mClosedOnce) {
172 throw new AssertionError("Don't post #onClosed more than once");
173 }
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700174 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700175 synchronized(mInterfaceLock) {
176 sessionListener = mSessionStateListener;
177 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700178 if (sessionListener != null) {
Igor Murashkin21547d62014-06-04 15:21:42 -0700179 sessionListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700180 }
Sol Boucher4b3f8002014-06-05 13:47:24 -0700181 mDeviceListener.onClosed(CameraDeviceImpl.this);
Igor Murashkin49b2b132014-06-18 19:03:00 -0700182 mClosedOnce = true;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700183 }
184 };
185
186 private final Runnable mCallOnIdle = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700187 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700188 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700189 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700190 synchronized(mInterfaceLock) {
191 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700192
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700193 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700194 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700195 if (sessionListener != null) {
196 sessionListener.onIdle(CameraDeviceImpl.this);
197 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700198 }
199 };
200
201 private final Runnable mCallOnDisconnected = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700202 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700203 public void run() {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700204 StateListenerKK sessionListener = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700205 synchronized(mInterfaceLock) {
206 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700207
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700208 sessionListener = mSessionStateListener;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700209 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700210 if (sessionListener != null) {
211 sessionListener.onDisconnected(CameraDeviceImpl.this);
212 }
213 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700214 }
215 };
216
Igor Murashkin21547d62014-06-04 15:21:42 -0700217 public CameraDeviceImpl(String cameraId, StateListener listener, Handler handler,
Ruben Brunk57493682014-05-27 18:58:08 -0700218 CameraCharacteristics characteristics) {
Zhijun He83159152014-07-16 11:32:59 -0700219 if (cameraId == null || listener == null || handler == null || characteristics == null) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700220 throw new IllegalArgumentException("Null argument given");
221 }
Igor Murashkin70725502013-06-25 20:27:06 +0000222 mCameraId = cameraId;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700223 mDeviceListener = listener;
224 mDeviceHandler = handler;
Ruben Brunk57493682014-05-27 18:58:08 -0700225 mCharacteristics = characteristics;
Eino-Ville Talvalab72d1ef2014-04-28 13:21:18 -0700226
227 final int MAX_TAG_LEN = 23;
228 String tag = String.format("CameraDevice-JV-%s", mCameraId);
229 if (tag.length() > MAX_TAG_LEN) {
230 tag = tag.substring(0, MAX_TAG_LEN);
231 }
232 TAG = tag;
Zhijun Heecb323e2013-07-31 09:40:27 -0700233 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Zhijun He83159152014-07-16 11:32:59 -0700234
235 Integer partialCount =
236 mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
237 if (partialCount == null) {
238 // 1 means partial result is not supported.
239 mTotalPartialCount = 1;
240 } else {
241 mTotalPartialCount = partialCount;
242 }
Igor Murashkin70725502013-06-25 20:27:06 +0000243 }
244
245 public CameraDeviceCallbacks getCallbacks() {
246 return mCallbacks;
247 }
248
Igor Murashkin70725502013-06-25 20:27:06 +0000249 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700250 synchronized(mInterfaceLock) {
251 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700252 // If setRemoteFailure already called, do nothing
253 if (mInError) return;
254
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700255 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
256
257 mDeviceHandler.post(mCallOnOpened);
258 mDeviceHandler.post(mCallOnUnconfigured);
259 }
Igor Murashkin70725502013-06-25 20:27:06 +0000260 }
261
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700262 /**
263 * Call to indicate failed connection to a remote camera device.
264 *
265 * <p>This places the camera device in the error state and informs the listener.
266 * Use in place of setRemoteDevice() when startup fails.</p>
267 */
268 public void setRemoteFailure(final CameraRuntimeException failure) {
269 int failureCode = StateListener.ERROR_CAMERA_DEVICE;
270 boolean failureIsError = true;
271
272 switch (failure.getReason()) {
273 case CameraAccessException.CAMERA_IN_USE:
274 failureCode = StateListener.ERROR_CAMERA_IN_USE;
275 break;
276 case CameraAccessException.MAX_CAMERAS_IN_USE:
277 failureCode = StateListener.ERROR_MAX_CAMERAS_IN_USE;
278 break;
279 case CameraAccessException.CAMERA_DISABLED:
280 failureCode = StateListener.ERROR_CAMERA_DISABLED;
281 break;
282 case CameraAccessException.CAMERA_DISCONNECTED:
283 failureIsError = false;
284 break;
285 case CameraAccessException.CAMERA_ERROR:
286 failureCode = StateListener.ERROR_CAMERA_DEVICE;
287 break;
288 default:
289 Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
290 break;
291 }
292 final int code = failureCode;
293 final boolean isError = failureIsError;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700294 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700295 mInError = true;
296 mDeviceHandler.post(new Runnable() {
Igor Murashkine1442202014-06-09 17:51:24 -0700297 @Override
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700298 public void run() {
299 if (isError) {
300 mDeviceListener.onError(CameraDeviceImpl.this, code);
301 } else {
302 mDeviceListener.onDisconnected(CameraDeviceImpl.this);
303 }
304 }
305 });
306 }
307 }
308
Igor Murashkin70725502013-06-25 20:27:06 +0000309 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700310 public String getId() {
311 return mCameraId;
312 }
313
Igor Murashkin70725502013-06-25 20:27:06 +0000314 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700315 // Leave this here for backwards compatibility with older code using this directly
316 configureOutputsChecked(outputs);
317 }
318
319 /**
320 * Attempt to configure the outputs; the device goes to idle and then configures the
321 * new outputs if possible.
322 *
323 * <p>The configuration may gracefully fail, if there are too many outputs, if the formats
324 * are not supported, or if the sizes for that format is not supported. In this case this
325 * function will return {@code false} and the unconfigured callback will be fired.</p>
326 *
327 * <p>If the configuration succeeds (with 1 or more outputs), then the idle callback is fired.
328 * Unconfiguring the device always fires the idle callback.</p>
329 *
330 * @param outputs a list of one or more surfaces, or {@code null} to unconfigure
331 * @return whether or not the configuration was successful
332 *
333 * @throws CameraAccessException if there were any unexpected problems during configuration
334 */
335 public boolean configureOutputsChecked(List<Surface> outputs) throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700336 // Treat a null input the same an empty list
337 if (outputs == null) {
338 outputs = new ArrayList<Surface>();
339 }
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700340 boolean success = false;
341
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700342 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700343 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700344
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700345 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
346 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
347
348 // Determine which streams need to be created, which to be deleted
349 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
350 int streamId = mConfiguredOutputs.keyAt(i);
351 Surface s = mConfiguredOutputs.valueAt(i);
352
353 if (!outputs.contains(s)) {
354 deleteList.add(streamId);
355 } else {
356 addSet.remove(s); // Don't create a stream previously created
357 }
358 }
359
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700360 mDeviceHandler.post(mCallOnBusy);
361 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700362
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700363 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700364 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700365
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700366 mRemoteDevice.beginConfigure();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700367 // Delete all streams first (to free up HW resources)
368 for (Integer streamId : deleteList) {
369 mRemoteDevice.deleteStream(streamId);
370 mConfiguredOutputs.delete(streamId);
371 }
372
373 // Add all new streams
374 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000375 // TODO: remove width,height,format since we are ignoring
376 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700377 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
378 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000379 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700380
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700381 try {
382 mRemoteDevice.endConfigure();
383 }
384 catch (IllegalArgumentException e) {
385 // OK. camera service can reject stream config if it's not supported by HAL
386 // This is only the result of a programmer misusing the camera2 api.
387 Log.e(TAG, "Stream configuration failed", e);
388 return false;
389 }
390
391 success = true;
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700392 } catch (CameraRuntimeException e) {
393 if (e.getReason() == CAMERA_IN_USE) {
394 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700395 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700396 }
397
398 throw e.asChecked();
399 } catch (RemoteException e) {
400 // impossible
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700401 return false;
402 } finally {
403 if (success && outputs.size() > 0) {
404 mDeviceHandler.post(mCallOnIdle);
405 } else {
406 // Always return to the 'unconfigured' state if we didn't hit a fatal error
407 mDeviceHandler.post(mCallOnUnconfigured);
408 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700409 }
Igor Murashkin70725502013-06-25 20:27:06 +0000410 }
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700411
412 return success;
Igor Murashkin70725502013-06-25 20:27:06 +0000413 }
414
415 @Override
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700416 public void createCaptureSession(List<Surface> outputs,
417 CameraCaptureSession.StateListener listener, Handler handler)
418 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700419 synchronized(mInterfaceLock) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700420 if (DEBUG) {
421 Log.d(TAG, "createCaptureSession");
422 }
423
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700424 checkIfCameraClosedOrInError();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700425
Eino-Ville Talvalad3b85f62014-08-05 15:02:31 -0700426 // Notify current session that it's going away, before starting camera operations
427 // After this call completes, the session is not allowed to call into CameraDeviceImpl
428 if (mCurrentSession != null) {
429 mCurrentSession.replaceSessionClose();
430 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700431
432 // TODO: dont block for this
433 boolean configureSuccess = true;
434 CameraAccessException pendingException = null;
435 try {
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700436 configureSuccess = configureOutputsChecked(outputs); // and then block until IDLE
Igor Murashkin0b27d342014-05-30 09:45:05 -0700437 } catch (CameraAccessException e) {
438 configureSuccess = false;
439 pendingException = e;
Igor Murashkine1442202014-06-09 17:51:24 -0700440 if (DEBUG) {
441 Log.v(TAG, "createCaptureSession - failed with exception ", e);
442 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700443 }
444
445 // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
446 CameraCaptureSessionImpl newSession =
447 new CameraCaptureSessionImpl(outputs, listener, handler, this, mDeviceHandler,
448 configureSuccess);
449
Igor Murashkin0b27d342014-05-30 09:45:05 -0700450 // TODO: wait until current session closes, then create the new session
451 mCurrentSession = newSession;
452
453 if (pendingException != null) {
454 throw pendingException;
455 }
456
457 mSessionStateListener = mCurrentSession.getDeviceStateListener();
458 }
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700459 }
460
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700461 /**
462 * For use by backwards-compatibility code only.
463 */
464 public void setSessionListener(StateListenerKK sessionListener) {
465 synchronized(mInterfaceLock) {
466 mSessionStateListener = sessionListener;
467 }
468 }
469
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700470 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700471 public CaptureRequest.Builder createCaptureRequest(int templateType)
472 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700473 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700474 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000475
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700476 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000477
478 try {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700479 mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000480 } catch (CameraRuntimeException e) {
481 throw e.asChecked();
482 } catch (RemoteException e) {
483 // impossible
484 return null;
485 }
486
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700487 CaptureRequest.Builder builder =
488 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000489
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700490 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000491 }
492 }
493
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700494 public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000495 throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700496 if (DEBUG) {
497 Log.d(TAG, "calling capture");
498 }
499 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
500 requestList.add(request);
501 return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000502 }
503
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700504 public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700505 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700506 if (requests == null || requests.isEmpty()) {
507 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700508 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700509 return submitCaptureRequest(requests, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000510 }
511
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700512 /**
513 * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
514 * starting and stopping repeating request and flushing.
515 *
516 * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700517 * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700518 * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
519 * is added to the list mFrameNumberRequestPairs.</p>
520 *
521 * @param requestId the request ID of the current repeating request.
522 *
523 * @param lastFrameNumber last frame number returned from binder.
524 */
525 private void checkEarlyTriggerSequenceComplete(
526 final int requestId, final long lastFrameNumber) {
527 // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700528 // was never sent to HAL. Should trigger onCaptureSequenceAborted immediately.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700529 if (lastFrameNumber == CaptureListener.NO_FRAMES_CAPTURED) {
530 final CaptureListenerHolder holder;
531 int index = mCaptureListenerMap.indexOfKey(requestId);
532 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index) : null;
533 if (holder != null) {
534 mCaptureListenerMap.removeAt(index);
Jianing Weibaf0c652014-04-18 17:35:00 -0700535 if (DEBUG) {
536 Log.v(TAG, String.format(
537 "remove holder for requestId %d, "
538 + "because lastFrame is %d.",
539 requestId, lastFrameNumber));
540 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700541 }
542
543 if (holder != null) {
544 if (DEBUG) {
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700545 Log.v(TAG, "immediately trigger onCaptureSequenceAborted because"
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700546 + " request did not reach HAL");
547 }
548
549 Runnable resultDispatch = new Runnable() {
550 @Override
551 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700552 if (!CameraDeviceImpl.this.isClosed()) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700553 if (DEBUG) {
554 Log.d(TAG, String.format(
555 "early trigger sequence complete for request %d",
556 requestId));
557 }
558 if (lastFrameNumber < Integer.MIN_VALUE
559 || lastFrameNumber > Integer.MAX_VALUE) {
560 throw new AssertionError(lastFrameNumber + " cannot be cast to int");
561 }
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700562 holder.getListener().onCaptureSequenceAborted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700563 CameraDeviceImpl.this,
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700564 requestId);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700565 }
566 }
567 };
568 holder.getHandler().post(resultDispatch);
569 } else {
570 Log.w(TAG, String.format(
571 "did not register listener to request %d",
572 requestId));
573 }
574 } else {
575 mFrameNumberRequestPairs.add(
576 new SimpleEntry<Long, Integer>(lastFrameNumber,
577 requestId));
578 }
579 }
580
Jianing Weid2c3a822014-03-27 18:27:43 -0700581 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700582 Handler handler, boolean repeating) throws CameraAccessException {
583
584 // Need a valid handler, or current thread needs to have a looper, if
585 // listener is valid
Eino-Ville Talvala7875a882014-07-31 12:47:07 -0700586 handler = checkHandler(handler, listener);
Igor Murashkin70725502013-06-25 20:27:06 +0000587
Ruben Brunk7f2372b2014-07-02 11:05:08 -0700588 // Make sure that there all requests have at least 1 surface; all surfaces are non-null
589 for (CaptureRequest request : requestList) {
590 if (request.getTargets().isEmpty()) {
591 throw new IllegalArgumentException(
592 "Each request must have at least one Surface target");
593 }
594
595 for (Surface surface : request.getTargets()) {
596 if (surface == null) {
597 throw new IllegalArgumentException("Null Surface targets are not allowed");
598 }
599 }
600 }
601
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700602 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700603 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000604 int requestId;
605
Ruben Brunke73b41b2013-11-07 19:30:43 -0800606 if (repeating) {
607 stopRepeating();
608 }
609
Jianing Weid2c3a822014-03-27 18:27:43 -0700610 LongParcelable lastFrameNumberRef = new LongParcelable();
Igor Murashkin70725502013-06-25 20:27:06 +0000611 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700612 requestId = mRemoteDevice.submitRequestList(requestList, repeating,
613 /*out*/lastFrameNumberRef);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700614 if (DEBUG) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700615 Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
616 }
Igor Murashkin70725502013-06-25 20:27:06 +0000617 } catch (CameraRuntimeException e) {
618 throw e.asChecked();
619 } catch (RemoteException e) {
620 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700621 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000622 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700623
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700624 if (listener != null) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700625 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener,
626 requestList, handler, repeating));
Jianing Weibaf0c652014-04-18 17:35:00 -0700627 } else {
628 if (DEBUG) {
629 Log.d(TAG, "Listen for request " + requestId + " is null");
630 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700631 }
Igor Murashkin70725502013-06-25 20:27:06 +0000632
Jianing Weid2c3a822014-03-27 18:27:43 -0700633 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700634
Igor Murashkin70725502013-06-25 20:27:06 +0000635 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -0700636 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700637 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700638 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700639 mRepeatingRequestId = requestId;
Jianing Weid2c3a822014-03-27 18:27:43 -0700640 } else {
641 mFrameNumberRequestPairs.add(
642 new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
Igor Murashkin70725502013-06-25 20:27:06 +0000643 }
644
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700645 if (mIdle) {
646 mDeviceHandler.post(mCallOnActive);
647 }
648 mIdle = false;
649
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700650 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000651 }
652 }
653
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700654 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700655 Handler handler) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700656 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
657 requestList.add(request);
658 return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000659 }
660
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700661 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700662 Handler handler) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700663 if (requests == null || requests.isEmpty()) {
664 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700665 }
Jianing Weid2c3a822014-03-27 18:27:43 -0700666 return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000667 }
668
Igor Murashkin70725502013-06-25 20:27:06 +0000669 public void stopRepeating() throws CameraAccessException {
670
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700671 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700672 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700673 if (mRepeatingRequestId != REQUEST_ID_NONE) {
674
675 int requestId = mRepeatingRequestId;
676 mRepeatingRequestId = REQUEST_ID_NONE;
677
678 // Queue for deletion after in-flight requests finish
Zhijun He1a9b6462014-03-31 16:11:33 -0700679 if (mCaptureListenerMap.get(requestId) != null) {
680 mRepeatingRequestIdDeletedList.add(requestId);
681 }
Igor Murashkin70725502013-06-25 20:27:06 +0000682
683 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700684 LongParcelable lastFrameNumberRef = new LongParcelable();
685 mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
686 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700687
688 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
689
Igor Murashkin70725502013-06-25 20:27:06 +0000690 } catch (CameraRuntimeException e) {
691 throw e.asChecked();
692 } catch (RemoteException e) {
693 // impossible
694 return;
695 }
696 }
697 }
698 }
699
Zhijun Hed842fcd2013-12-26 14:14:04 -0800700 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700701
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700702 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700703 checkIfCameraClosedOrInError();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700704
Ruben Brunkdecfe952013-10-29 11:00:32 -0700705 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700706 throw new IllegalStateException("Active repeating request ongoing");
707 }
Zhijun He7f4d3142013-07-23 07:54:38 -0700708 try {
709 mRemoteDevice.waitUntilIdle();
710 } catch (CameraRuntimeException e) {
711 throw e.asChecked();
712 } catch (RemoteException e) {
713 // impossible
714 return;
715 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700716 }
Igor Murashkin70725502013-06-25 20:27:06 +0000717 }
718
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700719 public void flush() throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700720 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700721 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700722
723 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700724 try {
Jianing Weid2c3a822014-03-27 18:27:43 -0700725 LongParcelable lastFrameNumberRef = new LongParcelable();
726 mRemoteDevice.flush(/*out*/lastFrameNumberRef);
727 if (mRepeatingRequestId != REQUEST_ID_NONE) {
728 long lastFrameNumber = lastFrameNumberRef.getNumber();
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700729 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -0700730 mRepeatingRequestId = REQUEST_ID_NONE;
731 }
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700732 } catch (CameraRuntimeException e) {
733 throw e.asChecked();
734 } catch (RemoteException e) {
735 // impossible
736 return;
737 }
738 }
739 }
740
741 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700742 public void close() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700743 synchronized (mInterfaceLock) {
Igor Murashkin70725502013-06-25 20:27:06 +0000744 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700745 if (mRemoteDevice != null) {
746 mRemoteDevice.disconnect();
747 }
Igor Murashkin70725502013-06-25 20:27:06 +0000748 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700749 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000750 } catch (RemoteException e) {
751 // impossible
752 }
753
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700754 // Only want to fire the onClosed callback once;
755 // either a normal close where the remote device is valid
756 // or a close after a startup error (no remote device but in error state)
757 if (mRemoteDevice != null || mInError) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700758 mDeviceHandler.post(mCallOnClosed);
759 }
Igor Murashkin70725502013-06-25 20:27:06 +0000760
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700761 mRemoteDevice = null;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700762 mInError = false;
Igor Murashkin70725502013-06-25 20:27:06 +0000763 }
764 }
765
766 @Override
767 protected void finalize() throws Throwable {
768 try {
769 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000770 }
771 finally {
772 super.finalize();
773 }
774 }
775
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700776 /**
777 * <p>A listener for tracking the progress of a {@link CaptureRequest}
778 * submitted to the camera device.</p>
779 *
780 */
781 public static abstract class CaptureListener {
782
783 /**
784 * This constant is used to indicate that no images were captured for
785 * the request.
786 *
787 * @hide
788 */
789 public static final int NO_FRAMES_CAPTURED = -1;
790
791 /**
792 * This method is called when the camera device has started capturing
793 * the output image for the request, at the beginning of image exposure.
794 *
795 * @see android.media.MediaActionSound
796 */
797 public void onCaptureStarted(CameraDevice camera,
798 CaptureRequest request, long timestamp) {
799 // default empty implementation
800 }
801
802 /**
803 * This method is called when some results from an image capture are
804 * available.
805 *
806 * @hide
807 */
808 public void onCapturePartial(CameraDevice camera,
809 CaptureRequest request, CaptureResult result) {
810 // default empty implementation
811 }
812
813 /**
814 * This method is called when an image capture makes partial forward progress; some
815 * (but not all) results from an image capture are available.
816 *
817 */
818 public void onCaptureProgressed(CameraDevice camera,
819 CaptureRequest request, CaptureResult partialResult) {
820 // default empty implementation
821 }
822
823 /**
824 * This method is called when an image capture has fully completed and all the
825 * result metadata is available.
826 */
827 public void onCaptureCompleted(CameraDevice camera,
828 CaptureRequest request, TotalCaptureResult result) {
829 // default empty implementation
830 }
831
832 /**
833 * This method is called instead of {@link #onCaptureCompleted} when the
834 * camera device failed to produce a {@link CaptureResult} for the
835 * request.
836 */
837 public void onCaptureFailed(CameraDevice camera,
838 CaptureRequest request, CaptureFailure failure) {
839 // default empty implementation
840 }
841
842 /**
843 * This method is called independently of the others in CaptureListener,
844 * when a capture sequence finishes and all {@link CaptureResult}
845 * or {@link CaptureFailure} for it have been returned via this listener.
846 */
847 public void onCaptureSequenceCompleted(CameraDevice camera,
848 int sequenceId, long frameNumber) {
849 // default empty implementation
850 }
851
852 /**
853 * This method is called independently of the others in CaptureListener,
854 * when a capture sequence aborts before any {@link CaptureResult}
855 * or {@link CaptureFailure} for it have been returned via this listener.
856 */
857 public void onCaptureSequenceAborted(CameraDevice camera,
858 int sequenceId) {
859 // default empty implementation
860 }
861 }
862
863 /**
864 * A listener for notifications about the state of a camera device, adding in the callbacks that
865 * were part of the earlier KK API design, but now only used internally.
866 */
867 public static abstract class StateListenerKK extends StateListener {
868 /**
869 * The method called when a camera device has no outputs configured.
870 *
871 */
872 public void onUnconfigured(CameraDevice camera) {
873 // Default empty implementation
874 }
875
876 /**
877 * The method called when a camera device begins processing
878 * {@link CaptureRequest capture requests}.
879 *
880 */
881 public void onActive(CameraDevice camera) {
882 // Default empty implementation
883 }
884
885 /**
886 * The method called when a camera device is busy.
887 *
888 */
889 public void onBusy(CameraDevice camera) {
890 // Default empty implementation
891 }
892
893 /**
894 * The method called when a camera device has finished processing all
895 * submitted capture requests and has reached an idle state.
896 *
897 */
898 public void onIdle(CameraDevice camera) {
899 // Default empty implementation
900 }
901 }
902
Igor Murashkin70725502013-06-25 20:27:06 +0000903 static class CaptureListenerHolder {
904
905 private final boolean mRepeating;
906 private final CaptureListener mListener;
Jianing Weid2c3a822014-03-27 18:27:43 -0700907 private final List<CaptureRequest> mRequestList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700908 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000909
Jianing Weid2c3a822014-03-27 18:27:43 -0700910 CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList,
911 Handler handler, boolean repeating) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700912 if (listener == null || handler == null) {
913 throw new UnsupportedOperationException(
914 "Must have a valid handler and a valid listener");
915 }
Igor Murashkin70725502013-06-25 20:27:06 +0000916 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700917 mHandler = handler;
Jianing Weid2c3a822014-03-27 18:27:43 -0700918 mRequestList = new ArrayList<CaptureRequest>(requestList);
Igor Murashkin70725502013-06-25 20:27:06 +0000919 mListener = listener;
920 }
921
922 public boolean isRepeating() {
923 return mRepeating;
924 }
925
926 public CaptureListener getListener() {
927 return mListener;
928 }
929
Jianing Weid2c3a822014-03-27 18:27:43 -0700930 public CaptureRequest getRequest(int subsequenceId) {
931 if (subsequenceId >= mRequestList.size()) {
932 throw new IllegalArgumentException(
933 String.format(
934 "Requested subsequenceId %d is larger than request list size %d.",
935 subsequenceId, mRequestList.size()));
936 } else {
937 if (subsequenceId < 0) {
938 throw new IllegalArgumentException(String.format(
939 "Requested subsequenceId %d is negative", subsequenceId));
940 } else {
941 return mRequestList.get(subsequenceId);
942 }
943 }
944 }
945
Igor Murashkin70725502013-06-25 20:27:06 +0000946 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700947 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +0000948 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700949
950 public Handler getHandler() {
951 return mHandler;
952 }
953
Igor Murashkin70725502013-06-25 20:27:06 +0000954 }
955
Jianing Weid2c3a822014-03-27 18:27:43 -0700956 /**
957 * This class tracks the last frame number for submitted requests.
958 */
959 public class FrameNumberTracker {
960
961 private long mCompletedFrameNumber = -1;
962 private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
963
964 private void update() {
965 Iterator<Long> iter = mFutureErrorSet.iterator();
966 while (iter.hasNext()) {
967 long errorFrameNumber = iter.next();
968 if (errorFrameNumber == mCompletedFrameNumber + 1) {
969 mCompletedFrameNumber++;
970 iter.remove();
971 } else {
972 break;
973 }
974 }
975 }
976
977 /**
978 * This function is called every time when a result or an error is received.
979 * @param frameNumber: the frame number corresponding to the result or error
980 * @param isError: true if it is an error, false if it is not an error
981 */
982 public void updateTracker(long frameNumber, boolean isError) {
983 if (isError) {
984 mFutureErrorSet.add(frameNumber);
985 } else {
986 /**
987 * HAL cannot send an OnResultReceived for frame N unless it knows for
988 * sure that all frames prior to N have either errored out or completed.
989 * So if the current frame is not an error, then all previous frames
990 * should have arrived. The following line checks whether this holds.
991 */
992 if (frameNumber != mCompletedFrameNumber + 1) {
Zhijun He22589b42014-05-01 10:37:36 -0700993 Log.e(TAG, String.format(
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700994 "result frame number %d comes out of order, should be %d + 1",
995 frameNumber, mCompletedFrameNumber));
Jianing Weid2c3a822014-03-27 18:27:43 -0700996 }
997 mCompletedFrameNumber++;
998 }
999 update();
1000 }
1001
1002 public long getCompletedFrameNumber() {
1003 return mCompletedFrameNumber;
1004 }
1005
1006 }
1007
1008 private void checkAndFireSequenceComplete() {
1009 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
1010 Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
1011 while (iter.hasNext()) {
1012 final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
1013 if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
1014
1015 // remove request from mCaptureListenerMap
1016 final int requestId = frameNumberRequestPair.getValue();
1017 final CaptureListenerHolder holder;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001018 synchronized(mInterfaceLock) {
1019 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001020 Log.w(TAG, "Camera closed while checking sequences");
1021 return;
1022 }
1023
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001024 int index = mCaptureListenerMap.indexOfKey(requestId);
1025 holder = (index >= 0) ? mCaptureListenerMap.valueAt(index)
Jianing Weid2c3a822014-03-27 18:27:43 -07001026 : null;
1027 if (holder != null) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001028 mCaptureListenerMap.removeAt(index);
1029 if (DEBUG) {
1030 Log.v(TAG, String.format(
1031 "remove holder for requestId %d, "
1032 + "because lastFrame %d is <= %d",
1033 requestId, frameNumberRequestPair.getKey(),
1034 completedFrameNumber));
1035 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001036 }
1037 }
1038 iter.remove();
1039
1040 // Call onCaptureSequenceCompleted
1041 if (holder != null) {
1042 Runnable resultDispatch = new Runnable() {
1043 @Override
1044 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001045 if (!CameraDeviceImpl.this.isClosed()){
Jianing Weid2c3a822014-03-27 18:27:43 -07001046 if (DEBUG) {
1047 Log.d(TAG, String.format(
1048 "fire sequence complete for request %d",
1049 requestId));
1050 }
1051
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001052 long lastFrameNumber = frameNumberRequestPair.getKey();
1053 if (lastFrameNumber < Integer.MIN_VALUE
1054 || lastFrameNumber > Integer.MAX_VALUE) {
1055 throw new AssertionError(lastFrameNumber
1056 + " cannot be cast to int");
1057 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001058 holder.getListener().onCaptureSequenceCompleted(
Igor Murashkin21547d62014-06-04 15:21:42 -07001059 CameraDeviceImpl.this,
Jianing Weid2c3a822014-03-27 18:27:43 -07001060 requestId,
Igor Murashkindb075af2014-05-21 10:07:08 -07001061 lastFrameNumber);
Jianing Weid2c3a822014-03-27 18:27:43 -07001062 }
1063 }
1064 };
1065 holder.getHandler().post(resultDispatch);
1066 }
1067
1068 }
1069 }
1070 }
1071
Zhijun Heecb323e2013-07-31 09:40:27 -07001072 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +00001073
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001074 //
1075 // Constants below need to be kept up-to-date with
1076 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
1077 //
1078
1079 //
1080 // Error codes for onCameraError
1081 //
1082
1083 /**
1084 * Camera has been disconnected
1085 */
1086 static final int ERROR_CAMERA_DISCONNECTED = 0;
1087
1088 /**
1089 * Camera has encountered a device-level error
1090 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
1091 */
1092 static final int ERROR_CAMERA_DEVICE = 1;
1093
1094 /**
1095 * Camera has encountered a service-level error
1096 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
1097 */
1098 static final int ERROR_CAMERA_SERVICE = 2;
1099
Igor Murashkin70725502013-06-25 20:27:06 +00001100 @Override
1101 public IBinder asBinder() {
1102 return this;
1103 }
1104
Igor Murashkin70725502013-06-25 20:27:06 +00001105 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001106 public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001107 Runnable r = null;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001108
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001109 synchronized(mInterfaceLock) {
1110 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001111 return; // Camera already closed
1112 }
1113
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001114 mInError = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001115 switch (errorCode) {
1116 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001117 r = mCallOnDisconnected;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001118 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001119 default:
1120 Log.e(TAG, "Unknown error from camera device: " + errorCode);
1121 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001122 case ERROR_CAMERA_DEVICE:
1123 case ERROR_CAMERA_SERVICE:
1124 r = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -07001125 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001126 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -07001127 if (!CameraDeviceImpl.this.isClosed()) {
1128 mDeviceListener.onError(CameraDeviceImpl.this, errorCode);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001129 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001130 }
1131 };
1132 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001133 }
Igor Murashkin21547d62014-06-04 15:21:42 -07001134 CameraDeviceImpl.this.mDeviceHandler.post(r);
Jianing Weid2c3a822014-03-27 18:27:43 -07001135
Igor Murashkin49b2b132014-06-18 19:03:00 -07001136 // Fire onCaptureSequenceCompleted
1137 if (DEBUG) {
1138 Log.v(TAG, String.format("got error frame %d", resultExtras.getFrameNumber()));
1139 }
1140 mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true);
1141 checkAndFireSequenceComplete();
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001142 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001143 }
1144
1145 @Override
1146 public void onCameraIdle() {
1147 if (DEBUG) {
1148 Log.d(TAG, "Camera now idle");
1149 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001150 synchronized(mInterfaceLock) {
1151 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07001152
Igor Murashkin21547d62014-06-04 15:21:42 -07001153 if (!CameraDeviceImpl.this.mIdle) {
1154 CameraDeviceImpl.this.mDeviceHandler.post(mCallOnIdle);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001155 }
Igor Murashkin21547d62014-06-04 15:21:42 -07001156 CameraDeviceImpl.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001157 }
1158 }
1159
1160 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001161 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
1162 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001163 if (DEBUG) {
1164 Log.d(TAG, "Capture started for id " + requestId);
1165 }
1166 final CaptureListenerHolder holder;
1167
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001168 synchronized(mInterfaceLock) {
1169 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07001170
1171 // Get the listener for this frame ID, if there is one
Igor Murashkin21547d62014-06-04 15:21:42 -07001172 holder = CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001173
Igor Murashkin49b2b132014-06-18 19:03:00 -07001174 if (holder == null) {
1175 return;
1176 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001177
Igor Murashkin49b2b132014-06-18 19:03:00 -07001178 if (isClosed()) return;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001179
Igor Murashkin49b2b132014-06-18 19:03:00 -07001180 // Dispatch capture start notice
1181 holder.getHandler().post(
1182 new Runnable() {
1183 @Override
1184 public void run() {
1185 if (!CameraDeviceImpl.this.isClosed()) {
1186 holder.getListener().onCaptureStarted(
1187 CameraDeviceImpl.this,
1188 holder.getRequest(resultExtras.getSubsequenceId()),
1189 timestamp);
1190 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001191 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001192 });
1193
1194 }
Igor Murashkin70725502013-06-25 20:27:06 +00001195 }
1196
1197 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07001198 public void onResultReceived(CameraMetadataNative result,
1199 CaptureResultExtras resultExtras) throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -07001200
Jianing Weid2c3a822014-03-27 18:27:43 -07001201 int requestId = resultExtras.getRequestId();
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001202 long frameNumber = resultExtras.getFrameNumber();
1203
Zhijun Heecb323e2013-07-31 09:40:27 -07001204 if (DEBUG) {
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001205 Log.v(TAG, "Received result frame " + frameNumber + " for id "
Jianing Weibaf0c652014-04-18 17:35:00 -07001206 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -07001207 }
Ruben Brunk57493682014-05-27 18:58:08 -07001208
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001209 synchronized(mInterfaceLock) {
1210 if (mRemoteDevice == null) return; // Camera already closed
Ruben Brunk57493682014-05-27 18:58:08 -07001211
Igor Murashkin49b2b132014-06-18 19:03:00 -07001212 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
1213 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
1214 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
Ruben Brunk57493682014-05-27 18:58:08 -07001215
Igor Murashkin49b2b132014-06-18 19:03:00 -07001216 final CaptureListenerHolder holder =
1217 CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +00001218
Zhijun He83159152014-07-16 11:32:59 -07001219 boolean isPartialResult =
1220 (resultExtras.getPartialResultCount() < mTotalPartialCount);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001221
Igor Murashkin49b2b132014-06-18 19:03:00 -07001222 // Update tracker (increment counter) when it's not a partial result.
Zhijun He83159152014-07-16 11:32:59 -07001223 if (!isPartialResult) {
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001224 mFrameNumberTracker.updateTracker(frameNumber,
Igor Murashkin49b2b132014-06-18 19:03:00 -07001225 /*error*/false);
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001226 }
Igor Murashkin70725502013-06-25 20:27:06 +00001227
Igor Murashkin49b2b132014-06-18 19:03:00 -07001228 // Check if we have a listener for this
1229 if (holder == null) {
1230 if (DEBUG) {
1231 Log.d(TAG,
1232 "holder is null, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001233 + frameNumber);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001234 }
1235 return;
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001236 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001237
Igor Murashkin49b2b132014-06-18 19:03:00 -07001238 if (isClosed()) {
1239 if (DEBUG) {
1240 Log.d(TAG,
1241 "camera is closed, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001242 + frameNumber);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001243 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001244 return;
1245 }
Igor Murashkindb075af2014-05-21 10:07:08 -07001246
Igor Murashkin49b2b132014-06-18 19:03:00 -07001247 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
1248
1249
1250 Runnable resultDispatch = null;
1251
1252 // Either send a partial result or the final capture completed result
Zhijun He83159152014-07-16 11:32:59 -07001253 if (isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001254 final CaptureResult resultAsCapture =
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001255 new CaptureResult(result, request, resultExtras);
Igor Murashkin49b2b132014-06-18 19:03:00 -07001256
1257 // Partial result
1258 resultDispatch = new Runnable() {
1259 @Override
1260 public void run() {
1261 if (!CameraDeviceImpl.this.isClosed()){
Zhijun Hefac77c42014-07-18 14:20:48 -07001262 holder.getListener().onCaptureProgressed(
Igor Murashkin49b2b132014-06-18 19:03:00 -07001263 CameraDeviceImpl.this,
1264 request,
1265 resultAsCapture);
1266 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001267 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07001268 };
1269 } else {
1270 final TotalCaptureResult resultAsCapture =
Igor Murashkinbdf366c2014-07-25 16:54:20 -07001271 new TotalCaptureResult(result, request, resultExtras);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08001272
Igor Murashkin49b2b132014-06-18 19:03:00 -07001273 // Final capture result
1274 resultDispatch = new Runnable() {
1275 @Override
1276 public void run() {
1277 if (!CameraDeviceImpl.this.isClosed()){
1278 holder.getListener().onCaptureCompleted(
1279 CameraDeviceImpl.this,
1280 request,
1281 resultAsCapture);
1282 }
1283 }
1284 };
1285 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001286
Igor Murashkin49b2b132014-06-18 19:03:00 -07001287 holder.getHandler().post(resultDispatch);
1288
1289 // Fire onCaptureSequenceCompleted
Zhijun He83159152014-07-16 11:32:59 -07001290 if (!isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001291 checkAndFireSequenceComplete();
1292 }
1293
Jianing Weid2c3a822014-03-27 18:27:43 -07001294 }
Igor Murashkin70725502013-06-25 20:27:06 +00001295 }
1296
1297 }
1298
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001299 /**
Igor Murashkin0b27d342014-05-30 09:45:05 -07001300 * Default handler management.
1301 *
1302 * <p>
1303 * If handler is null, get the current thread's
1304 * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
1305 * </p>
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001306 */
Igor Murashkin0b27d342014-05-30 09:45:05 -07001307 static Handler checkHandler(Handler handler) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001308 if (handler == null) {
1309 Looper looper = Looper.myLooper();
1310 if (looper == null) {
1311 throw new IllegalArgumentException(
1312 "No handler given, and current thread has no looper!");
1313 }
1314 handler = new Handler(looper);
1315 }
1316 return handler;
1317 }
1318
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07001319 /**
1320 * Default handler management, conditional on there being a listener.
1321 *
1322 * <p>If the listener isn't null, check the handler, otherwise pass it through.</p>
1323 */
1324 static <T> Handler checkHandler(Handler handler, T listener) {
1325 if (listener != null) {
1326 return checkHandler(handler);
1327 }
1328 return handler;
1329 }
1330
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001331 private void checkIfCameraClosedOrInError() throws CameraAccessException {
1332 if (mInError) {
1333 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
1334 "The camera device has encountered a serious error");
1335 }
Zhijun He7f4d3142013-07-23 07:54:38 -07001336 if (mRemoteDevice == null) {
1337 throw new IllegalStateException("CameraDevice was already closed");
1338 }
1339 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001340
Igor Murashkin49b2b132014-06-18 19:03:00 -07001341 /** Whether the camera device has started to close (may not yet have finished) */
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001342 private boolean isClosed() {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001343 return mClosing;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001344 }
Ruben Brunk57493682014-05-27 18:58:08 -07001345
1346 private CameraCharacteristics getCharacteristics() {
1347 return mCharacteristics;
1348 }
Igor Murashkin70725502013-06-25 20:27:06 +00001349}