blob: 70f34637970d9035ed7a1e8af88a2946e080e90c [file] [log] [blame]
Ruben Brunkfeb50af2014-05-09 19:58:49 -07001/*
2 * Copyright (C) 2014 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.camera2.legacy;
18
19import android.hardware.Camera;
Igor Murashkina296fec2014-06-23 14:44:09 -070020import android.hardware.Camera.CameraInfo;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070021import android.hardware.camera2.CameraAccessException;
Igor Murashkina296fec2014-06-23 14:44:09 -070022import android.hardware.camera2.CameraCharacteristics;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070023import android.hardware.camera2.CaptureRequest;
24import android.hardware.camera2.ICameraDeviceCallbacks;
25import android.hardware.camera2.ICameraDeviceUser;
26import android.hardware.camera2.utils.LongParcelable;
27import android.hardware.camera2.impl.CameraMetadataNative;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070028import android.hardware.camera2.impl.CaptureResultExtras;
Yin-Chia Yeh981e0562015-03-12 13:39:26 -070029import android.hardware.camera2.params.OutputConfiguration;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070030import android.hardware.camera2.utils.CameraBinderDecorator;
31import android.hardware.camera2.utils.CameraRuntimeException;
Igor Murashkina296fec2014-06-23 14:44:09 -070032import android.os.ConditionVariable;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070033import android.os.IBinder;
Igor Murashkina296fec2014-06-23 14:44:09 -070034import android.os.Looper;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070035import android.os.Handler;
36import android.os.HandlerThread;
37import android.os.Message;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070038import android.os.RemoteException;
39import android.util.Log;
40import android.util.SparseArray;
41import android.view.Surface;
42
43import java.util.ArrayList;
44import java.util.List;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070045
46/**
47 * Compatibility implementation of the Camera2 API binder interface.
48 *
49 * <p>
50 * This is intended to be called from the same process as client
51 * {@link android.hardware.camera2.CameraDevice}, and wraps a
52 * {@link android.hardware.camera2.legacy.LegacyCameraDevice} that emulates Camera2 service using
53 * the Camera1 API.
54 * </p>
55 *
56 * <p>
57 * Keep up to date with ICameraDeviceUser.aidl.
58 * </p>
59 */
Igor Murashkin66533622014-08-19 14:51:47 -070060@SuppressWarnings("deprecation")
Ruben Brunkfeb50af2014-05-09 19:58:49 -070061public class CameraDeviceUserShim implements ICameraDeviceUser {
62 private static final String TAG = "CameraDeviceUserShim";
63
64 private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG);
Igor Murashkina296fec2014-06-23 14:44:09 -070065 private static final int OPEN_CAMERA_TIMEOUT_MS = 5000; // 5 sec (same as api1 cts timeout)
Ruben Brunkfeb50af2014-05-09 19:58:49 -070066
67 private final LegacyCameraDevice mLegacyDevice;
68
69 private final Object mConfigureLock = new Object();
70 private int mSurfaceIdCounter;
71 private boolean mConfiguring;
72 private final SparseArray<Surface> mSurfaces;
Igor Murashkina296fec2014-06-23 14:44:09 -070073 private final CameraCharacteristics mCameraCharacteristics;
74 private final CameraLooper mCameraInit;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070075 private final CameraCallbackThread mCameraCallbacks;
76
Ruben Brunkfeb50af2014-05-09 19:58:49 -070077
Igor Murashkina296fec2014-06-23 14:44:09 -070078 protected CameraDeviceUserShim(int cameraId, LegacyCameraDevice legacyCamera,
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070079 CameraCharacteristics characteristics, CameraLooper cameraInit,
80 CameraCallbackThread cameraCallbacks) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -070081 mLegacyDevice = legacyCamera;
82 mConfiguring = false;
83 mSurfaces = new SparseArray<Surface>();
Igor Murashkina296fec2014-06-23 14:44:09 -070084 mCameraCharacteristics = characteristics;
85 mCameraInit = cameraInit;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070086 mCameraCallbacks = cameraCallbacks;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070087
88 mSurfaceIdCounter = 0;
89 }
90
Ruben Brunk3084c2f2014-09-23 10:32:18 -070091 private static int translateErrorsFromCamera1(int errorCode) {
92 switch (errorCode) {
93 case CameraBinderDecorator.EACCES:
94 return CameraBinderDecorator.PERMISSION_DENIED;
95 default:
96 return errorCode;
97 }
98 }
99
Igor Murashkina296fec2014-06-23 14:44:09 -0700100 /**
101 * Create a separate looper/thread for the camera to run on; open the camera.
102 *
103 * <p>Since the camera automatically latches on to the current thread's looper,
104 * it's important that we have our own thread with our own looper to guarantee
105 * that the camera callbacks get correctly posted to our own thread.</p>
106 */
107 private static class CameraLooper implements Runnable, AutoCloseable {
108 private final int mCameraId;
109 private Looper mLooper;
110 private volatile int mInitErrors;
111 private final Camera mCamera = Camera.openUninitialized();
112 private final ConditionVariable mStartDone = new ConditionVariable();
113 private final Thread mThread;
114
115 /**
116 * Spin up a new thread, immediately open the camera in the background.
117 *
118 * <p>Use {@link #waitForOpen} to block until the camera is finished opening.</p>
119 *
120 * @param cameraId numeric camera Id
121 *
122 * @see #waitForOpen
123 */
124 public CameraLooper(int cameraId) {
125 mCameraId = cameraId;
126
127 mThread = new Thread(this);
128 mThread.start();
129 }
130
131 public Camera getCamera() {
132 return mCamera;
133 }
134
135 @Override
136 public void run() {
137 // Set up a looper to be used by camera.
138 Looper.prepare();
139
140 // Save the looper so that we can terminate this thread
141 // after we are done with it.
142 mLooper = Looper.myLooper();
Ruben Brunk3084c2f2014-09-23 10:32:18 -0700143 mInitErrors = translateErrorsFromCamera1(mCamera.cameraInitUnspecified(mCameraId));
Igor Murashkina296fec2014-06-23 14:44:09 -0700144 mStartDone.open();
145 Looper.loop(); // Blocks forever until #close is called.
146 }
147
148 /**
149 * Quit the looper safely; then join until the thread shuts down.
150 */
151 @Override
152 public void close() {
153 if (mLooper == null) {
154 return;
155 }
156
157 mLooper.quitSafely();
158 try {
159 mThread.join();
160 } catch (InterruptedException e) {
161 throw new AssertionError(e);
162 }
163
164 mLooper = null;
165 }
166
167 /**
168 * Block until the camera opens; then return its initialization error code (if any).
169 *
170 * @param timeoutMs timeout in milliseconds
171 *
172 * @return int error code
173 *
174 * @throws CameraRuntimeException if the camera open times out with ({@code CAMERA_ERROR})
175 */
176 public int waitForOpen(int timeoutMs) {
177 // Block until the camera is open asynchronously
178 if (!mStartDone.block(timeoutMs)) {
179 Log.e(TAG, "waitForOpen - Camera failed to open after timeout of "
180 + OPEN_CAMERA_TIMEOUT_MS + " ms");
181 try {
182 mCamera.release();
183 } catch (RuntimeException e) {
184 Log.e(TAG, "connectBinderShim - Failed to release camera after timeout ", e);
185 }
186
187 throw new CameraRuntimeException(CameraAccessException.CAMERA_ERROR);
188 }
189
190 return mInitErrors;
191 }
192 }
193
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700194 /**
195 * A thread to process callbacks to send back to the camera client.
196 *
197 * <p>This effectively emulates one-way binder semantics when in the same process as the
198 * callee.</p>
199 */
200 private static class CameraCallbackThread implements ICameraDeviceCallbacks {
201 private static final int CAMERA_ERROR = 0;
202 private static final int CAMERA_IDLE = 1;
203 private static final int CAPTURE_STARTED = 2;
204 private static final int RESULT_RECEIVED = 3;
205
206 private final HandlerThread mHandlerThread;
207 private Handler mHandler;
208
209 private final ICameraDeviceCallbacks mCallbacks;
210
211 public CameraCallbackThread(ICameraDeviceCallbacks callbacks) {
212 mCallbacks = callbacks;
213
214 mHandlerThread = new HandlerThread("LegacyCameraCallback");
215 mHandlerThread.start();
216 }
217
218 public void close() {
219 mHandlerThread.quitSafely();
220 }
221
222 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700223 public void onDeviceError(final int errorCode, final CaptureResultExtras resultExtras) {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700224 Message msg = getHandler().obtainMessage(CAMERA_ERROR,
225 /*arg1*/ errorCode, /*arg2*/ 0,
226 /*obj*/ resultExtras);
227 getHandler().sendMessage(msg);
228 }
229
230 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700231 public void onDeviceIdle() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700232 Message msg = getHandler().obtainMessage(CAMERA_IDLE);
233 getHandler().sendMessage(msg);
234 }
235
236 @Override
237 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
238 Message msg = getHandler().obtainMessage(CAPTURE_STARTED,
239 /*arg1*/ (int) (timestamp & 0xFFFFFFFFL),
240 /*arg2*/ (int) ( (timestamp >> 32) & 0xFFFFFFFFL),
241 /*obj*/ resultExtras);
242 getHandler().sendMessage(msg);
243 }
244
245 @Override
246 public void onResultReceived(final CameraMetadataNative result,
247 final CaptureResultExtras resultExtras) {
248 Object[] resultArray = new Object[] { result, resultExtras };
249 Message msg = getHandler().obtainMessage(RESULT_RECEIVED,
250 /*obj*/ resultArray);
251 getHandler().sendMessage(msg);
252 }
253
254 @Override
255 public IBinder asBinder() {
256 // This is solely intended to be used for in-process binding.
257 return null;
258 }
259
260 private Handler getHandler() {
261 if (mHandler == null) {
262 mHandler = new CallbackHandler(mHandlerThread.getLooper());
263 }
264 return mHandler;
265 }
266
267 private class CallbackHandler extends Handler {
268 public CallbackHandler(Looper l) {
269 super(l);
270 }
271
Igor Murashkin66533622014-08-19 14:51:47 -0700272 @Override
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700273 public void handleMessage(Message msg) {
274 try {
275 switch (msg.what) {
276 case CAMERA_ERROR: {
277 int errorCode = msg.arg1;
278 CaptureResultExtras resultExtras = (CaptureResultExtras) msg.obj;
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700279 mCallbacks.onDeviceError(errorCode, resultExtras);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700280 break;
281 }
282 case CAMERA_IDLE:
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700283 mCallbacks.onDeviceIdle();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700284 break;
285 case CAPTURE_STARTED: {
286 long timestamp = msg.arg2 & 0xFFFFFFFFL;
287 timestamp = (timestamp << 32) | (msg.arg1 & 0xFFFFFFFFL);
288 CaptureResultExtras resultExtras = (CaptureResultExtras) msg.obj;
289 mCallbacks.onCaptureStarted(resultExtras, timestamp);
290 break;
291 }
292 case RESULT_RECEIVED: {
293 Object[] resultArray = (Object[]) msg.obj;
294 CameraMetadataNative result = (CameraMetadataNative) resultArray[0];
295 CaptureResultExtras resultExtras = (CaptureResultExtras) resultArray[1];
296 mCallbacks.onResultReceived(result, resultExtras);
297 break;
298 }
299 default:
300 throw new IllegalArgumentException(
301 "Unknown callback message " + msg.what);
302 }
303 } catch (RemoteException e) {
304 throw new IllegalStateException(
305 "Received remote exception during camera callback " + msg.what, e);
306 }
307 }
308 }
309 }
310
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700311 public static CameraDeviceUserShim connectBinderShim(ICameraDeviceCallbacks callbacks,
312 int cameraId) {
313 if (DEBUG) {
314 Log.d(TAG, "Opening shim Camera device");
315 }
Igor Murashkina296fec2014-06-23 14:44:09 -0700316
317 /*
318 * Put the camera open on a separate thread with its own looper; otherwise
319 * if the main thread is used then the callbacks might never get delivered
320 * (e.g. in CTS which run its own default looper only after tests)
321 */
322
323 CameraLooper init = new CameraLooper(cameraId);
324
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700325 CameraCallbackThread threadCallbacks = new CameraCallbackThread(callbacks);
326
Igor Murashkina296fec2014-06-23 14:44:09 -0700327 // TODO: Make this async instead of blocking
328 int initErrors = init.waitForOpen(OPEN_CAMERA_TIMEOUT_MS);
329 Camera legacyCamera = init.getCamera();
Igor Murashkina1d66272014-06-20 11:22:11 -0700330
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700331 // Check errors old HAL initialization
Igor Murashkina1d66272014-06-20 11:22:11 -0700332 CameraBinderDecorator.throwOnError(initErrors);
333
Igor Murashkin66533622014-08-19 14:51:47 -0700334 // Disable shutter sounds (this will work unconditionally) for api2 clients
335 legacyCamera.disableShutterSound();
336
Igor Murashkina296fec2014-06-23 14:44:09 -0700337 CameraInfo info = new CameraInfo();
338 Camera.getCameraInfo(cameraId, info);
339
Eino-Ville Talvalaeecc9042014-09-23 16:37:31 -0700340 Camera.Parameters legacyParameters = null;
341 try {
342 legacyParameters = legacyCamera.getParameters();
343 } catch (RuntimeException e) {
344 throw new CameraRuntimeException(CameraAccessException.CAMERA_ERROR,
345 "Unable to get initial parameters", e);
346 }
347
Igor Murashkina296fec2014-06-23 14:44:09 -0700348 CameraCharacteristics characteristics =
Eino-Ville Talvalaeecc9042014-09-23 16:37:31 -0700349 LegacyMetadataMapper.createCharacteristics(legacyParameters, info);
Igor Murashkindf6242e2014-07-01 18:06:13 -0700350 LegacyCameraDevice device = new LegacyCameraDevice(
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700351 cameraId, legacyCamera, characteristics, threadCallbacks);
352 return new CameraDeviceUserShim(cameraId, device, characteristics, init, threadCallbacks);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700353 }
354
355 @Override
356 public void disconnect() {
357 if (DEBUG) {
358 Log.d(TAG, "disconnect called.");
359 }
Igor Murashkina296fec2014-06-23 14:44:09 -0700360
Ruben Brunke663cb772014-09-16 13:18:31 -0700361 if (mLegacyDevice.isClosed()) {
362 Log.w(TAG, "Cannot disconnect, device has already been closed.");
363 }
364
Igor Murashkina296fec2014-06-23 14:44:09 -0700365 try {
366 mLegacyDevice.close();
367 } finally {
368 mCameraInit.close();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700369 mCameraCallbacks.close();
Igor Murashkina296fec2014-06-23 14:44:09 -0700370 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700371 }
372
373 @Override
374 public int submitRequest(CaptureRequest request, boolean streaming,
375 /*out*/LongParcelable lastFrameNumber) {
376 if (DEBUG) {
377 Log.d(TAG, "submitRequest called.");
378 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700379 if (mLegacyDevice.isClosed()) {
380 Log.e(TAG, "Cannot submit request, device has been closed.");
381 return CameraBinderDecorator.ENODEV;
382 }
383
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700384 synchronized(mConfigureLock) {
385 if (mConfiguring) {
386 Log.e(TAG, "Cannot submit request, configuration change in progress.");
387 return CameraBinderDecorator.INVALID_OPERATION;
388 }
389 }
390 return mLegacyDevice.submitRequest(request, streaming, lastFrameNumber);
391 }
392
393 @Override
394 public int submitRequestList(List<CaptureRequest> request, boolean streaming,
395 /*out*/LongParcelable lastFrameNumber) {
396 if (DEBUG) {
397 Log.d(TAG, "submitRequestList called.");
398 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700399 if (mLegacyDevice.isClosed()) {
400 Log.e(TAG, "Cannot submit request list, device has been closed.");
401 return CameraBinderDecorator.ENODEV;
402 }
403
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700404 synchronized(mConfigureLock) {
405 if (mConfiguring) {
406 Log.e(TAG, "Cannot submit request, configuration change in progress.");
407 return CameraBinderDecorator.INVALID_OPERATION;
408 }
409 }
410 return mLegacyDevice.submitRequestList(request, streaming, lastFrameNumber);
411 }
412
413 @Override
414 public int cancelRequest(int requestId, /*out*/LongParcelable lastFrameNumber) {
415 if (DEBUG) {
416 Log.d(TAG, "cancelRequest called.");
417 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700418 if (mLegacyDevice.isClosed()) {
419 Log.e(TAG, "Cannot cancel request, device has been closed.");
420 return CameraBinderDecorator.ENODEV;
421 }
422
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700423 synchronized(mConfigureLock) {
424 if (mConfiguring) {
425 Log.e(TAG, "Cannot cancel request, configuration change in progress.");
426 return CameraBinderDecorator.INVALID_OPERATION;
427 }
428 }
429 long lastFrame = mLegacyDevice.cancelRequest(requestId);
430 lastFrameNumber.setNumber(lastFrame);
431 return CameraBinderDecorator.NO_ERROR;
432 }
433
434 @Override
435 public int beginConfigure() {
436 if (DEBUG) {
437 Log.d(TAG, "beginConfigure called.");
438 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700439 if (mLegacyDevice.isClosed()) {
440 Log.e(TAG, "Cannot begin configure, device has been closed.");
441 return CameraBinderDecorator.ENODEV;
442 }
443
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700444 synchronized(mConfigureLock) {
445 if (mConfiguring) {
446 Log.e(TAG, "Cannot begin configure, configuration change already in progress.");
447 return CameraBinderDecorator.INVALID_OPERATION;
448 }
449 mConfiguring = true;
450 }
451 return CameraBinderDecorator.NO_ERROR;
452 }
453
454 @Override
455 public int endConfigure() {
456 if (DEBUG) {
457 Log.d(TAG, "endConfigure called.");
458 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700459 if (mLegacyDevice.isClosed()) {
460 Log.e(TAG, "Cannot end configure, device has been closed.");
461 return CameraBinderDecorator.ENODEV;
462 }
463
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700464 ArrayList<Surface> surfaces = null;
465 synchronized(mConfigureLock) {
466 if (!mConfiguring) {
467 Log.e(TAG, "Cannot end configure, no configuration change in progress.");
468 return CameraBinderDecorator.INVALID_OPERATION;
469 }
470 int numSurfaces = mSurfaces.size();
471 if (numSurfaces > 0) {
Ruben Brunk5776aaf2014-06-19 13:42:40 -0700472 surfaces = new ArrayList<>();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700473 for (int i = 0; i < numSurfaces; ++i) {
474 surfaces.add(mSurfaces.valueAt(i));
475 }
476 }
477 mConfiguring = false;
478 }
479 return mLegacyDevice.configureOutputs(surfaces);
480 }
481
482 @Override
483 public int deleteStream(int streamId) {
484 if (DEBUG) {
485 Log.d(TAG, "deleteStream called.");
486 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700487 if (mLegacyDevice.isClosed()) {
488 Log.e(TAG, "Cannot delete stream, device has been closed.");
489 return CameraBinderDecorator.ENODEV;
490 }
491
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700492 synchronized(mConfigureLock) {
493 if (!mConfiguring) {
494 Log.e(TAG, "Cannot delete stream, beginConfigure hasn't been called yet.");
495 return CameraBinderDecorator.INVALID_OPERATION;
496 }
497 int index = mSurfaces.indexOfKey(streamId);
498 if (index < 0) {
499 Log.e(TAG, "Cannot delete stream, stream id " + streamId + " doesn't exist.");
500 return CameraBinderDecorator.BAD_VALUE;
501 }
502 mSurfaces.removeAt(index);
503 }
504 return CameraBinderDecorator.NO_ERROR;
505 }
506
507 @Override
Yin-Chia Yeh981e0562015-03-12 13:39:26 -0700508 public int createStream(OutputConfiguration outputConfiguration) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700509 if (DEBUG) {
510 Log.d(TAG, "createStream called.");
511 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700512 if (mLegacyDevice.isClosed()) {
513 Log.e(TAG, "Cannot create stream, device has been closed.");
514 return CameraBinderDecorator.ENODEV;
515 }
516
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700517 synchronized(mConfigureLock) {
518 if (!mConfiguring) {
519 Log.e(TAG, "Cannot create stream, beginConfigure hasn't been called yet.");
520 return CameraBinderDecorator.INVALID_OPERATION;
521 }
Yin-Chia Yeh981e0562015-03-12 13:39:26 -0700522 if (outputConfiguration.getRotation() != OutputConfiguration.ROTATION_0) {
523 Log.e(TAG, "Cannot create stream, stream rotation is not supported.");
524 return CameraBinderDecorator.INVALID_OPERATION;
525 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700526 int id = ++mSurfaceIdCounter;
Yin-Chia Yeh981e0562015-03-12 13:39:26 -0700527 mSurfaces.put(id, outputConfiguration.getSurface());
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700528 return id;
529 }
530 }
531
532 @Override
533 public int createDefaultRequest(int templateId, /*out*/CameraMetadataNative request) {
534 if (DEBUG) {
535 Log.d(TAG, "createDefaultRequest called.");
536 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700537 if (mLegacyDevice.isClosed()) {
538 Log.e(TAG, "Cannot create default request, device has been closed.");
539 return CameraBinderDecorator.ENODEV;
540 }
Igor Murashkina296fec2014-06-23 14:44:09 -0700541
542 CameraMetadataNative template;
543 try {
544 template =
545 LegacyMetadataMapper.createRequestTemplate(mCameraCharacteristics, templateId);
546 } catch (IllegalArgumentException e) {
547 Log.e(TAG, "createDefaultRequest - invalid templateId specified");
548 return CameraBinderDecorator.BAD_VALUE;
549 }
550
551 request.swap(template);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700552 return CameraBinderDecorator.NO_ERROR;
553 }
554
555 @Override
556 public int getCameraInfo(/*out*/CameraMetadataNative info) {
557 if (DEBUG) {
558 Log.d(TAG, "getCameraInfo called.");
559 }
560 // TODO: implement getCameraInfo.
561 Log.e(TAG, "getCameraInfo unimplemented.");
562 return CameraBinderDecorator.NO_ERROR;
563 }
564
565 @Override
566 public int waitUntilIdle() throws RemoteException {
567 if (DEBUG) {
568 Log.d(TAG, "waitUntilIdle called.");
569 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700570 if (mLegacyDevice.isClosed()) {
571 Log.e(TAG, "Cannot wait until idle, device has been closed.");
572 return CameraBinderDecorator.ENODEV;
573 }
574
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700575 synchronized(mConfigureLock) {
576 if (mConfiguring) {
577 Log.e(TAG, "Cannot wait until idle, configuration change in progress.");
578 return CameraBinderDecorator.INVALID_OPERATION;
579 }
580 }
581 mLegacyDevice.waitUntilIdle();
582 return CameraBinderDecorator.NO_ERROR;
583 }
584
585 @Override
586 public int flush(/*out*/LongParcelable lastFrameNumber) {
587 if (DEBUG) {
588 Log.d(TAG, "flush called.");
589 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700590 if (mLegacyDevice.isClosed()) {
591 Log.e(TAG, "Cannot flush, device has been closed.");
592 return CameraBinderDecorator.ENODEV;
593 }
594
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700595 synchronized(mConfigureLock) {
596 if (mConfiguring) {
597 Log.e(TAG, "Cannot flush, configuration change in progress.");
598 return CameraBinderDecorator.INVALID_OPERATION;
599 }
600 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700601 long lastFrame = mLegacyDevice.flush();
602 if (lastFrameNumber != null) {
603 lastFrameNumber.setNumber(lastFrame);
604 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700605 return CameraBinderDecorator.NO_ERROR;
606 }
607
608 @Override
609 public IBinder asBinder() {
610 // This is solely intended to be used for in-process binding.
611 return null;
612 }
613}