blob: ee199bcb9682840dfe3fd3e5ad1c828d65a643b2 [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
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070019import android.hardware.camera2.CameraMetadata;
20import android.hardware.camera2.CaptureResult;
21import android.hardware.camera2.ICameraDeviceUser;
22import android.hardware.camera2.ICameraDeviceCallbacks;
23import android.hardware.camera2.CameraAccessException;
24import android.hardware.camera2.CameraProperties;
25import android.hardware.camera2.CaptureRequest;
26import android.hardware.camera2.utils.CameraRuntimeException;
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -070027import android.hardware.camera2.utils.CameraBinderDecorator;
Igor Murashkin70725502013-06-25 20:27:06 +000028import android.os.IBinder;
29import android.os.RemoteException;
30import android.util.Log;
31import android.view.Surface;
32
33import java.util.HashMap;
34import java.util.List;
35import java.util.Stack;
36
37/**
38 * HAL2.1+ implementation of CameraDevice Use CameraManager#open to instantiate
39 */
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070040public class CameraDevice implements android.hardware.camera2.CameraDevice {
Igor Murashkin70725502013-06-25 20:27:06 +000041
42 private final String TAG;
Zhijun Heecb323e2013-07-31 09:40:27 -070043 private final boolean DEBUG;
Igor Murashkin70725502013-06-25 20:27:06 +000044
45 // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
46 private ICameraDeviceUser mRemoteDevice;
47
48 private final Object mLock = new Object();
49 private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
50
51 // XX: Make this a WeakReference<CaptureListener> ?
Igor Murashkind7bf1772013-07-12 18:01:31 -070052 // TODO: Convert to SparseIntArray
Igor Murashkin70725502013-06-25 20:27:06 +000053 private final HashMap<Integer, CaptureListenerHolder> mCaptureListenerMap =
54 new HashMap<Integer, CaptureListenerHolder>();
55
56 private final Stack<Integer> mRepeatingRequestIdStack = new Stack<Integer>();
57
58 private final String mCameraId;
59
60 public CameraDevice(String cameraId) {
61 mCameraId = cameraId;
62 TAG = String.format("CameraDevice-%s-JV", mCameraId);
Zhijun Heecb323e2013-07-31 09:40:27 -070063 DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Igor Murashkin70725502013-06-25 20:27:06 +000064 }
65
66 public CameraDeviceCallbacks getCallbacks() {
67 return mCallbacks;
68 }
69
Igor Murashkin70725502013-06-25 20:27:06 +000070 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
Eino-Ville Talvala5afd3e92013-08-21 10:37:04 -070071 // TODO: Move from decorator to direct binder-mediated exceptions
72 mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
Igor Murashkin70725502013-06-25 20:27:06 +000073 }
74
75 @Override
76 public CameraProperties getProperties() throws CameraAccessException {
Igor Murashkind7bf1772013-07-12 18:01:31 -070077
78 CameraProperties properties = new CameraProperties();
79 CameraMetadata info = new CameraMetadata();
80
81 try {
82 mRemoteDevice.getCameraInfo(/*out*/info);
83 } catch(CameraRuntimeException e) {
84 throw e.asChecked();
85 } catch(RemoteException e) {
86 // impossible
87 return null;
88 }
89
90 properties.swap(info);
91 return properties;
Igor Murashkin70725502013-06-25 20:27:06 +000092 }
93
94 @Override
95 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
96 synchronized (mLock) {
97 // TODO: delete outputs that aren't in this list that were configured previously
98 for (Surface s : outputs) {
99 try {
100 // TODO: remove width,height,format since we are ignoring
101 // it.
102 mRemoteDevice.createStream(0, 0, 0, s);
103 } catch (CameraRuntimeException e) {
104 throw e.asChecked();
105 } catch (RemoteException e) {
106 // impossible
107 return;
108 }
109 }
110 }
111 }
112
113 @Override
114 public CaptureRequest createCaptureRequest(int templateType) throws CameraAccessException {
115
116 synchronized (mLock) {
117
118 CameraMetadata templatedRequest = new CameraMetadata();
119
120 try {
121 mRemoteDevice.createDefaultRequest(templateType, /* out */templatedRequest);
122 } catch (CameraRuntimeException e) {
123 throw e.asChecked();
124 } catch (RemoteException e) {
125 // impossible
126 return null;
127 }
128
129 CaptureRequest request = new CaptureRequest();
Igor Murashkin70725502013-06-25 20:27:06 +0000130 request.swap(templatedRequest);
131
132 return request;
133
134 }
135 }
136
137 @Override
138 public void capture(CaptureRequest request, CaptureListener listener)
139 throws CameraAccessException {
140 submitCaptureRequest(request, listener, /*streaming*/false);
141 }
142
143 @Override
144 public void captureBurst(List<CaptureRequest> requests, CaptureListener listener)
145 throws CameraAccessException {
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700146 if (requests.isEmpty()) {
147 Log.w(TAG, "Capture burst request list is empty, do nothing!");
148 return;
149 }
Igor Murashkin70725502013-06-25 20:27:06 +0000150 // TODO
151 throw new UnsupportedOperationException("Burst capture implemented yet");
152
153 }
154
155 private void submitCaptureRequest(CaptureRequest request, CaptureListener listener,
156 boolean repeating) throws CameraAccessException {
157
158 synchronized (mLock) {
159
160 int requestId;
161
162 try {
163 requestId = mRemoteDevice.submitRequest(request, repeating);
164 } catch (CameraRuntimeException e) {
165 throw e.asChecked();
166 } catch (RemoteException e) {
167 // impossible
168 return;
169 }
170
171 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
172 repeating));
173
174 if (repeating) {
175 mRepeatingRequestIdStack.add(requestId);
176 }
177
178 }
179 }
180
181 @Override
182 public void setRepeatingRequest(CaptureRequest request, CaptureListener listener)
183 throws CameraAccessException {
184 submitCaptureRequest(request, listener, /*streaming*/true);
185 }
186
187 @Override
188 public void setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener)
189 throws CameraAccessException {
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700190 if (requests.isEmpty()) {
191 Log.w(TAG, "Set Repeating burst request list is empty, do nothing!");
192 return;
193 }
Igor Murashkin70725502013-06-25 20:27:06 +0000194 // TODO
195 throw new UnsupportedOperationException("Burst capture implemented yet");
196 }
197
198 @Override
199 public void stopRepeating() throws CameraAccessException {
200
201 synchronized (mLock) {
202
203 while (!mRepeatingRequestIdStack.isEmpty()) {
204 int requestId = mRepeatingRequestIdStack.pop();
205
206 try {
207 mRemoteDevice.cancelRequest(requestId);
208 } catch (CameraRuntimeException e) {
209 throw e.asChecked();
210 } catch (RemoteException e) {
211 // impossible
212 return;
213 }
214 }
215 }
216 }
217
218 @Override
219 public void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -0700220
221 synchronized (mLock) {
222 checkIfCameraClosed();
223 if (!mRepeatingRequestIdStack.isEmpty()) {
224 throw new IllegalStateException("Active repeating request ongoing");
225 }
226
227 try {
228 mRemoteDevice.waitUntilIdle();
229 } catch (CameraRuntimeException e) {
230 throw e.asChecked();
231 } catch (RemoteException e) {
232 // impossible
233 return;
234 }
235 }
Igor Murashkin70725502013-06-25 20:27:06 +0000236 }
237
238 @Override
239 public void setErrorListener(ErrorListener listener) {
240 // TODO Auto-generated method stub
241
242 }
243
244 @Override
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -0700245 public void flush() throws CameraAccessException {
246 synchronized (mLock) {
247 try {
248 mRemoteDevice.flush();
249 } catch (CameraRuntimeException e) {
250 throw e.asChecked();
251 } catch (RemoteException e) {
252 // impossible
253 return;
254 }
255 }
256 }
257
258 @Override
Igor Murashkin70725502013-06-25 20:27:06 +0000259 public void close() throws Exception {
260
261 // TODO: every method should throw IllegalStateException after close has been called
262
263 synchronized (mLock) {
264
265 try {
266 mRemoteDevice.disconnect();
267 } catch (CameraRuntimeException e) {
268 throw e.asChecked();
269 } catch (RemoteException e) {
270 // impossible
271 }
272
273 mRemoteDevice = null;
274
275 }
276 }
277
278 @Override
279 protected void finalize() throws Throwable {
280 try {
281 close();
282 } catch (CameraRuntimeException e) {
283 Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage());
284 }
285 finally {
286 super.finalize();
287 }
288 }
289
290 static class CaptureListenerHolder {
291
292 private final boolean mRepeating;
293 private final CaptureListener mListener;
294 private final CaptureRequest mRequest;
295
296 CaptureListenerHolder(CaptureListener listener, CaptureRequest request, boolean repeating) {
297 mRepeating = repeating;
298 mRequest = request;
299 mListener = listener;
300 }
301
302 public boolean isRepeating() {
303 return mRepeating;
304 }
305
306 public CaptureListener getListener() {
307 return mListener;
308 }
309
310 public CaptureRequest getRequest() {
311 return mRequest;
312 }
313 }
314
315 // TODO: unit tests
Zhijun Heecb323e2013-07-31 09:40:27 -0700316 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Igor Murashkin70725502013-06-25 20:27:06 +0000317
318 @Override
319 public IBinder asBinder() {
320 return this;
321 }
322
323 // TODO: consider rename to onMessageReceived
324 @Override
325 public void notifyCallback(int msgType, int ext1, int ext2) throws RemoteException {
Zhijun Heecb323e2013-07-31 09:40:27 -0700326 if (DEBUG) {
327 Log.d(TAG, "Got message " + msgType + " ext1: " + ext1 + " , ext2: " + ext2);
328 }
Igor Murashkin70725502013-06-25 20:27:06 +0000329 // TODO implement rest
330 }
331
332 @Override
Zhijun Heecb323e2013-07-31 09:40:27 -0700333 public void onResultReceived(int requestId, CameraMetadata result) throws RemoteException {
334 if (DEBUG) {
335 Log.d(TAG, "Received result for id " + requestId);
336 }
Igor Murashkin70725502013-06-25 20:27:06 +0000337 CaptureListenerHolder holder;
338
339 synchronized (mLock) {
340 // TODO: move this whole map into this class to make it more testable,
341 // exposing the methods necessary like subscribeToRequest, unsubscribe..
342 // TODO: make class static class
343
Zhijun Heecb323e2013-07-31 09:40:27 -0700344 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000345
346 // Clean up listener once we no longer expect to see it.
347
348 // TODO: how to handle repeating listeners?
349 // we probably want cancelRequest to return # of times it already enqueued and
350 // keep a counter.
351 if (holder != null && !holder.isRepeating()) {
Zhijun Heecb323e2013-07-31 09:40:27 -0700352 CameraDevice.this.mCaptureListenerMap.remove(requestId);
Igor Murashkin70725502013-06-25 20:27:06 +0000353 }
354 }
355
356 if (holder == null) {
357 Log.e(TAG, "Result had no listener holder associated with it, dropping result");
358 return;
359 }
360
361 CaptureResult resultAsCapture = new CaptureResult();
362 resultAsCapture.swap(result);
363
364 if (holder.getListener() != null) {
365 holder.getListener().onCaptureComplete(CameraDevice.this, holder.getRequest(),
366 resultAsCapture);
367 }
368 }
369
370 }
371
Zhijun He7f4d3142013-07-23 07:54:38 -0700372 private void checkIfCameraClosed() {
373 if (mRemoteDevice == null) {
374 throw new IllegalStateException("CameraDevice was already closed");
375 }
376 }
Igor Murashkin70725502013-06-25 20:27:06 +0000377}