blob: 5ec01ade317501b0c0b8069923e35bcda9f80585 [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 Talvala2f1a2e42013-07-25 17:12:05 -070022import android.hardware.camera2.CaptureRequest;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070023import android.hardware.camera2.CaptureResult;
24import android.hardware.camera2.ICameraDeviceCallbacks;
25import android.hardware.camera2.ICameraDeviceUser;
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -070026import android.hardware.camera2.utils.CameraBinderDecorator;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070027import android.hardware.camera2.utils.CameraRuntimeException;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070028import android.os.Handler;
Ruben Brunkdecfe952013-10-29 11:00:32 -070029import android.os.IBinder;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070030import android.os.Looper;
Ruben Brunkdecfe952013-10-29 11:00:32 -070031import android.os.RemoteException;
Igor Murashkin70725502013-06-25 20:27:06 +000032import android.util.Log;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070033import android.util.SparseArray;
Igor Murashkin70725502013-06-25 20:27:06 +000034import android.view.Surface;
35
Igor Murashkin57ea59b2013-08-23 16:55:57 -070036import java.util.ArrayList;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070037import java.util.HashSet;
Ruben Brunkdecfe952013-10-29 11:00:32 -070038import java.util.Iterator;
Igor Murashkin70725502013-06-25 20:27:06 +000039import java.util.List;
Igor Murashkin70725502013-06-25 20:27:06 +000040
41/**
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070042 * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
Igor Murashkin70725502013-06-25 20:27:06 +000043 */
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070044public class CameraDevice implements android.hardware.camera2.CameraDevice {
Igor Murashkin70725502013-06-25 20:27:06 +000045
46 private final String TAG;
Zhijun Heecb323e2013-07-31 09:40:27 -070047 private final boolean DEBUG;
Igor Murashkin70725502013-06-25 20:27:06 +000048
Ruben Brunkdecfe952013-10-29 11:00:32 -070049 private static final int REQUEST_ID_NONE = -1;
50
Igor Murashkin70725502013-06-25 20:27:06 +000051 // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
52 private ICameraDeviceUser mRemoteDevice;
53
54 private final Object mLock = new Object();
55 private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
56
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070057 private final StateListener mDeviceListener;
58 private final Handler mDeviceHandler;
59
60 private boolean mIdle = true;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070061
62 private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
63 new SparseArray<CaptureListenerHolder>();
Igor Murashkin70725502013-06-25 20:27:06 +000064
Ruben Brunkdecfe952013-10-29 11:00:32 -070065 private int mRepeatingRequestId = REQUEST_ID_NONE;
66 private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<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 {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700189 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700190
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
Ruben Brunke73b41b2013-11-07 19:30:43 -0800282 if (repeating) {
283 stopRepeating();
284 }
285
Igor Murashkin70725502013-06-25 20:27:06 +0000286 try {
287 requestId = mRemoteDevice.submitRequest(request, repeating);
288 } catch (CameraRuntimeException e) {
289 throw e.asChecked();
290 } catch (RemoteException e) {
291 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700292 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000293 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700294 if (listener != null) {
295 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
296 handler, repeating));
297 }
Igor Murashkin70725502013-06-25 20:27:06 +0000298
299 if (repeating) {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700300 mRepeatingRequestId = requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000301 }
302
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700303 if (mIdle) {
304 mDeviceHandler.post(mCallOnActive);
305 }
306 mIdle = false;
307
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700308 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000309 }
310 }
311
312 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700313 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700314 Handler handler) throws CameraAccessException {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700315 return submitCaptureRequest(request, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000316 }
317
318 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700319 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700320 Handler handler) throws CameraAccessException {
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700321 if (requests.isEmpty()) {
322 Log.w(TAG, "Set Repeating burst request list is empty, do nothing!");
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700323 return -1;
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700324 }
Igor Murashkin70725502013-06-25 20:27:06 +0000325 // TODO
326 throw new UnsupportedOperationException("Burst capture implemented yet");
327 }
328
329 @Override
330 public void stopRepeating() throws CameraAccessException {
331
332 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700333 checkIfCameraClosed();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700334 if (mRepeatingRequestId != REQUEST_ID_NONE) {
335
336 int requestId = mRepeatingRequestId;
337 mRepeatingRequestId = REQUEST_ID_NONE;
338
339 // Queue for deletion after in-flight requests finish
340 mRepeatingRequestIdDeletedList.add(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000341
342 try {
343 mRemoteDevice.cancelRequest(requestId);
344 } catch (CameraRuntimeException e) {
345 throw e.asChecked();
346 } catch (RemoteException e) {
347 // impossible
348 return;
349 }
350 }
351 }
352 }
353
Zhijun Hed842fcd2013-12-26 14:14:04 -0800354 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700355
356 synchronized (mLock) {
357 checkIfCameraClosed();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700358 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700359 throw new IllegalStateException("Active repeating request ongoing");
360 }
361
362 try {
363 mRemoteDevice.waitUntilIdle();
364 } catch (CameraRuntimeException e) {
365 throw e.asChecked();
366 } catch (RemoteException e) {
367 // impossible
368 return;
369 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700370
371 mRepeatingRequestId = REQUEST_ID_NONE;
372 mRepeatingRequestIdDeletedList.clear();
373 mCaptureListenerMap.clear();
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700374 }
Igor Murashkin70725502013-06-25 20:27:06 +0000375 }
376
377 @Override
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700378 public void flush() throws CameraAccessException {
379 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700380 checkIfCameraClosed();
381
382 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700383 try {
384 mRemoteDevice.flush();
385 } catch (CameraRuntimeException e) {
386 throw e.asChecked();
387 } catch (RemoteException e) {
388 // impossible
389 return;
390 }
391 }
392 }
393
394 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700395 public void close() {
Igor Murashkin70725502013-06-25 20:27:06 +0000396 synchronized (mLock) {
397
398 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700399 if (mRemoteDevice != null) {
400 mRemoteDevice.disconnect();
401 }
Igor Murashkin70725502013-06-25 20:27:06 +0000402 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700403 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000404 } catch (RemoteException e) {
405 // impossible
406 }
407
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700408 if (mRemoteDevice != null) {
409 mDeviceHandler.post(mCallOnClosed);
410 }
Igor Murashkin70725502013-06-25 20:27:06 +0000411
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700412 mRemoteDevice = null;
Igor Murashkin70725502013-06-25 20:27:06 +0000413 }
414 }
415
416 @Override
417 protected void finalize() throws Throwable {
418 try {
419 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000420 }
421 finally {
422 super.finalize();
423 }
424 }
425
426 static class CaptureListenerHolder {
427
428 private final boolean mRepeating;
429 private final CaptureListener mListener;
430 private final CaptureRequest mRequest;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700431 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000432
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700433 CaptureListenerHolder(CaptureListener listener, CaptureRequest request, Handler handler,
434 boolean repeating) {
435 if (listener == null || handler == null) {
436 throw new UnsupportedOperationException(
437 "Must have a valid handler and a valid listener");
438 }
Igor Murashkin70725502013-06-25 20:27:06 +0000439 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700440 mHandler = handler;
Igor Murashkin70725502013-06-25 20:27:06 +0000441 mRequest = request;
442 mListener = listener;
443 }
444
445 public boolean isRepeating() {
446 return mRepeating;
447 }
448
449 public CaptureListener getListener() {
450 return mListener;
451 }
452
453 public CaptureRequest getRequest() {
454 return mRequest;
455 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700456
457 public Handler getHandler() {
458 return mHandler;
459 }
460
Igor Murashkin70725502013-06-25 20:27:06 +0000461 }
462
Zhijun Heecb323e2013-07-31 09:40:27 -0700463 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +0000464
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700465 //
466 // Constants below need to be kept up-to-date with
467 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
468 //
469
470 //
471 // Error codes for onCameraError
472 //
473
474 /**
475 * Camera has been disconnected
476 */
477 static final int ERROR_CAMERA_DISCONNECTED = 0;
478
479 /**
480 * Camera has encountered a device-level error
481 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
482 */
483 static final int ERROR_CAMERA_DEVICE = 1;
484
485 /**
486 * Camera has encountered a service-level error
487 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
488 */
489 static final int ERROR_CAMERA_SERVICE = 2;
490
Igor Murashkin70725502013-06-25 20:27:06 +0000491 @Override
492 public IBinder asBinder() {
493 return this;
494 }
495
Igor Murashkin70725502013-06-25 20:27:06 +0000496 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700497 public void onCameraError(final int errorCode) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700498 Runnable r = null;
499 if (isClosed()) return;
500
501 synchronized(mLock) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700502 switch (errorCode) {
503 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700504 r = mCallOnDisconnected;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700505 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700506 default:
507 Log.e(TAG, "Unknown error from camera device: " + errorCode);
508 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700509 case ERROR_CAMERA_DEVICE:
510 case ERROR_CAMERA_SERVICE:
511 r = new Runnable() {
512 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700513 if (!CameraDevice.this.isClosed()) {
514 mDeviceListener.onError(CameraDevice.this, errorCode);
515 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700516 }
517 };
518 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700519 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700520 CameraDevice.this.mDeviceHandler.post(r);
Zhijun Heecb323e2013-07-31 09:40:27 -0700521 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700522 }
523
524 @Override
525 public void onCameraIdle() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700526 if (isClosed()) return;
527
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700528 if (DEBUG) {
529 Log.d(TAG, "Camera now idle");
530 }
531 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700532 if (!CameraDevice.this.mIdle) {
533 CameraDevice.this.mDeviceHandler.post(mCallOnIdle);
534 }
535 CameraDevice.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700536 }
537 }
538
539 @Override
540 public void onCaptureStarted(int requestId, final long timestamp) {
541 if (DEBUG) {
542 Log.d(TAG, "Capture started for id " + requestId);
543 }
544 final CaptureListenerHolder holder;
545
546 // Get the listener for this frame ID, if there is one
547 synchronized (mLock) {
548 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
549 }
550
551 if (holder == null) {
552 return;
553 }
554
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700555 if (isClosed()) return;
556
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700557 // Dispatch capture start notice
558 holder.getHandler().post(
559 new Runnable() {
560 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700561 if (!CameraDevice.this.isClosed()) {
562 holder.getListener().onCaptureStarted(
563 CameraDevice.this,
564 holder.getRequest(),
565 timestamp);
566 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700567 }
568 });
Igor Murashkin70725502013-06-25 20:27:06 +0000569 }
570
571 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700572 public void onResultReceived(int requestId, CameraMetadataNative result)
573 throws RemoteException {
Zhijun Heecb323e2013-07-31 09:40:27 -0700574 if (DEBUG) {
575 Log.d(TAG, "Received result for id " + requestId);
576 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700577 final CaptureListenerHolder holder;
Igor Murashkin70725502013-06-25 20:27:06 +0000578
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800579 Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT);
580 boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial);
581
Igor Murashkin70725502013-06-25 20:27:06 +0000582 synchronized (mLock) {
583 // TODO: move this whole map into this class to make it more testable,
584 // exposing the methods necessary like subscribeToRequest, unsubscribe..
585 // TODO: make class static class
586
Zhijun Heecb323e2013-07-31 09:40:27 -0700587 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000588
589 // Clean up listener once we no longer expect to see it.
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800590 if (holder != null && !holder.isRepeating() && !quirkIsPartialResult) {
Zhijun Heecb323e2013-07-31 09:40:27 -0700591 CameraDevice.this.mCaptureListenerMap.remove(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000592 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700593
594 // TODO: add 'capture sequence completed' callback to the
595 // service, and clean up repeating requests there instead.
596
597 // If we received a result for a repeating request and have
598 // prior repeating requests queued for deletion, remove those
599 // requests from mCaptureListenerMap.
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800600 if (holder != null && holder.isRepeating() && !quirkIsPartialResult
Ruben Brunkdecfe952013-10-29 11:00:32 -0700601 && mRepeatingRequestIdDeletedList.size() > 0) {
602 Iterator<Integer> iter = mRepeatingRequestIdDeletedList.iterator();
603 while (iter.hasNext()) {
604 int deletedRequestId = iter.next();
605 if (deletedRequestId < requestId) {
606 CameraDevice.this.mCaptureListenerMap.remove(deletedRequestId);
607 iter.remove();
608 }
609 }
610 }
611
Igor Murashkin70725502013-06-25 20:27:06 +0000612 }
613
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700614 // Check if we have a listener for this
Igor Murashkin70725502013-06-25 20:27:06 +0000615 if (holder == null) {
Igor Murashkin70725502013-06-25 20:27:06 +0000616 return;
617 }
618
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700619 if (isClosed()) return;
620
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700621 final CaptureRequest request = holder.getRequest();
622 final CaptureResult resultAsCapture = new CaptureResult(result, request, requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000623
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800624 Runnable resultDispatch = null;
625
626 // Either send a partial result or the final capture completed result
627 if (quirkIsPartialResult) {
628 // Partial result
629 resultDispatch = new Runnable() {
630 @Override
631 public void run() {
632 if (!CameraDevice.this.isClosed()){
633 holder.getListener().onCapturePartial(
634 CameraDevice.this,
635 request,
636 resultAsCapture);
637 }
638 }
639 };
640 } else {
641 // Final capture result
642 resultDispatch = new Runnable() {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700643 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700644 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700645 if (!CameraDevice.this.isClosed()){
646 holder.getListener().onCaptureCompleted(
647 CameraDevice.this,
648 request,
649 resultAsCapture);
650 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700651 }
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800652 };
653 }
654
655 holder.getHandler().post(resultDispatch);
Igor Murashkin70725502013-06-25 20:27:06 +0000656 }
657
658 }
659
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700660 /**
661 * Default handler management. If handler is null, get the current thread's
662 * Looper to create a Handler with. If no looper exists, throw exception.
663 */
664 private Handler checkHandler(Handler handler) {
665 if (handler == null) {
666 Looper looper = Looper.myLooper();
667 if (looper == null) {
668 throw new IllegalArgumentException(
669 "No handler given, and current thread has no looper!");
670 }
671 handler = new Handler(looper);
672 }
673 return handler;
674 }
675
Zhijun He7f4d3142013-07-23 07:54:38 -0700676 private void checkIfCameraClosed() {
677 if (mRemoteDevice == null) {
678 throw new IllegalStateException("CameraDevice was already closed");
679 }
680 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700681
682 private boolean isClosed() {
683 synchronized(mLock) {
684 return (mRemoteDevice == null);
685 }
686 }
Igor Murashkin70725502013-06-25 20:27:06 +0000687}