blob: 2c8a5c29c137751d11fd9a104ae666aa7c463f57 [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() {
Zhijun He2db56022014-01-02 15:12:00 -0800109 mDeviceListener.onClosed(CameraDevice.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700110 }
111 };
112
113 private final Runnable mCallOnIdle = new Runnable() {
114 public void run() {
115 if (!CameraDevice.this.isClosed()) {
116 mDeviceListener.onIdle(CameraDevice.this);
117 }
118 }
119 };
120
121 private final Runnable mCallOnDisconnected = new Runnable() {
122 public void run() {
123 if (!CameraDevice.this.isClosed()) {
124 mDeviceListener.onDisconnected(CameraDevice.this);
125 }
126 }
127 };
128
129 public CameraDevice(String cameraId, StateListener listener, Handler handler) {
130 if (cameraId == null || listener == null || handler == null) {
131 throw new IllegalArgumentException("Null argument given");
132 }
Igor Murashkin70725502013-06-25 20:27:06 +0000133 mCameraId = cameraId;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700134 mDeviceListener = listener;
135 mDeviceHandler = handler;
Igor Murashkin70725502013-06-25 20:27:06 +0000136 TAG = String.format("CameraDevice-%s-JV", mCameraId);
Zhijun Heecb323e2013-07-31 09:40:27 -0700137 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Igor Murashkin70725502013-06-25 20:27:06 +0000138 }
139
140 public CameraDeviceCallbacks getCallbacks() {
141 return mCallbacks;
142 }
143
Igor Murashkin70725502013-06-25 20:27:06 +0000144 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -0700145 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700146 synchronized(mLock) {
147 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
148
149 mDeviceHandler.post(mCallOnOpened);
150 mDeviceHandler.post(mCallOnUnconfigured);
151 }
Igor Murashkin70725502013-06-25 20:27:06 +0000152 }
153
154 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700155 public String getId() {
156 return mCameraId;
157 }
158
159 @Override
Igor Murashkin70725502013-06-25 20:27:06 +0000160 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700161 // Treat a null input the same an empty list
162 if (outputs == null) {
163 outputs = new ArrayList<Surface>();
164 }
Igor Murashkin70725502013-06-25 20:27:06 +0000165 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700166 checkIfCameraClosed();
167
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700168 HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
169 List<Integer> deleteList = new ArrayList<Integer>(); // Streams to delete
170
171 // Determine which streams need to be created, which to be deleted
172 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
173 int streamId = mConfiguredOutputs.keyAt(i);
174 Surface s = mConfiguredOutputs.valueAt(i);
175
176 if (!outputs.contains(s)) {
177 deleteList.add(streamId);
178 } else {
179 addSet.remove(s); // Don't create a stream previously created
180 }
181 }
182
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700183 mDeviceHandler.post(mCallOnBusy);
184 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700185
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700186 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700187 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700188
189 // TODO: mRemoteDevice.beginConfigure
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700190 // Delete all streams first (to free up HW resources)
191 for (Integer streamId : deleteList) {
192 mRemoteDevice.deleteStream(streamId);
193 mConfiguredOutputs.delete(streamId);
194 }
195
196 // Add all new streams
197 for (Surface s : addSet) {
Igor Murashkin70725502013-06-25 20:27:06 +0000198 // TODO: remove width,height,format since we are ignoring
199 // it.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700200 int streamId = mRemoteDevice.createStream(0, 0, 0, s);
201 mConfiguredOutputs.put(streamId, s);
Igor Murashkin70725502013-06-25 20:27:06 +0000202 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700203
204 // TODO: mRemoteDevice.endConfigure
205 } catch (CameraRuntimeException e) {
206 if (e.getReason() == CAMERA_IN_USE) {
207 throw new IllegalStateException("The camera is currently busy." +
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700208 " You must wait until the previous operation completes.");
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700209 }
210
211 throw e.asChecked();
212 } catch (RemoteException e) {
213 // impossible
214 return;
Igor Murashkin70725502013-06-25 20:27:06 +0000215 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700216
217 if (outputs.size() > 0) {
218 mDeviceHandler.post(mCallOnIdle);
219 } else {
220 mDeviceHandler.post(mCallOnUnconfigured);
221 }
Igor Murashkin70725502013-06-25 20:27:06 +0000222 }
223 }
224
225 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700226 public CaptureRequest.Builder createCaptureRequest(int templateType)
227 throws CameraAccessException {
Igor Murashkin70725502013-06-25 20:27:06 +0000228 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700229 checkIfCameraClosed();
Igor Murashkin70725502013-06-25 20:27:06 +0000230
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700231 CameraMetadataNative templatedRequest = new CameraMetadataNative();
Igor Murashkin70725502013-06-25 20:27:06 +0000232
233 try {
234 mRemoteDevice.createDefaultRequest(templateType, /* out */templatedRequest);
235 } catch (CameraRuntimeException e) {
236 throw e.asChecked();
237 } catch (RemoteException e) {
238 // impossible
239 return null;
240 }
241
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700242 CaptureRequest.Builder builder =
243 new CaptureRequest.Builder(templatedRequest);
Igor Murashkin70725502013-06-25 20:27:06 +0000244
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700245 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000246 }
247 }
248
249 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700250 public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
Igor Murashkin70725502013-06-25 20:27:06 +0000251 throws CameraAccessException {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700252 return submitCaptureRequest(request, listener, handler, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000253 }
254
255 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700256 public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700257 Handler handler) throws CameraAccessException {
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700258 if (requests.isEmpty()) {
259 Log.w(TAG, "Capture burst request list is empty, do nothing!");
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700260 return -1;
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700261 }
Igor Murashkin70725502013-06-25 20:27:06 +0000262 // TODO
263 throw new UnsupportedOperationException("Burst capture implemented yet");
264
265 }
266
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700267 private int submitCaptureRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700268 Handler handler, boolean repeating) throws CameraAccessException {
269
270 // Need a valid handler, or current thread needs to have a looper, if
271 // listener is valid
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700272 if (listener != null) {
273 handler = checkHandler(handler);
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700274 }
Igor Murashkin70725502013-06-25 20:27:06 +0000275
276 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700277 checkIfCameraClosed();
Igor Murashkin70725502013-06-25 20:27:06 +0000278 int requestId;
279
Ruben Brunke73b41b2013-11-07 19:30:43 -0800280 if (repeating) {
281 stopRepeating();
282 }
283
Igor Murashkin70725502013-06-25 20:27:06 +0000284 try {
285 requestId = mRemoteDevice.submitRequest(request, repeating);
286 } catch (CameraRuntimeException e) {
287 throw e.asChecked();
288 } catch (RemoteException e) {
289 // impossible
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700290 return -1;
Igor Murashkin70725502013-06-25 20:27:06 +0000291 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700292 if (listener != null) {
293 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
294 handler, repeating));
295 }
Igor Murashkin70725502013-06-25 20:27:06 +0000296
297 if (repeating) {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700298 mRepeatingRequestId = requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000299 }
300
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700301 if (mIdle) {
302 mDeviceHandler.post(mCallOnActive);
303 }
304 mIdle = false;
305
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700306 return requestId;
Igor Murashkin70725502013-06-25 20:27:06 +0000307 }
308 }
309
310 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700311 public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700312 Handler handler) throws CameraAccessException {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700313 return submitCaptureRequest(request, listener, handler, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +0000314 }
315
316 @Override
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700317 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700318 Handler handler) throws CameraAccessException {
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700319 if (requests.isEmpty()) {
320 Log.w(TAG, "Set Repeating burst request list is empty, do nothing!");
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700321 return -1;
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700322 }
Igor Murashkin70725502013-06-25 20:27:06 +0000323 // TODO
324 throw new UnsupportedOperationException("Burst capture implemented yet");
325 }
326
327 @Override
328 public void stopRepeating() throws CameraAccessException {
329
330 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700331 checkIfCameraClosed();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700332 if (mRepeatingRequestId != REQUEST_ID_NONE) {
333
334 int requestId = mRepeatingRequestId;
335 mRepeatingRequestId = REQUEST_ID_NONE;
336
337 // Queue for deletion after in-flight requests finish
338 mRepeatingRequestIdDeletedList.add(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000339
340 try {
341 mRemoteDevice.cancelRequest(requestId);
342 } catch (CameraRuntimeException e) {
343 throw e.asChecked();
344 } catch (RemoteException e) {
345 // impossible
346 return;
347 }
348 }
349 }
350 }
351
Zhijun Hed842fcd2013-12-26 14:14:04 -0800352 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700353
354 synchronized (mLock) {
355 checkIfCameraClosed();
Ruben Brunkdecfe952013-10-29 11:00:32 -0700356 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -0700357 throw new IllegalStateException("Active repeating request ongoing");
358 }
359
360 try {
361 mRemoteDevice.waitUntilIdle();
362 } catch (CameraRuntimeException e) {
363 throw e.asChecked();
364 } catch (RemoteException e) {
365 // impossible
366 return;
367 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700368
369 mRepeatingRequestId = REQUEST_ID_NONE;
370 mRepeatingRequestIdDeletedList.clear();
371 mCaptureListenerMap.clear();
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700372 }
Igor Murashkin70725502013-06-25 20:27:06 +0000373 }
374
375 @Override
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700376 public void flush() throws CameraAccessException {
377 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700378 checkIfCameraClosed();
379
380 mDeviceHandler.post(mCallOnBusy);
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700381 try {
382 mRemoteDevice.flush();
383 } catch (CameraRuntimeException e) {
384 throw e.asChecked();
385 } catch (RemoteException e) {
386 // impossible
387 return;
388 }
389 }
390 }
391
392 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700393 public void close() {
Igor Murashkin70725502013-06-25 20:27:06 +0000394 synchronized (mLock) {
395
396 try {
Igor Murashkin2a3eced2013-08-28 17:35:10 -0700397 if (mRemoteDevice != null) {
398 mRemoteDevice.disconnect();
399 }
Igor Murashkin70725502013-06-25 20:27:06 +0000400 } catch (CameraRuntimeException e) {
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700401 Log.e(TAG, "Exception while closing: ", e.asChecked());
Igor Murashkin70725502013-06-25 20:27:06 +0000402 } catch (RemoteException e) {
403 // impossible
404 }
405
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700406 if (mRemoteDevice != null) {
407 mDeviceHandler.post(mCallOnClosed);
408 }
Igor Murashkin70725502013-06-25 20:27:06 +0000409
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700410 mRemoteDevice = null;
Igor Murashkin70725502013-06-25 20:27:06 +0000411 }
412 }
413
414 @Override
415 protected void finalize() throws Throwable {
416 try {
417 close();
Igor Murashkin70725502013-06-25 20:27:06 +0000418 }
419 finally {
420 super.finalize();
421 }
422 }
423
424 static class CaptureListenerHolder {
425
426 private final boolean mRepeating;
427 private final CaptureListener mListener;
428 private final CaptureRequest mRequest;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700429 private final Handler mHandler;
Igor Murashkin70725502013-06-25 20:27:06 +0000430
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700431 CaptureListenerHolder(CaptureListener listener, CaptureRequest request, Handler handler,
432 boolean repeating) {
433 if (listener == null || handler == null) {
434 throw new UnsupportedOperationException(
435 "Must have a valid handler and a valid listener");
436 }
Igor Murashkin70725502013-06-25 20:27:06 +0000437 mRepeating = repeating;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700438 mHandler = handler;
Igor Murashkin70725502013-06-25 20:27:06 +0000439 mRequest = request;
440 mListener = listener;
441 }
442
443 public boolean isRepeating() {
444 return mRepeating;
445 }
446
447 public CaptureListener getListener() {
448 return mListener;
449 }
450
451 public CaptureRequest getRequest() {
452 return mRequest;
453 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700454
455 public Handler getHandler() {
456 return mHandler;
457 }
458
Igor Murashkin70725502013-06-25 20:27:06 +0000459 }
460
Zhijun Heecb323e2013-07-31 09:40:27 -0700461 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +0000462
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700463 //
464 // Constants below need to be kept up-to-date with
465 // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
466 //
467
468 //
469 // Error codes for onCameraError
470 //
471
472 /**
473 * Camera has been disconnected
474 */
475 static final int ERROR_CAMERA_DISCONNECTED = 0;
476
477 /**
478 * Camera has encountered a device-level error
479 * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE
480 */
481 static final int ERROR_CAMERA_DEVICE = 1;
482
483 /**
484 * Camera has encountered a service-level error
485 * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE
486 */
487 static final int ERROR_CAMERA_SERVICE = 2;
488
Igor Murashkin70725502013-06-25 20:27:06 +0000489 @Override
490 public IBinder asBinder() {
491 return this;
492 }
493
Igor Murashkin70725502013-06-25 20:27:06 +0000494 @Override
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700495 public void onCameraError(final int errorCode) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700496 Runnable r = null;
497 if (isClosed()) return;
498
499 synchronized(mLock) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700500 switch (errorCode) {
501 case ERROR_CAMERA_DISCONNECTED:
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700502 r = mCallOnDisconnected;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700503 break;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700504 default:
505 Log.e(TAG, "Unknown error from camera device: " + errorCode);
506 // no break
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700507 case ERROR_CAMERA_DEVICE:
508 case ERROR_CAMERA_SERVICE:
509 r = new Runnable() {
510 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700511 if (!CameraDevice.this.isClosed()) {
512 mDeviceListener.onError(CameraDevice.this, errorCode);
513 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700514 }
515 };
516 break;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700517 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700518 CameraDevice.this.mDeviceHandler.post(r);
Zhijun Heecb323e2013-07-31 09:40:27 -0700519 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700520 }
521
522 @Override
523 public void onCameraIdle() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700524 if (isClosed()) return;
525
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700526 if (DEBUG) {
527 Log.d(TAG, "Camera now idle");
528 }
529 synchronized (mLock) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700530 if (!CameraDevice.this.mIdle) {
531 CameraDevice.this.mDeviceHandler.post(mCallOnIdle);
532 }
533 CameraDevice.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700534 }
535 }
536
537 @Override
538 public void onCaptureStarted(int requestId, final long timestamp) {
539 if (DEBUG) {
540 Log.d(TAG, "Capture started for id " + requestId);
541 }
542 final CaptureListenerHolder holder;
543
544 // Get the listener for this frame ID, if there is one
545 synchronized (mLock) {
546 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
547 }
548
549 if (holder == null) {
550 return;
551 }
552
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700553 if (isClosed()) return;
554
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700555 // Dispatch capture start notice
556 holder.getHandler().post(
557 new Runnable() {
558 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700559 if (!CameraDevice.this.isClosed()) {
560 holder.getListener().onCaptureStarted(
561 CameraDevice.this,
562 holder.getRequest(),
563 timestamp);
564 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700565 }
566 });
Igor Murashkin70725502013-06-25 20:27:06 +0000567 }
568
569 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700570 public void onResultReceived(int requestId, CameraMetadataNative result)
571 throws RemoteException {
Zhijun Heecb323e2013-07-31 09:40:27 -0700572 if (DEBUG) {
573 Log.d(TAG, "Received result for id " + requestId);
574 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700575 final CaptureListenerHolder holder;
Igor Murashkin70725502013-06-25 20:27:06 +0000576
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800577 Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT);
578 boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial);
579
Igor Murashkin70725502013-06-25 20:27:06 +0000580 synchronized (mLock) {
581 // TODO: move this whole map into this class to make it more testable,
582 // exposing the methods necessary like subscribeToRequest, unsubscribe..
583 // TODO: make class static class
584
Zhijun Heecb323e2013-07-31 09:40:27 -0700585 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000586
587 // Clean up listener once we no longer expect to see it.
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800588 if (holder != null && !holder.isRepeating() && !quirkIsPartialResult) {
Zhijun Heecb323e2013-07-31 09:40:27 -0700589 CameraDevice.this.mCaptureListenerMap.remove(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000590 }
Ruben Brunkdecfe952013-10-29 11:00:32 -0700591
592 // TODO: add 'capture sequence completed' callback to the
593 // service, and clean up repeating requests there instead.
594
595 // If we received a result for a repeating request and have
596 // prior repeating requests queued for deletion, remove those
597 // requests from mCaptureListenerMap.
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800598 if (holder != null && holder.isRepeating() && !quirkIsPartialResult
Ruben Brunkdecfe952013-10-29 11:00:32 -0700599 && mRepeatingRequestIdDeletedList.size() > 0) {
600 Iterator<Integer> iter = mRepeatingRequestIdDeletedList.iterator();
601 while (iter.hasNext()) {
602 int deletedRequestId = iter.next();
603 if (deletedRequestId < requestId) {
604 CameraDevice.this.mCaptureListenerMap.remove(deletedRequestId);
605 iter.remove();
606 }
607 }
608 }
609
Igor Murashkin70725502013-06-25 20:27:06 +0000610 }
611
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700612 // Check if we have a listener for this
Igor Murashkin70725502013-06-25 20:27:06 +0000613 if (holder == null) {
Igor Murashkin70725502013-06-25 20:27:06 +0000614 return;
615 }
616
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700617 if (isClosed()) return;
618
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700619 final CaptureRequest request = holder.getRequest();
620 final CaptureResult resultAsCapture = new CaptureResult(result, request, requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000621
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800622 Runnable resultDispatch = null;
623
624 // Either send a partial result or the final capture completed result
625 if (quirkIsPartialResult) {
626 // Partial result
627 resultDispatch = new Runnable() {
628 @Override
629 public void run() {
630 if (!CameraDevice.this.isClosed()){
631 holder.getListener().onCapturePartial(
632 CameraDevice.this,
633 request,
634 resultAsCapture);
635 }
636 }
637 };
638 } else {
639 // Final capture result
640 resultDispatch = new Runnable() {
Igor Murashkin6bbf9dc2013-09-05 12:22:00 -0700641 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700642 public void run() {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700643 if (!CameraDevice.this.isClosed()){
644 holder.getListener().onCaptureCompleted(
645 CameraDevice.this,
646 request,
647 resultAsCapture);
648 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700649 }
Eino-Ville Talvala7a313102013-11-07 14:45:06 -0800650 };
651 }
652
653 holder.getHandler().post(resultDispatch);
Igor Murashkin70725502013-06-25 20:27:06 +0000654 }
655
656 }
657
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -0700658 /**
659 * Default handler management. If handler is null, get the current thread's
660 * Looper to create a Handler with. If no looper exists, throw exception.
661 */
662 private Handler checkHandler(Handler handler) {
663 if (handler == null) {
664 Looper looper = Looper.myLooper();
665 if (looper == null) {
666 throw new IllegalArgumentException(
667 "No handler given, and current thread has no looper!");
668 }
669 handler = new Handler(looper);
670 }
671 return handler;
672 }
673
Zhijun He7f4d3142013-07-23 07:54:38 -0700674 private void checkIfCameraClosed() {
675 if (mRemoteDevice == null) {
676 throw new IllegalStateException("CameraDevice was already closed");
677 }
678 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700679
680 private boolean isClosed() {
681 synchronized(mLock) {
682 return (mRemoteDevice == null);
683 }
684 }
Igor Murashkin70725502013-06-25 20:27:06 +0000685}