blob: b1e3f6ad5e65b81a113091bb1b56d31c7b53da30 [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> ?
51 private final HashMap<Integer, CaptureListenerHolder> mCaptureListenerMap =
52 new HashMap<Integer, CaptureListenerHolder>();
53
54 private final Stack<Integer> mRepeatingRequestIdStack = new Stack<Integer>();
55
56 private final String mCameraId;
57
58 public CameraDevice(String cameraId) {
59 mCameraId = cameraId;
60 TAG = String.format("CameraDevice-%s-JV", mCameraId);
61 }
62
63 public CameraDeviceCallbacks getCallbacks() {
64 return mCallbacks;
65 }
66
67 /**
68 * @hide
69 */
70 public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
71 mRemoteDevice = remoteDevice;
72 }
73
74 @Override
75 public CameraProperties getProperties() throws CameraAccessException {
76 // TODO
77 Log.v(TAG, "TODO: Implement getProperties");
78 return new CameraProperties();
79 }
80
81 @Override
82 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
83 synchronized (mLock) {
84 // TODO: delete outputs that aren't in this list that were configured previously
85 for (Surface s : outputs) {
86 try {
87 // TODO: remove width,height,format since we are ignoring
88 // it.
89 mRemoteDevice.createStream(0, 0, 0, s);
90 } catch (CameraRuntimeException e) {
91 throw e.asChecked();
92 } catch (RemoteException e) {
93 // impossible
94 return;
95 }
96 }
97 }
98 }
99
100 @Override
101 public CaptureRequest createCaptureRequest(int templateType) throws CameraAccessException {
102
103 synchronized (mLock) {
104
105 CameraMetadata templatedRequest = new CameraMetadata();
106
107 try {
108 mRemoteDevice.createDefaultRequest(templateType, /* out */templatedRequest);
109 } catch (CameraRuntimeException e) {
110 throw e.asChecked();
111 } catch (RemoteException e) {
112 // impossible
113 return null;
114 }
115
116 CaptureRequest request = new CaptureRequest();
117
118 // XX: could also change binder signature but that's more work than
119 // just using swap.
120 request.swap(templatedRequest);
121
122 return request;
123
124 }
125 }
126
127 @Override
128 public void capture(CaptureRequest request, CaptureListener listener)
129 throws CameraAccessException {
130 submitCaptureRequest(request, listener, /*streaming*/false);
131 }
132
133 @Override
134 public void captureBurst(List<CaptureRequest> requests, CaptureListener listener)
135 throws CameraAccessException {
136 // TODO
137 throw new UnsupportedOperationException("Burst capture implemented yet");
138
139 }
140
141 private void submitCaptureRequest(CaptureRequest request, CaptureListener listener,
142 boolean repeating) throws CameraAccessException {
143
144 synchronized (mLock) {
145
146 int requestId;
147
148 try {
149 requestId = mRemoteDevice.submitRequest(request, repeating);
150 } catch (CameraRuntimeException e) {
151 throw e.asChecked();
152 } catch (RemoteException e) {
153 // impossible
154 return;
155 }
156
157 mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
158 repeating));
159
160 if (repeating) {
161 mRepeatingRequestIdStack.add(requestId);
162 }
163
164 }
165 }
166
167 @Override
168 public void setRepeatingRequest(CaptureRequest request, CaptureListener listener)
169 throws CameraAccessException {
170 submitCaptureRequest(request, listener, /*streaming*/true);
171 }
172
173 @Override
174 public void setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener)
175 throws CameraAccessException {
176 // TODO
177 throw new UnsupportedOperationException("Burst capture implemented yet");
178 }
179
180 @Override
181 public void stopRepeating() throws CameraAccessException {
182
183 synchronized (mLock) {
184
185 while (!mRepeatingRequestIdStack.isEmpty()) {
186 int requestId = mRepeatingRequestIdStack.pop();
187
188 try {
189 mRemoteDevice.cancelRequest(requestId);
190 } catch (CameraRuntimeException e) {
191 throw e.asChecked();
192 } catch (RemoteException e) {
193 // impossible
194 return;
195 }
196 }
197 }
198 }
199
200 @Override
201 public void waitUntilIdle() throws CameraAccessException {
202 // TODO: implement
203 }
204
205 @Override
206 public void setErrorListener(ErrorListener listener) {
207 // TODO Auto-generated method stub
208
209 }
210
211 @Override
212 public void close() throws Exception {
213
214 // TODO: every method should throw IllegalStateException after close has been called
215
216 synchronized (mLock) {
217
218 try {
219 mRemoteDevice.disconnect();
220 } catch (CameraRuntimeException e) {
221 throw e.asChecked();
222 } catch (RemoteException e) {
223 // impossible
224 }
225
226 mRemoteDevice = null;
227
228 }
229 }
230
231 @Override
232 protected void finalize() throws Throwable {
233 try {
234 close();
235 } catch (CameraRuntimeException e) {
236 Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage());
237 }
238 finally {
239 super.finalize();
240 }
241 }
242
243 static class CaptureListenerHolder {
244
245 private final boolean mRepeating;
246 private final CaptureListener mListener;
247 private final CaptureRequest mRequest;
248
249 CaptureListenerHolder(CaptureListener listener, CaptureRequest request, boolean repeating) {
250 mRepeating = repeating;
251 mRequest = request;
252 mListener = listener;
253 }
254
255 public boolean isRepeating() {
256 return mRepeating;
257 }
258
259 public CaptureListener getListener() {
260 return mListener;
261 }
262
263 public CaptureRequest getRequest() {
264 return mRequest;
265 }
266 }
267
268 // TODO: unit tests
269 public class CameraDeviceCallbacks extends Binder implements ICameraDeviceCallbacks {
270
271 @Override
272 public IBinder asBinder() {
273 return this;
274 }
275
276 // TODO: consider rename to onMessageReceived
277 @Override
278 public void notifyCallback(int msgType, int ext1, int ext2) throws RemoteException {
279 Log.d(TAG, "Got message " + msgType + " ext1: " + ext1 + " , ext2: " + ext2);
280 // TODO implement rest
281 }
282
283 @Override
284 public void onResultReceived(int frameId, CameraMetadata result) throws RemoteException {
285 Log.d(TAG, "Received result for frameId " + frameId);
286
287 CaptureListenerHolder holder;
288
289 synchronized (mLock) {
290 // TODO: move this whole map into this class to make it more testable,
291 // exposing the methods necessary like subscribeToRequest, unsubscribe..
292 // TODO: make class static class
293
294 holder = CameraDevice.this.mCaptureListenerMap.get(frameId);
295
296 // Clean up listener once we no longer expect to see it.
297
298 // TODO: how to handle repeating listeners?
299 // we probably want cancelRequest to return # of times it already enqueued and
300 // keep a counter.
301 if (holder != null && !holder.isRepeating()) {
302 CameraDevice.this.mCaptureListenerMap.remove(frameId);
303 }
304 }
305
306 if (holder == null) {
307 Log.e(TAG, "Result had no listener holder associated with it, dropping result");
308 return;
309 }
310
311 CaptureResult resultAsCapture = new CaptureResult();
312 resultAsCapture.swap(result);
313
314 if (holder.getListener() != null) {
315 holder.getListener().onCaptureComplete(CameraDevice.this, holder.getRequest(),
316 resultAsCapture);
317 }
318 }
319
320 }
321
322}