blob: 802cb8339c1eec94718844777f4bcb9484936a1e [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
17package android.hardware.photography.impl;
18
19import android.hardware.photography.CameraMetadata;
20import android.hardware.photography.CaptureResult;
21import android.hardware.photography.ICameraDeviceUser;
22import android.hardware.photography.ICameraDeviceCallbacks;
23import android.hardware.photography.CameraAccessException;
24import android.hardware.photography.CameraProperties;
25import android.hardware.photography.CaptureRequest;
26import android.hardware.photography.utils.CameraRuntimeException;
27import android.os.Binder;
28import 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 */
40public class CameraDevice implements android.hardware.photography.CameraDevice {
41
42 private final String TAG;
43
44 // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
45 private ICameraDeviceUser mRemoteDevice;
46
47 private final Object mLock = new Object();
48 private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
49
50 // XX: Make this a WeakReference<CaptureListener> ?
Igor Murashkind7bf1772013-07-12 18:01:31 -070051 // TODO: Convert to SparseIntArray
Igor Murashkin70725502013-06-25 20:27:06 +000052 private final HashMap<Integer, CaptureListenerHolder> mCaptureListenerMap =
53 new HashMap<Integer, CaptureListenerHolder>();
54
55 private final Stack<Integer> mRepeatingRequestIdStack = new Stack<Integer>();
56
57 private final String mCameraId;
58
59 public CameraDevice(String cameraId) {
60 mCameraId = cameraId;
61 TAG = String.format("CameraDevice-%s-JV", mCameraId);
62 }
63
64 public CameraDeviceCallbacks getCallbacks() {
65 return mCallbacks;
66 }
67
68 /**
69 * @hide
70 */
71 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
72 mRemoteDevice = remoteDevice;
73 }
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 {
146 // TODO
147 throw new UnsupportedOperationException("Burst capture implemented yet");
148
149 }
150
151 private void submitCaptureRequest(CaptureRequest request, CaptureListener listener,
152 boolean repeating) throws CameraAccessException {
153
154 synchronized (mLock) {
155
156 int requestId;
157
158 try {
159 requestId = mRemoteDevice.submitRequest(request, repeating);
160 } catch (CameraRuntimeException e) {
161 throw e.asChecked();
162 } catch (RemoteException e) {
163 // impossible
164 return;
165 }
166
167 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
168 repeating));
169
170 if (repeating) {
171 mRepeatingRequestIdStack.add(requestId);
172 }
173
174 }
175 }
176
177 @Override
178 public void setRepeatingRequest(CaptureRequest request, CaptureListener listener)
179 throws CameraAccessException {
180 submitCaptureRequest(request, listener, /*streaming*/true);
181 }
182
183 @Override
184 public void setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener)
185 throws CameraAccessException {
186 // TODO
187 throw new UnsupportedOperationException("Burst capture implemented yet");
188 }
189
190 @Override
191 public void stopRepeating() throws CameraAccessException {
192
193 synchronized (mLock) {
194
195 while (!mRepeatingRequestIdStack.isEmpty()) {
196 int requestId = mRepeatingRequestIdStack.pop();
197
198 try {
199 mRemoteDevice.cancelRequest(requestId);
200 } catch (CameraRuntimeException e) {
201 throw e.asChecked();
202 } catch (RemoteException e) {
203 // impossible
204 return;
205 }
206 }
207 }
208 }
209
210 @Override
211 public void waitUntilIdle() throws CameraAccessException {
212 // TODO: implement
213 }
214
215 @Override
216 public void setErrorListener(ErrorListener listener) {
217 // TODO Auto-generated method stub
218
219 }
220
221 @Override
222 public void close() throws Exception {
223
224 // TODO: every method should throw IllegalStateException after close has been called
225
226 synchronized (mLock) {
227
228 try {
229 mRemoteDevice.disconnect();
230 } catch (CameraRuntimeException e) {
231 throw e.asChecked();
232 } catch (RemoteException e) {
233 // impossible
234 }
235
236 mRemoteDevice = null;
237
238 }
239 }
240
241 @Override
242 protected void finalize() throws Throwable {
243 try {
244 close();
245 } catch (CameraRuntimeException e) {
246 Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage());
247 }
248 finally {
249 super.finalize();
250 }
251 }
252
253 static class CaptureListenerHolder {
254
255 private final boolean mRepeating;
256 private final CaptureListener mListener;
257 private final CaptureRequest mRequest;
258
259 CaptureListenerHolder(CaptureListener listener, CaptureRequest request, boolean repeating) {
260 mRepeating = repeating;
261 mRequest = request;
262 mListener = listener;
263 }
264
265 public boolean isRepeating() {
266 return mRepeating;
267 }
268
269 public CaptureListener getListener() {
270 return mListener;
271 }
272
273 public CaptureRequest getRequest() {
274 return mRequest;
275 }
276 }
277
278 // TODO: unit tests
279 public class CameraDeviceCallbacks extends Binder implements ICameraDeviceCallbacks {
280
281 @Override
282 public IBinder asBinder() {
283 return this;
284 }
285
286 // TODO: consider rename to onMessageReceived
287 @Override
288 public void notifyCallback(int msgType, int ext1, int ext2) throws RemoteException {
289 Log.d(TAG, "Got message " + msgType + " ext1: " + ext1 + " , ext2: " + ext2);
290 // TODO implement rest
291 }
292
293 @Override
294 public void onResultReceived(int frameId, CameraMetadata result) throws RemoteException {
295 Log.d(TAG, "Received result for frameId " + frameId);
296
297 CaptureListenerHolder holder;
298
299 synchronized (mLock) {
300 // TODO: move this whole map into this class to make it more testable,
301 // exposing the methods necessary like subscribeToRequest, unsubscribe..
302 // TODO: make class static class
303
304 holder = CameraDevice.this.mCaptureListenerMap.get(frameId);
305
306 // Clean up listener once we no longer expect to see it.
307
308 // TODO: how to handle repeating listeners?
309 // we probably want cancelRequest to return # of times it already enqueued and
310 // keep a counter.
311 if (holder != null && !holder.isRepeating()) {
312 CameraDevice.this.mCaptureListenerMap.remove(frameId);
313 }
314 }
315
316 if (holder == null) {
317 Log.e(TAG, "Result had no listener holder associated with it, dropping result");
318 return;
319 }
320
321 CaptureResult resultAsCapture = new CaptureResult();
322 resultAsCapture.swap(result);
323
324 if (holder.getListener() != null) {
325 holder.getListener().onCaptureComplete(CameraDevice.this, holder.getRequest(),
326 resultAsCapture);
327 }
328 }
329
330 }
331
332}