blob: c5d0999213068cbe0439cda4b6915e4ae4b419c0 [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
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070058 private final StateListener mDeviceListener;
59 private final Handler mDeviceHandler;
60
61 private boolean mIdle = true;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070062
63 private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
64 new SparseArray<CaptureListenerHolder>();
Igor Murashkin70725502013-06-25 20:27:06 +000065
66 private final Stack<Integer> mRepeatingRequestIdStack = new Stack<Integer>();
Igor Murashkin57ea59b2013-08-23 16:55:57 -070067 // Map stream IDs to Surfaces
68 private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
Igor Murashkin70725502013-06-25 20:27:06 +000069
70 private final String mCameraId;
71
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070072 // Runnables for all state transitions, except error, which needs the
73 // error code argument
74
75 private final Runnable mCallOnOpened = new Runnable() {
76 public void run() {
77 if (!CameraDevice.this.isClosed()) {
78 mDeviceListener.onOpened(CameraDevice.this);
79 }
80 }
81 };
82
83 private final Runnable mCallOnUnconfigured = new Runnable() {
84 public void run() {
85 if (!CameraDevice.this.isClosed()) {
86 mDeviceListener.onUnconfigured(CameraDevice.this);
87 }
88 }
89 };
90
91 private final Runnable mCallOnActive = new Runnable() {
92 public void run() {
93 if (!CameraDevice.this.isClosed()) {
94 mDeviceListener.onActive(CameraDevice.this);
95 }
96 }
97 };
98
99 private final Runnable mCallOnBusy = new Runnable() {
100 public void run() {
101 if (!CameraDevice.this.isClosed()) {
102 mDeviceListener.onBusy(CameraDevice.this);
103 }
104 }
105 };
106
107 private final Runnable mCallOnClosed = new Runnable() {
108 public void run() {
109 if (!CameraDevice.this.isClosed()) {
110 mDeviceListener.onClosed(CameraDevice.this);
111 }
112 }
113 };
114
115 private final Runnable mCallOnIdle = new Runnable() {
116 public void run() {
117 if (!CameraDevice.this.isClosed()) {
118 mDeviceListener.onIdle(CameraDevice.this);
119 }
120 }
121 };
122
123 private final Runnable mCallOnDisconnected = new Runnable() {
124 public void run() {
125 if (!CameraDevice.this.isClosed()) {
126 mDeviceListener.onDisconnected(CameraDevice.this);
127 }
128 }
129 };
130
131 public CameraDevice(String cameraId, StateListener listener, Handler handler) {
132 if (cameraId == null || listener == null || handler == null) {
133 throw new IllegalArgumentException("Null argument given");
134 }
Igor Murashkin70725502013-06-25 20:27:06 +0000135 mCameraId = cameraId;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700136 mDeviceListener = listener;
137 mDeviceHandler = handler;
Igor Murashkin70725502013-06-25 20:27:06 +0000138 TAG = String.format("CameraDevice-%s-JV", mCameraId);
Zhijun Heecb323e2013-07-31 09:40:27 -0700139 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Igor Murashkin70725502013-06-25 20:27:06 +0000140 }
141
142 public CameraDeviceCallbacks getCallbacks() {
143 return mCallbacks;
144 }
145
Igor Murashkin70725502013-06-25 20:27:06 +0000146 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -0700147 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700148 synchronized(mLock) {
149 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
150
151 mDeviceHandler.post(mCallOnOpened);
152 mDeviceHandler.post(mCallOnUnconfigured);
153 }
Igor Murashkin70725502013-06-25 20:27:06 +0000154 }
155
156 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700157 public String getId() {
158 return mCameraId;
159 }
160
161 @Override
Igor Murashkin70725502013-06-25 20:27:06 +0000162 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700163 // Treat a null input the same an empty list
164 if (outputs == null) {
165 outputs = new ArrayList<Surface>();
166 }
Igor Murashkin70725502013-06-25 20:27:06 +0000167 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700168 checkIfCameraClosed();
169
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700170 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
171 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
172
173 // Determine which streams need to be created, which to be deleted
174 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
175 int streamId = mConfiguredOutputs.keyAt(i);
176 Surface s = mConfiguredOutputs.valueAt(i);
177
178 if (!outputs.contains(s)) {
179 deleteList.add(streamId);
180 } else {
181 addSet.remove(s); // Don't create a stream previously created
182 }
183 }
184
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700185 mDeviceHandler.post(mCallOnBusy);
186 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700187
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700188 try {
189 mRemoteDevice.waitUntilIdle();
190
191 // TODO: mRemoteDevice.beginConfigure
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700192 // Delete all streams first (to free up HW resources)
193 for (Integer streamId : deleteList) {
194 mRemoteDevice.deleteStream(streamId);
195 mConfiguredOutputs.delete(streamId);
196 }
197
198 // Add all new streams
199 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000200 // TODO: remove width,height,format since we are ignoring
201 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700202 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
203 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000204 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700205
206 // TODO: mRemoteDevice.endConfigure
207 } catch (CameraRuntimeException e) {
208 if (e.getReason() == CAMERA_IN_USE) {
209 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700210 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700211 }
212
213 throw e.asChecked();
214 } catch (RemoteException e) {
215 // impossible
216 return;
Igor Murashkin70725502013-06-25 20:27:06 +0000217 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700218
219 if (outputs.size() > 0) {
220 mDeviceHandler.post(mCallOnIdle);
221 } else {
222 mDeviceHandler.post(mCallOnUnconfigured);
223 }
Igor Murashkin70725502013-06-25 20:27:06 +0000224 }
225 }
226
227 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700228 public CaptureRequest.Builder createCaptureRequest(int templateType)
229 throws CameraAccessException {
Igor Murashkin70725502013-06-25 20:27:06 +0000230 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700231 checkIfCameraClosed();
Igor Murashkin70725502013-06-25 20:27:06 +0000232
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700233 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000234
235 try {
236 mRemoteDevice.createDefaultRequest(templateType, /* out */templatedRequest);
237 } catch (CameraRuntimeException e) {
238 throw e.asChecked();
239 } catch (RemoteException e) {
240 // impossible
241 return null;
242 }
243
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700244 CaptureRequest.Builder builder =
245 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000246
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700247 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000248 }
249 }
250
251 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700252 public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000253 throws CameraAccessException {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700254 return submitCaptureRequest(request, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000255 }
256
257 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700258 public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700259 Handler handler) throws CameraAccessException {
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700260 if (requests.isEmpty()) {
261 Log.w(TAG, "Capture burst request list is empty, do nothing!");
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700262 return -1;
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700263 }
Igor Murashkin70725502013-06-25 20:27:06 +0000264 // TODO
265 throw new UnsupportedOperationException("Burst capture implemented yet");
266
267 }
268
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700269 private int submitCaptureRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700270 Handler handler, boolean repeating) throws CameraAccessException {
271
272 // Need a valid handler, or current thread needs to have a looper, if
273 // listener is valid
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700274 if (listener != null) {
275 handler = checkHandler(handler);
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700276 }
Igor Murashkin70725502013-06-25 20:27:06 +0000277
278 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700279 checkIfCameraClosed();
Igor Murashkin70725502013-06-25 20:27:06 +0000280 int requestId;
281
282 try {
283 requestId = mRemoteDevice.submitRequest(request, repeating);
284 } catch (CameraRuntimeException e) {
285 throw e.asChecked();
286 } catch (RemoteException e) {
287 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700288 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000289 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700290 if (listener != null) {
291 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
292 handler, repeating));
293 }
Igor Murashkin70725502013-06-25 20:27:06 +0000294
295 if (repeating) {
296 mRepeatingRequestIdStack.add(requestId);
297 }
298
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700299 if (mIdle) {
300 mDeviceHandler.post(mCallOnActive);
301 }
302 mIdle = false;
303
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700304 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000305 }
306 }
307
308 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700309 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700310 Handler handler) throws CameraAccessException {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700311 return submitCaptureRequest(request, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000312 }
313
314 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700315 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700316 Handler handler) throws CameraAccessException {
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700317 if (requests.isEmpty()) {
318 Log.w(TAG, "Set Repeating burst request list is empty, do nothing!");
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700319 return -1;
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700320 }
Igor Murashkin70725502013-06-25 20:27:06 +0000321 // TODO
322 throw new UnsupportedOperationException("Burst capture implemented yet");
323 }
324
325 @Override
326 public void stopRepeating() throws CameraAccessException {
327
328 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700329 checkIfCameraClosed();
Igor Murashkin70725502013-06-25 20:27:06 +0000330 while (!mRepeatingRequestIdStack.isEmpty()) {
331 int requestId = mRepeatingRequestIdStack.pop();
332
333 try {
334 mRemoteDevice.cancelRequest(requestId);
335 } catch (CameraRuntimeException e) {
336 throw e.asChecked();
337 } catch (RemoteException e) {
338 // impossible
339 return;
340 }
341 }
342 }
343 }
344
345 @Override
346 public void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700347
348 synchronized (mLock) {
349 checkIfCameraClosed();
350 if (!mRepeatingRequestIdStack.isEmpty()) {
351 throw new IllegalStateException("Active repeating request ongoing");
352 }
353
354 try {
355 mRemoteDevice.waitUntilIdle();
356 } catch (CameraRuntimeException e) {
357 throw e.asChecked();
358 } catch (RemoteException e) {
359 // impossible
360 return;
361 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700362 }
Igor Murashkin70725502013-06-25 20:27:06 +0000363 }
364
365 @Override
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700366 public void flush() throws CameraAccessException {
367 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700368 checkIfCameraClosed();
369
370 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700371 try {
372 mRemoteDevice.flush();
373 } catch (CameraRuntimeException e) {
374 throw e.asChecked();
375 } catch (RemoteException e) {
376 // impossible
377 return;
378 }
379 }
380 }
381
382 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700383 public void close() {
Igor Murashkin70725502013-06-25 20:27:06 +0000384 synchronized (mLock) {
385
386 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700387 if (mRemoteDevice != null) {
388 mRemoteDevice.disconnect();
389 }
Igor Murashkin70725502013-06-25 20:27:06 +0000390 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700391 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000392 } catch (RemoteException e) {
393 // impossible
394 }
395
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700396 if (mRemoteDevice != null) {
397 mDeviceHandler.post(mCallOnClosed);
398 }
Igor Murashkin70725502013-06-25 20:27:06 +0000399
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700400 mRemoteDevice = null;
Igor Murashkin70725502013-06-25 20:27:06 +0000401 }
402 }
403
404 @Override
405 protected void finalize() throws Throwable {
406 try {
407 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000408 }
409 finally {
410 super.finalize();
411 }
412 }
413
414 static class CaptureListenerHolder {
415
416 private final boolean mRepeating;
417 private final CaptureListener mListener;
418 private final CaptureRequest mRequest;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700419 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000420
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700421 CaptureListenerHolder(CaptureListener listener, CaptureRequest request, Handler handler,
422 boolean repeating) {
423 if (listener == null || handler == null) {
424 throw new UnsupportedOperationException(
425 "Must have a valid handler and a valid listener");
426 }
Igor Murashkin70725502013-06-25 20:27:06 +0000427 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700428 mHandler = handler;
Igor Murashkin70725502013-06-25 20:27:06 +0000429 mRequest = request;
430 mListener = listener;
431 }
432
433 public boolean isRepeating() {
434 return mRepeating;
435 }
436
437 public CaptureListener getListener() {
438 return mListener;
439 }
440
441 public CaptureRequest getRequest() {
442 return mRequest;
443 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700444
445 public Handler getHandler() {
446 return mHandler;
447 }
448
Igor Murashkin70725502013-06-25 20:27:06 +0000449 }
450
Zhijun Heecb323e2013-07-31 09:40:27 -0700451 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +0000452
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700453 //
454 // Constants below need to be kept up-to-date with
455 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
456 //
457
458 //
459 // Error codes for onCameraError
460 //
461
462 /**
463 * Camera has been disconnected
464 */
465 static final int ERROR_CAMERA_DISCONNECTED = 0;
466
467 /**
468 * Camera has encountered a device-level error
469 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
470 */
471 static final int ERROR_CAMERA_DEVICE = 1;
472
473 /**
474 * Camera has encountered a service-level error
475 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
476 */
477 static final int ERROR_CAMERA_SERVICE = 2;
478
Igor Murashkin70725502013-06-25 20:27:06 +0000479 @Override
480 public IBinder asBinder() {
481 return this;
482 }
483
Igor Murashkin70725502013-06-25 20:27:06 +0000484 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700485 public void onCameraError(final int errorCode) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700486 Runnable r = null;
487 if (isClosed()) return;
488
489 synchronized(mLock) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700490 switch (errorCode) {
491 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700492 r = mCallOnDisconnected;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700493 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700494 default:
495 Log.e(TAG, "Unknown error from camera device: " + errorCode);
496 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700497 case ERROR_CAMERA_DEVICE:
498 case ERROR_CAMERA_SERVICE:
499 r = new Runnable() {
500 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700501 if (!CameraDevice.this.isClosed()) {
502 mDeviceListener.onError(CameraDevice.this, errorCode);
503 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700504 }
505 };
506 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700507 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700508 CameraDevice.this.mDeviceHandler.post(r);
Zhijun Heecb323e2013-07-31 09:40:27 -0700509 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700510 }
511
512 @Override
513 public void onCameraIdle() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700514 if (isClosed()) return;
515
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700516 if (DEBUG) {
517 Log.d(TAG, "Camera now idle");
518 }
519 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700520 if (!CameraDevice.this.mIdle) {
521 CameraDevice.this.mDeviceHandler.post(mCallOnIdle);
522 }
523 CameraDevice.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700524 }
525 }
526
527 @Override
528 public void onCaptureStarted(int requestId, final long timestamp) {
529 if (DEBUG) {
530 Log.d(TAG, "Capture started for id " + requestId);
531 }
532 final CaptureListenerHolder holder;
533
534 // Get the listener for this frame ID, if there is one
535 synchronized (mLock) {
536 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
537 }
538
539 if (holder == null) {
540 return;
541 }
542
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700543 if (isClosed()) return;
544
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700545 // Dispatch capture start notice
546 holder.getHandler().post(
547 new Runnable() {
548 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700549 if (!CameraDevice.this.isClosed()) {
550 holder.getListener().onCaptureStarted(
551 CameraDevice.this,
552 holder.getRequest(),
553 timestamp);
554 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700555 }
556 });
Igor Murashkin70725502013-06-25 20:27:06 +0000557 }
558
559 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700560 public void onResultReceived(int requestId, CameraMetadataNative result)
561 throws RemoteException {
Zhijun Heecb323e2013-07-31 09:40:27 -0700562 if (DEBUG) {
563 Log.d(TAG, "Received result for id " + requestId);
564 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700565 final CaptureListenerHolder holder;
Igor Murashkin70725502013-06-25 20:27:06 +0000566
567 synchronized (mLock) {
568 // TODO: move this whole map into this class to make it more testable,
569 // exposing the methods necessary like subscribeToRequest, unsubscribe..
570 // TODO: make class static class
571
Zhijun Heecb323e2013-07-31 09:40:27 -0700572 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000573
574 // Clean up listener once we no longer expect to see it.
575
576 // TODO: how to handle repeating listeners?
577 // we probably want cancelRequest to return # of times it already enqueued and
578 // keep a counter.
579 if (holder != null && !holder.isRepeating()) {
Zhijun Heecb323e2013-07-31 09:40:27 -0700580 CameraDevice.this.mCaptureListenerMap.remove(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000581 }
582 }
583
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700584 // Check if we have a listener for this
Igor Murashkin70725502013-06-25 20:27:06 +0000585 if (holder == null) {
Igor Murashkin70725502013-06-25 20:27:06 +0000586 return;
587 }
588
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700589 if (isClosed()) return;
590
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700591 final CaptureRequest request = holder.getRequest();
592 final CaptureResult resultAsCapture = new CaptureResult(result, request, requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000593
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700594 holder.getHandler().post(
595 new Runnable() {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700596 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700597 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700598 if (!CameraDevice.this.isClosed()){
599 holder.getListener().onCaptureCompleted(
600 CameraDevice.this,
601 request,
602 resultAsCapture);
603 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700604 }
605 });
Igor Murashkin70725502013-06-25 20:27:06 +0000606 }
607
608 }
609
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700610 /**
611 * Default handler management. If handler is null, get the current thread's
612 * Looper to create a Handler with. If no looper exists, throw exception.
613 */
614 private Handler checkHandler(Handler handler) {
615 if (handler == null) {
616 Looper looper = Looper.myLooper();
617 if (looper == null) {
618 throw new IllegalArgumentException(
619 "No handler given, and current thread has no looper!");
620 }
621 handler = new Handler(looper);
622 }
623 return handler;
624 }
625
Zhijun He7f4d3142013-07-23 07:54:38 -0700626 private void checkIfCameraClosed() {
627 if (mRemoteDevice == null) {
628 throw new IllegalStateException("CameraDevice was already closed");
629 }
630 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700631
632 private boolean isClosed() {
633 synchronized(mLock) {
634 return (mRemoteDevice == null);
635 }
636 }
Igor Murashkin70725502013-06-25 20:27:06 +0000637}