blob: 463063c1fb2aca23b8231c0654994fc57dd06156 [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;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070022import android.hardware.camera2.CameraMetadata;
Igor Murashkin68f40062013-09-10 12:15:54 -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;
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -070028import android.hardware.camera2.utils.CameraBinderDecorator;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070029import android.hardware.camera2.utils.CameraRuntimeException;
Igor Murashkin70725502013-06-25 20:27:06 +000030import android.os.IBinder;
31import android.os.RemoteException;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070032import android.os.Handler;
33import android.os.Looper;
Igor Murashkin70725502013-06-25 20:27:06 +000034import android.util.Log;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070035import android.util.SparseArray;
Igor Murashkin70725502013-06-25 20:27:06 +000036import android.view.Surface;
37
Igor Murashkin57ea59b2013-08-23 16:55:57 -070038import java.util.ArrayList;
Igor Murashkin70725502013-06-25 20:27:06 +000039import java.util.HashMap;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070040import java.util.HashSet;
Igor Murashkin70725502013-06-25 20:27:06 +000041import java.util.List;
42import java.util.Stack;
43
44/**
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070045 * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
Igor Murashkin70725502013-06-25 20:27:06 +000046 */
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070047public class CameraDevice implements android.hardware.camera2.CameraDevice {
Igor Murashkin70725502013-06-25 20:27:06 +000048
49 private final String TAG;
Zhijun Heecb323e2013-07-31 09:40:27 -070050 private final boolean DEBUG;
Igor Murashkin70725502013-06-25 20:27:06 +000051
52 // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
53 private ICameraDeviceUser mRemoteDevice;
54
55 private final Object mLock = new Object();
56 private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
57
Igor Murashkin5c9eaf62013-09-10 19:35:24 -070058 private StateListener mDeviceListener;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070059 private Handler mDeviceHandler;
60
61 private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
62 new SparseArray<CaptureListenerHolder>();
Igor Murashkin70725502013-06-25 20:27:06 +000063
64 private final Stack<Integer> mRepeatingRequestIdStack = new Stack<Integer>();
Igor Murashkin57ea59b2013-08-23 16:55:57 -070065 // Map stream IDs to Surfaces
66 private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
Igor Murashkin70725502013-06-25 20:27:06 +000067
68 private final String mCameraId;
69
70 public CameraDevice(String cameraId) {
71 mCameraId = cameraId;
72 TAG = String.format("CameraDevice-%s-JV", mCameraId);
Zhijun Heecb323e2013-07-31 09:40:27 -070073 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Igor Murashkin70725502013-06-25 20:27:06 +000074 }
75
76 public CameraDeviceCallbacks getCallbacks() {
77 return mCallbacks;
78 }
79
Igor Murashkin70725502013-06-25 20:27:06 +000080 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -070081 // TODO: Move from decorator to direct binder-mediated exceptions
82 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
Igor Murashkin70725502013-06-25 20:27:06 +000083 }
84
85 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070086 public String getId() {
87 return mCameraId;
88 }
89
90 @Override
Igor Murashkin70725502013-06-25 20:27:06 +000091 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
92 synchronized (mLock) {
Igor Murashkin57ea59b2013-08-23 16:55:57 -070093 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
94 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
95
96 // Determine which streams need to be created, which to be deleted
97 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
98 int streamId = mConfiguredOutputs.keyAt(i);
99 Surface s = mConfiguredOutputs.valueAt(i);
100
101 if (!outputs.contains(s)) {
102 deleteList.add(streamId);
103 } else {
104 addSet.remove(s); // Don't create a stream previously created
105 }
106 }
107
108 try {
109 // TODO: mRemoteDevice.beginConfigure
110
111 // Delete all streams first (to free up HW resources)
112 for (Integer streamId : deleteList) {
113 mRemoteDevice.deleteStream(streamId);
114 mConfiguredOutputs.delete(streamId);
115 }
116
117 // Add all new streams
118 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000119 // TODO: remove width,height,format since we are ignoring
120 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700121 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
122 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000123 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700124
125 // TODO: mRemoteDevice.endConfigure
126 } catch (CameraRuntimeException e) {
127 if (e.getReason() == CAMERA_IN_USE) {
128 throw new IllegalStateException("The camera is currently busy." +
129 " You must call waitUntilIdle before trying to reconfigure.");
130 }
131
132 throw e.asChecked();
133 } catch (RemoteException e) {
134 // impossible
135 return;
Igor Murashkin70725502013-06-25 20:27:06 +0000136 }
137 }
138 }
139
140 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700141 public CaptureRequest.Builder createCaptureRequest(int templateType)
142 throws CameraAccessException {
Igor Murashkin70725502013-06-25 20:27:06 +0000143 synchronized (mLock) {
144
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700145 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000146
147 try {
148 mRemoteDevice.createDefaultRequest(templateType, /* out */templatedRequest);
149 } catch (CameraRuntimeException e) {
150 throw e.asChecked();
151 } catch (RemoteException e) {
152 // impossible
153 return null;
154 }
155
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700156 CaptureRequest.Builder builder =
157 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000158
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700159 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000160 }
161 }
162
163 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700164 public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000165 throws CameraAccessException {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700166 return submitCaptureRequest(request, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000167 }
168
169 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700170 public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700171 Handler handler) throws CameraAccessException {
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700172 if (requests.isEmpty()) {
173 Log.w(TAG, "Capture burst request list is empty, do nothing!");
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700174 return -1;
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700175 }
Igor Murashkin70725502013-06-25 20:27:06 +0000176 // TODO
177 throw new UnsupportedOperationException("Burst capture implemented yet");
178
179 }
180
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700181 private int submitCaptureRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700182 Handler handler, boolean repeating) throws CameraAccessException {
183
184 // Need a valid handler, or current thread needs to have a looper, if
185 // listener is valid
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700186 if (listener != null) {
187 handler = checkHandler(handler);
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700188 }
Igor Murashkin70725502013-06-25 20:27:06 +0000189
190 synchronized (mLock) {
191
192 int requestId;
193
194 try {
195 requestId = mRemoteDevice.submitRequest(request, repeating);
196 } catch (CameraRuntimeException e) {
197 throw e.asChecked();
198 } catch (RemoteException e) {
199 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700200 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000201 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700202 if (listener != null) {
203 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
204 handler, repeating));
205 }
Igor Murashkin70725502013-06-25 20:27:06 +0000206
207 if (repeating) {
208 mRepeatingRequestIdStack.add(requestId);
209 }
210
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700211 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000212 }
213 }
214
215 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700216 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700217 Handler handler) throws CameraAccessException {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700218 return submitCaptureRequest(request, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000219 }
220
221 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700222 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700223 Handler handler) throws CameraAccessException {
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700224 if (requests.isEmpty()) {
225 Log.w(TAG, "Set Repeating burst request list is empty, do nothing!");
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700226 return -1;
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700227 }
Igor Murashkin70725502013-06-25 20:27:06 +0000228 // TODO
229 throw new UnsupportedOperationException("Burst capture implemented yet");
230 }
231
232 @Override
233 public void stopRepeating() throws CameraAccessException {
234
235 synchronized (mLock) {
236
237 while (!mRepeatingRequestIdStack.isEmpty()) {
238 int requestId = mRepeatingRequestIdStack.pop();
239
240 try {
241 mRemoteDevice.cancelRequest(requestId);
242 } catch (CameraRuntimeException e) {
243 throw e.asChecked();
244 } catch (RemoteException e) {
245 // impossible
246 return;
247 }
248 }
249 }
250 }
251
252 @Override
253 public void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700254
255 synchronized (mLock) {
256 checkIfCameraClosed();
257 if (!mRepeatingRequestIdStack.isEmpty()) {
258 throw new IllegalStateException("Active repeating request ongoing");
259 }
260
261 try {
262 mRemoteDevice.waitUntilIdle();
263 } catch (CameraRuntimeException e) {
264 throw e.asChecked();
265 } catch (RemoteException e) {
266 // impossible
267 return;
268 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700269 }
Igor Murashkin70725502013-06-25 20:27:06 +0000270 }
271
272 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700273 public void setDeviceListener(StateListener listener, Handler handler) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700274 synchronized (mLock) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700275 if (listener != null) {
276 handler = checkHandler(handler);
277 }
278
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700279 mDeviceListener = listener;
280 mDeviceHandler = handler;
281 }
Igor Murashkin70725502013-06-25 20:27:06 +0000282 }
283
284 @Override
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700285 public void flush() throws CameraAccessException {
286 synchronized (mLock) {
287 try {
288 mRemoteDevice.flush();
289 } catch (CameraRuntimeException e) {
290 throw e.asChecked();
291 } catch (RemoteException e) {
292 // impossible
293 return;
294 }
295 }
296 }
297
298 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700299 public void close() {
Igor Murashkin70725502013-06-25 20:27:06 +0000300
301 // TODO: every method should throw IllegalStateException after close has been called
302
303 synchronized (mLock) {
304
305 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700306 if (mRemoteDevice != null) {
307 mRemoteDevice.disconnect();
308 }
Igor Murashkin70725502013-06-25 20:27:06 +0000309 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700310 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000311 } catch (RemoteException e) {
312 // impossible
313 }
314
315 mRemoteDevice = null;
316
317 }
318 }
319
320 @Override
321 protected void finalize() throws Throwable {
322 try {
323 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000324 }
325 finally {
326 super.finalize();
327 }
328 }
329
330 static class CaptureListenerHolder {
331
332 private final boolean mRepeating;
333 private final CaptureListener mListener;
334 private final CaptureRequest mRequest;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700335 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000336
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700337 CaptureListenerHolder(CaptureListener listener, CaptureRequest request, Handler handler,
338 boolean repeating) {
339 if (listener == null || handler == null) {
340 throw new UnsupportedOperationException(
341 "Must have a valid handler and a valid listener");
342 }
Igor Murashkin70725502013-06-25 20:27:06 +0000343 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700344 mHandler = handler;
Igor Murashkin70725502013-06-25 20:27:06 +0000345 mRequest = request;
346 mListener = listener;
347 }
348
349 public boolean isRepeating() {
350 return mRepeating;
351 }
352
353 public CaptureListener getListener() {
354 return mListener;
355 }
356
357 public CaptureRequest getRequest() {
358 return mRequest;
359 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700360
361 public Handler getHandler() {
362 return mHandler;
363 }
364
Igor Murashkin70725502013-06-25 20:27:06 +0000365 }
366
Zhijun Heecb323e2013-07-31 09:40:27 -0700367 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +0000368
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700369 //
370 // Constants below need to be kept up-to-date with
371 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
372 //
373
374 //
375 // Error codes for onCameraError
376 //
377
378 /**
379 * Camera has been disconnected
380 */
381 static final int ERROR_CAMERA_DISCONNECTED = 0;
382
383 /**
384 * Camera has encountered a device-level error
385 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
386 */
387 static final int ERROR_CAMERA_DEVICE = 1;
388
389 /**
390 * Camera has encountered a service-level error
391 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
392 */
393 static final int ERROR_CAMERA_SERVICE = 2;
394
Igor Murashkin70725502013-06-25 20:27:06 +0000395 @Override
396 public IBinder asBinder() {
397 return this;
398 }
399
Igor Murashkin70725502013-06-25 20:27:06 +0000400 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700401 public void onCameraError(final int errorCode) {
402 synchronized (mLock) {
403 if (CameraDevice.this.mDeviceListener == null) return;
404 final StateListener listener = CameraDevice.this.mDeviceListener;
405 Runnable r = null;
406 switch (errorCode) {
407 case ERROR_CAMERA_DISCONNECTED:
408 r = new Runnable() {
409 public void run() {
410 listener.onDisconnected(CameraDevice.this);
411 }
412 };
413 break;
414 case ERROR_CAMERA_DEVICE:
415 case ERROR_CAMERA_SERVICE:
416 r = new Runnable() {
417 public void run() {
418 listener.onError(CameraDevice.this, errorCode);
419 }
420 };
421 break;
422 default:
423 Log.e(TAG, "Unknown error from camera device: " + errorCode);
424 }
425 if (r != null) {
426 CameraDevice.this.mDeviceHandler.post(r);
427 }
Zhijun Heecb323e2013-07-31 09:40:27 -0700428 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700429 }
430
431 @Override
432 public void onCameraIdle() {
433 if (DEBUG) {
434 Log.d(TAG, "Camera now idle");
435 }
436 synchronized (mLock) {
437 if (CameraDevice.this.mDeviceListener == null) return;
438 final StateListener listener = CameraDevice.this.mDeviceListener;
439 Runnable r = new Runnable() {
440 public void run() {
441 listener.onIdle(CameraDevice.this);
442 }
443 };
444 CameraDevice.this.mDeviceHandler.post(r);
445 }
446 }
447
448 @Override
449 public void onCaptureStarted(int requestId, final long timestamp) {
450 if (DEBUG) {
451 Log.d(TAG, "Capture started for id " + requestId);
452 }
453 final CaptureListenerHolder holder;
454
455 // Get the listener for this frame ID, if there is one
456 synchronized (mLock) {
457 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
458 }
459
460 if (holder == null) {
461 return;
462 }
463
464 // Dispatch capture start notice
465 holder.getHandler().post(
466 new Runnable() {
467 public void run() {
468 holder.getListener().onCaptureStarted(
469 CameraDevice.this,
470 holder.getRequest(),
471 timestamp);
472 }
473 });
Igor Murashkin70725502013-06-25 20:27:06 +0000474 }
475
476 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700477 public void onResultReceived(int requestId, CameraMetadataNative result)
478 throws RemoteException {
Zhijun Heecb323e2013-07-31 09:40:27 -0700479 if (DEBUG) {
480 Log.d(TAG, "Received result for id " + requestId);
481 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700482 final CaptureListenerHolder holder;
Igor Murashkin70725502013-06-25 20:27:06 +0000483
484 synchronized (mLock) {
485 // TODO: move this whole map into this class to make it more testable,
486 // exposing the methods necessary like subscribeToRequest, unsubscribe..
487 // TODO: make class static class
488
Zhijun Heecb323e2013-07-31 09:40:27 -0700489 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000490
491 // Clean up listener once we no longer expect to see it.
492
493 // TODO: how to handle repeating listeners?
494 // we probably want cancelRequest to return # of times it already enqueued and
495 // keep a counter.
496 if (holder != null && !holder.isRepeating()) {
Zhijun Heecb323e2013-07-31 09:40:27 -0700497 CameraDevice.this.mCaptureListenerMap.remove(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000498 }
499 }
500
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700501 // Check if we have a listener for this
Igor Murashkin70725502013-06-25 20:27:06 +0000502 if (holder == null) {
Igor Murashkin70725502013-06-25 20:27:06 +0000503 return;
504 }
505
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700506 final CaptureRequest request = holder.getRequest();
507 final CaptureResult resultAsCapture = new CaptureResult(result, request, requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000508
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700509 holder.getHandler().post(
510 new Runnable() {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700511 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700512 public void run() {
513 holder.getListener().onCaptureCompleted(
514 CameraDevice.this,
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700515 request,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700516 resultAsCapture);
517 }
518 });
Igor Murashkin70725502013-06-25 20:27:06 +0000519 }
520
521 }
522
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700523 /**
524 * Default handler management. If handler is null, get the current thread's
525 * Looper to create a Handler with. If no looper exists, throw exception.
526 */
527 private Handler checkHandler(Handler handler) {
528 if (handler == null) {
529 Looper looper = Looper.myLooper();
530 if (looper == null) {
531 throw new IllegalArgumentException(
532 "No handler given, and current thread has no looper!");
533 }
534 handler = new Handler(looper);
535 }
536 return handler;
537 }
538
Zhijun He7f4d3142013-07-23 07:54:38 -0700539 private void checkIfCameraClosed() {
540 if (mRemoteDevice == null) {
541 throw new IllegalStateException("CameraDevice was already closed");
542 }
543 }
Igor Murashkin70725502013-06-25 20:27:06 +0000544}