blob: d01c275e74dc061caa592327d26cbf0aaf197783 [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
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080019import android.hardware.ICameraService;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070020import android.hardware.Camera;
Igor Murashkina296fec2014-06-23 14:44:09 -070021import android.hardware.Camera.CameraInfo;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070022import android.hardware.camera2.CameraAccessException;
Igor Murashkina296fec2014-06-23 14:44:09 -070023import android.hardware.camera2.CameraCharacteristics;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070024import android.hardware.camera2.CaptureRequest;
25import android.hardware.camera2.ICameraDeviceCallbacks;
26import android.hardware.camera2.ICameraDeviceUser;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070027import android.hardware.camera2.impl.CameraMetadataNative;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070028import android.hardware.camera2.impl.CaptureResultExtras;
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -070029import android.hardware.camera2.params.OutputConfiguration;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080030import android.hardware.camera2.utils.SubmitInfo;
Igor Murashkina296fec2014-06-23 14:44:09 -070031import android.os.ConditionVariable;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070032import android.os.IBinder;
Igor Murashkina296fec2014-06-23 14:44:09 -070033import android.os.Looper;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070034import android.os.Handler;
35import android.os.HandlerThread;
36import android.os.Message;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070037import android.os.RemoteException;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080038import android.os.ServiceSpecificException;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070039import 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
Lazar Trsic8ea56f62015-07-07 17:31:20 +020046import static android.system.OsConstants.EACCES;
47import static android.system.OsConstants.ENODEV;
48
Ruben Brunkfeb50af2014-05-09 19:58:49 -070049/**
50 * Compatibility implementation of the Camera2 API binder interface.
51 *
52 * <p>
53 * This is intended to be called from the same process as client
54 * {@link android.hardware.camera2.CameraDevice}, and wraps a
55 * {@link android.hardware.camera2.legacy.LegacyCameraDevice} that emulates Camera2 service using
56 * the Camera1 API.
57 * </p>
58 *
59 * <p>
60 * Keep up to date with ICameraDeviceUser.aidl.
61 * </p>
62 */
Igor Murashkin66533622014-08-19 14:51:47 -070063@SuppressWarnings("deprecation")
Ruben Brunkfeb50af2014-05-09 19:58:49 -070064public class CameraDeviceUserShim implements ICameraDeviceUser {
65 private static final String TAG = "CameraDeviceUserShim";
66
Eino-Ville Talvalaa78791f2015-06-01 12:39:54 -070067 private static final boolean DEBUG = false;
Igor Murashkina296fec2014-06-23 14:44:09 -070068 private static final int OPEN_CAMERA_TIMEOUT_MS = 5000; // 5 sec (same as api1 cts timeout)
Ruben Brunkfeb50af2014-05-09 19:58:49 -070069
70 private final LegacyCameraDevice mLegacyDevice;
71
72 private final Object mConfigureLock = new Object();
73 private int mSurfaceIdCounter;
74 private boolean mConfiguring;
75 private final SparseArray<Surface> mSurfaces;
Igor Murashkina296fec2014-06-23 14:44:09 -070076 private final CameraCharacteristics mCameraCharacteristics;
77 private final CameraLooper mCameraInit;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070078 private final CameraCallbackThread mCameraCallbacks;
79
Ruben Brunkfeb50af2014-05-09 19:58:49 -070080
Igor Murashkina296fec2014-06-23 14:44:09 -070081 protected CameraDeviceUserShim(int cameraId, LegacyCameraDevice legacyCamera,
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070082 CameraCharacteristics characteristics, CameraLooper cameraInit,
83 CameraCallbackThread cameraCallbacks) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -070084 mLegacyDevice = legacyCamera;
85 mConfiguring = false;
86 mSurfaces = new SparseArray<Surface>();
Igor Murashkina296fec2014-06-23 14:44:09 -070087 mCameraCharacteristics = characteristics;
88 mCameraInit = cameraInit;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070089 mCameraCallbacks = cameraCallbacks;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070090
91 mSurfaceIdCounter = 0;
92 }
93
Lazar Trsic8ea56f62015-07-07 17:31:20 +020094 private static int translateErrorsFromCamera1(int errorCode) {
95 if (errorCode == -EACCES) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080096 return ICameraService.ERROR_PERMISSION_DENIED;
Lazar Trsic8ea56f62015-07-07 17:31:20 +020097 }
98
99 return errorCode;
100 }
101
Igor Murashkina296fec2014-06-23 14:44:09 -0700102 /**
103 * Create a separate looper/thread for the camera to run on; open the camera.
104 *
105 * <p>Since the camera automatically latches on to the current thread's looper,
106 * it's important that we have our own thread with our own looper to guarantee
107 * that the camera callbacks get correctly posted to our own thread.</p>
108 */
109 private static class CameraLooper implements Runnable, AutoCloseable {
110 private final int mCameraId;
111 private Looper mLooper;
112 private volatile int mInitErrors;
113 private final Camera mCamera = Camera.openUninitialized();
114 private final ConditionVariable mStartDone = new ConditionVariable();
115 private final Thread mThread;
116
117 /**
118 * Spin up a new thread, immediately open the camera in the background.
119 *
120 * <p>Use {@link #waitForOpen} to block until the camera is finished opening.</p>
121 *
122 * @param cameraId numeric camera Id
123 *
124 * @see #waitForOpen
125 */
126 public CameraLooper(int cameraId) {
127 mCameraId = cameraId;
128
129 mThread = new Thread(this);
130 mThread.start();
131 }
132
133 public Camera getCamera() {
134 return mCamera;
135 }
136
137 @Override
138 public void run() {
139 // Set up a looper to be used by camera.
140 Looper.prepare();
141
142 // Save the looper so that we can terminate this thread
143 // after we are done with it.
144 mLooper = Looper.myLooper();
Eino-Ville Talvaladb70a972015-06-03 16:27:11 -0700145 mInitErrors = mCamera.cameraInitUnspecified(mCameraId);
Igor Murashkina296fec2014-06-23 14:44:09 -0700146 mStartDone.open();
147 Looper.loop(); // Blocks forever until #close is called.
148 }
149
150 /**
151 * Quit the looper safely; then join until the thread shuts down.
152 */
153 @Override
154 public void close() {
155 if (mLooper == null) {
156 return;
157 }
158
159 mLooper.quitSafely();
160 try {
161 mThread.join();
162 } catch (InterruptedException e) {
163 throw new AssertionError(e);
164 }
165
166 mLooper = null;
167 }
168
169 /**
170 * Block until the camera opens; then return its initialization error code (if any).
171 *
172 * @param timeoutMs timeout in milliseconds
173 *
174 * @return int error code
175 *
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800176 * @throws ServiceSpecificException if the camera open times out with ({@code CAMERA_ERROR})
Igor Murashkina296fec2014-06-23 14:44:09 -0700177 */
178 public int waitForOpen(int timeoutMs) {
179 // Block until the camera is open asynchronously
180 if (!mStartDone.block(timeoutMs)) {
181 Log.e(TAG, "waitForOpen - Camera failed to open after timeout of "
182 + OPEN_CAMERA_TIMEOUT_MS + " ms");
183 try {
184 mCamera.release();
185 } catch (RuntimeException e) {
186 Log.e(TAG, "connectBinderShim - Failed to release camera after timeout ", e);
187 }
188
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800189 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION);
Igor Murashkina296fec2014-06-23 14:44:09 -0700190 }
191
192 return mInitErrors;
193 }
194 }
195
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700196 /**
197 * A thread to process callbacks to send back to the camera client.
198 *
199 * <p>This effectively emulates one-way binder semantics when in the same process as the
200 * callee.</p>
201 */
202 private static class CameraCallbackThread implements ICameraDeviceCallbacks {
203 private static final int CAMERA_ERROR = 0;
204 private static final int CAMERA_IDLE = 1;
205 private static final int CAPTURE_STARTED = 2;
206 private static final int RESULT_RECEIVED = 3;
Eino-Ville Talvalabe6d9852015-04-29 11:37:00 -0700207 private static final int PREPARED = 4;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700208
209 private final HandlerThread mHandlerThread;
210 private Handler mHandler;
211
212 private final ICameraDeviceCallbacks mCallbacks;
213
214 public CameraCallbackThread(ICameraDeviceCallbacks callbacks) {
215 mCallbacks = callbacks;
216
217 mHandlerThread = new HandlerThread("LegacyCameraCallback");
218 mHandlerThread.start();
219 }
220
221 public void close() {
222 mHandlerThread.quitSafely();
223 }
224
225 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700226 public void onDeviceError(final int errorCode, final CaptureResultExtras resultExtras) {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700227 Message msg = getHandler().obtainMessage(CAMERA_ERROR,
228 /*arg1*/ errorCode, /*arg2*/ 0,
229 /*obj*/ resultExtras);
230 getHandler().sendMessage(msg);
231 }
232
233 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700234 public void onDeviceIdle() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700235 Message msg = getHandler().obtainMessage(CAMERA_IDLE);
236 getHandler().sendMessage(msg);
237 }
238
239 @Override
240 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
241 Message msg = getHandler().obtainMessage(CAPTURE_STARTED,
242 /*arg1*/ (int) (timestamp & 0xFFFFFFFFL),
243 /*arg2*/ (int) ( (timestamp >> 32) & 0xFFFFFFFFL),
244 /*obj*/ resultExtras);
245 getHandler().sendMessage(msg);
246 }
247
248 @Override
249 public void onResultReceived(final CameraMetadataNative result,
250 final CaptureResultExtras resultExtras) {
251 Object[] resultArray = new Object[] { result, resultExtras };
252 Message msg = getHandler().obtainMessage(RESULT_RECEIVED,
253 /*obj*/ resultArray);
254 getHandler().sendMessage(msg);
255 }
256
257 @Override
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700258 public void onPrepared(int streamId) {
Eino-Ville Talvalabe6d9852015-04-29 11:37:00 -0700259 Message msg = getHandler().obtainMessage(PREPARED,
260 /*arg1*/ streamId, /*arg2*/ 0);
261 getHandler().sendMessage(msg);
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700262 }
263
264 @Override
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700265 public IBinder asBinder() {
266 // This is solely intended to be used for in-process binding.
267 return null;
268 }
269
270 private Handler getHandler() {
271 if (mHandler == null) {
272 mHandler = new CallbackHandler(mHandlerThread.getLooper());
273 }
274 return mHandler;
275 }
276
277 private class CallbackHandler extends Handler {
278 public CallbackHandler(Looper l) {
279 super(l);
280 }
281
Igor Murashkin66533622014-08-19 14:51:47 -0700282 @Override
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700283 public void handleMessage(Message msg) {
284 try {
285 switch (msg.what) {
286 case CAMERA_ERROR: {
287 int errorCode = msg.arg1;
288 CaptureResultExtras resultExtras = (CaptureResultExtras) msg.obj;
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700289 mCallbacks.onDeviceError(errorCode, resultExtras);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700290 break;
291 }
292 case CAMERA_IDLE:
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700293 mCallbacks.onDeviceIdle();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700294 break;
295 case CAPTURE_STARTED: {
296 long timestamp = msg.arg2 & 0xFFFFFFFFL;
297 timestamp = (timestamp << 32) | (msg.arg1 & 0xFFFFFFFFL);
298 CaptureResultExtras resultExtras = (CaptureResultExtras) msg.obj;
299 mCallbacks.onCaptureStarted(resultExtras, timestamp);
300 break;
301 }
302 case RESULT_RECEIVED: {
303 Object[] resultArray = (Object[]) msg.obj;
304 CameraMetadataNative result = (CameraMetadataNative) resultArray[0];
305 CaptureResultExtras resultExtras = (CaptureResultExtras) resultArray[1];
306 mCallbacks.onResultReceived(result, resultExtras);
307 break;
308 }
Eino-Ville Talvalabe6d9852015-04-29 11:37:00 -0700309 case PREPARED: {
310 int streamId = msg.arg1;
311 mCallbacks.onPrepared(streamId);
312 break;
313 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700314 default:
315 throw new IllegalArgumentException(
316 "Unknown callback message " + msg.what);
317 }
318 } catch (RemoteException e) {
319 throw new IllegalStateException(
320 "Received remote exception during camera callback " + msg.what, e);
321 }
322 }
323 }
324 }
325
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700326 public static CameraDeviceUserShim connectBinderShim(ICameraDeviceCallbacks callbacks,
327 int cameraId) {
328 if (DEBUG) {
329 Log.d(TAG, "Opening shim Camera device");
330 }
Igor Murashkina296fec2014-06-23 14:44:09 -0700331
332 /*
333 * Put the camera open on a separate thread with its own looper; otherwise
334 * if the main thread is used then the callbacks might never get delivered
335 * (e.g. in CTS which run its own default looper only after tests)
336 */
337
338 CameraLooper init = new CameraLooper(cameraId);
339
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700340 CameraCallbackThread threadCallbacks = new CameraCallbackThread(callbacks);
341
Igor Murashkina296fec2014-06-23 14:44:09 -0700342 // TODO: Make this async instead of blocking
343 int initErrors = init.waitForOpen(OPEN_CAMERA_TIMEOUT_MS);
344 Camera legacyCamera = init.getCamera();
Igor Murashkina1d66272014-06-20 11:22:11 -0700345
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700346 // Check errors old HAL initialization
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800347 LegacyExceptionUtils.throwOnServiceError(initErrors);
Igor Murashkina1d66272014-06-20 11:22:11 -0700348
Igor Murashkin66533622014-08-19 14:51:47 -0700349 // Disable shutter sounds (this will work unconditionally) for api2 clients
350 legacyCamera.disableShutterSound();
351
Igor Murashkina296fec2014-06-23 14:44:09 -0700352 CameraInfo info = new CameraInfo();
353 Camera.getCameraInfo(cameraId, info);
354
Eino-Ville Talvalaeecc9042014-09-23 16:37:31 -0700355 Camera.Parameters legacyParameters = null;
356 try {
357 legacyParameters = legacyCamera.getParameters();
358 } catch (RuntimeException e) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800359 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION,
360 "Unable to get initial parameters: " + e.getMessage());
Eino-Ville Talvalaeecc9042014-09-23 16:37:31 -0700361 }
362
Igor Murashkina296fec2014-06-23 14:44:09 -0700363 CameraCharacteristics characteristics =
Eino-Ville Talvalaeecc9042014-09-23 16:37:31 -0700364 LegacyMetadataMapper.createCharacteristics(legacyParameters, info);
Igor Murashkindf6242e2014-07-01 18:06:13 -0700365 LegacyCameraDevice device = new LegacyCameraDevice(
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700366 cameraId, legacyCamera, characteristics, threadCallbacks);
367 return new CameraDeviceUserShim(cameraId, device, characteristics, init, threadCallbacks);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700368 }
369
370 @Override
371 public void disconnect() {
372 if (DEBUG) {
373 Log.d(TAG, "disconnect called.");
374 }
Igor Murashkina296fec2014-06-23 14:44:09 -0700375
Ruben Brunke663cb772014-09-16 13:18:31 -0700376 if (mLegacyDevice.isClosed()) {
377 Log.w(TAG, "Cannot disconnect, device has already been closed.");
378 }
379
Igor Murashkina296fec2014-06-23 14:44:09 -0700380 try {
381 mLegacyDevice.close();
382 } finally {
383 mCameraInit.close();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700384 mCameraCallbacks.close();
Igor Murashkina296fec2014-06-23 14:44:09 -0700385 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700386 }
387
388 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800389 public SubmitInfo submitRequest(CaptureRequest request, boolean streaming) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700390 if (DEBUG) {
391 Log.d(TAG, "submitRequest called.");
392 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700393 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800394 String err = "Cannot submit request, device has been closed.";
395 Log.e(TAG, err);
396 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700397 }
398
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700399 synchronized(mConfigureLock) {
400 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800401 String err = "Cannot submit request, configuration change in progress.";
402 Log.e(TAG, err);
403 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700404 }
405 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800406 return mLegacyDevice.submitRequest(request, streaming);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700407 }
408
409 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800410 public SubmitInfo submitRequestList(CaptureRequest[] request, boolean streaming) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700411 if (DEBUG) {
412 Log.d(TAG, "submitRequestList called.");
413 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700414 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800415 String err = "Cannot submit request list, device has been closed.";
416 Log.e(TAG, err);
417 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700418 }
419
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700420 synchronized(mConfigureLock) {
421 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800422 String err = "Cannot submit request, configuration change in progress.";
423 Log.e(TAG, err);
424 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700425 }
426 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800427 return mLegacyDevice.submitRequestList(request, streaming);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700428 }
429
430 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800431 public long cancelRequest(int requestId) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700432 if (DEBUG) {
433 Log.d(TAG, "cancelRequest called.");
434 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700435 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800436 String err = "Cannot cancel request, device has been closed.";
437 Log.e(TAG, err);
438 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700439 }
440
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700441 synchronized(mConfigureLock) {
442 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800443 String err = "Cannot cancel request, configuration change in progress.";
444 Log.e(TAG, err);
445 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700446 }
447 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800448 return mLegacyDevice.cancelRequest(requestId);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700449 }
450
451 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800452 public void beginConfigure() {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700453 if (DEBUG) {
454 Log.d(TAG, "beginConfigure called.");
455 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700456 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800457 String err = "Cannot begin configure, device has been closed.";
458 Log.e(TAG, err);
459 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700460 }
461
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700462 synchronized(mConfigureLock) {
463 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800464 String err = "Cannot begin configure, configuration change already in progress.";
465 Log.e(TAG, err);
466 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700467 }
468 mConfiguring = true;
469 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700470 }
471
472 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800473 public void endConfigure(boolean isConstrainedHighSpeed) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700474 if (DEBUG) {
475 Log.d(TAG, "endConfigure called.");
476 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700477 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800478 String err = "Cannot end configure, device has been closed.";
479 Log.e(TAG, err);
480 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700481 }
482
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700483 ArrayList<Surface> surfaces = null;
484 synchronized(mConfigureLock) {
485 if (!mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800486 String err = "Cannot end configure, no configuration change in progress.";
487 Log.e(TAG, err);
488 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700489 }
490 int numSurfaces = mSurfaces.size();
491 if (numSurfaces > 0) {
Ruben Brunk5776aaf2014-06-19 13:42:40 -0700492 surfaces = new ArrayList<>();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700493 for (int i = 0; i < numSurfaces; ++i) {
494 surfaces.add(mSurfaces.valueAt(i));
495 }
496 }
497 mConfiguring = false;
498 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800499 mLegacyDevice.configureOutputs(surfaces);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700500 }
501
502 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800503 public void deleteStream(int streamId) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700504 if (DEBUG) {
505 Log.d(TAG, "deleteStream called.");
506 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700507 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800508 String err = "Cannot delete stream, device has been closed.";
509 Log.e(TAG, err);
510 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700511 }
512
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700513 synchronized(mConfigureLock) {
514 if (!mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800515 String err = "Cannot delete stream, no configuration change in progress.";
516 Log.e(TAG, err);
517 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700518 }
519 int index = mSurfaces.indexOfKey(streamId);
520 if (index < 0) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800521 String err = "Cannot delete stream, stream id " + streamId + " doesn't exist.";
522 Log.e(TAG, err);
523 throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700524 }
525 mSurfaces.removeAt(index);
526 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700527 }
528
529 @Override
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700530 public int createStream(OutputConfiguration outputConfiguration) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700531 if (DEBUG) {
532 Log.d(TAG, "createStream called.");
533 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700534 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800535 String err = "Cannot create stream, device has been closed.";
536 Log.e(TAG, err);
537 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700538 }
539
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700540 synchronized(mConfigureLock) {
541 if (!mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800542 String err = "Cannot create stream, beginConfigure hasn't been called yet.";
543 Log.e(TAG, err);
544 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700545 }
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700546 if (outputConfiguration.getRotation() != OutputConfiguration.ROTATION_0) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800547 String err = "Cannot create stream, stream rotation is not supported.";
548 Log.e(TAG, err);
549 throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700550 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700551 int id = ++mSurfaceIdCounter;
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700552 mSurfaces.put(id, outputConfiguration.getSurface());
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700553 return id;
554 }
555 }
556
557 @Override
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700558 public int createInputStream(int width, int height, int format) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800559 String err = "Creating input stream is not supported on legacy devices";
560 Log.e(TAG, err);
561 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700562 }
563
564 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800565 public Surface getInputSurface() {
566 String err = "Getting input surface is not supported on legacy devices";
567 Log.e(TAG, err);
568 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700569 }
570
571 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800572 public CameraMetadataNative createDefaultRequest(int templateId) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700573 if (DEBUG) {
574 Log.d(TAG, "createDefaultRequest called.");
575 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700576 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800577 String err = "Cannot create default request, device has been closed.";
578 Log.e(TAG, err);
579 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700580 }
Igor Murashkina296fec2014-06-23 14:44:09 -0700581
582 CameraMetadataNative template;
583 try {
584 template =
585 LegacyMetadataMapper.createRequestTemplate(mCameraCharacteristics, templateId);
586 } catch (IllegalArgumentException e) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800587 String err = "createDefaultRequest - invalid templateId specified";
588 Log.e(TAG, err);
589 throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
Igor Murashkina296fec2014-06-23 14:44:09 -0700590 }
591
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800592 return template;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700593 }
594
595 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800596 public CameraMetadataNative getCameraInfo() {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700597 if (DEBUG) {
598 Log.d(TAG, "getCameraInfo called.");
599 }
600 // TODO: implement getCameraInfo.
601 Log.e(TAG, "getCameraInfo unimplemented.");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800602 return null;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700603 }
604
605 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800606 public void waitUntilIdle() throws RemoteException {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700607 if (DEBUG) {
608 Log.d(TAG, "waitUntilIdle called.");
609 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700610 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800611 String err = "Cannot wait until idle, device has been closed.";
612 Log.e(TAG, err);
613 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700614 }
615
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700616 synchronized(mConfigureLock) {
617 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800618 String err = "Cannot wait until idle, configuration change in progress.";
619 Log.e(TAG, err);
620 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700621 }
622 }
623 mLegacyDevice.waitUntilIdle();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700624 }
625
626 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800627 public long flush() {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700628 if (DEBUG) {
629 Log.d(TAG, "flush called.");
630 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700631 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800632 String err = "Cannot flush, device has been closed.";
633 Log.e(TAG, err);
634 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700635 }
636
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700637 synchronized(mConfigureLock) {
638 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800639 String err = "Cannot flush, configuration change in progress.";
640 Log.e(TAG, err);
641 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700642 }
643 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800644 return mLegacyDevice.flush();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700645 }
646
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800647 public void prepare(int streamId) {
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700648 if (DEBUG) {
649 Log.d(TAG, "prepare called.");
650 }
651 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800652 String err = "Cannot prepare stream, device has been closed.";
653 Log.e(TAG, err);
654 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700655 }
656
Eino-Ville Talvalabe6d9852015-04-29 11:37:00 -0700657 // LEGACY doesn't support actual prepare, just signal success right away
658 mCameraCallbacks.onPrepared(streamId);
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700659 }
660
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800661 public void prepare2(int maxCount, int streamId) {
Ruben Brunk7ed1aaa2015-08-13 17:57:14 -0700662 // We don't support this in LEGACY mode.
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800663 prepare(streamId);
Ruben Brunk7ed1aaa2015-08-13 17:57:14 -0700664 }
665
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800666 public void tearDown(int streamId) {
Eino-Ville Talvala14c09fa2015-07-15 16:04:04 -0700667 if (DEBUG) {
668 Log.d(TAG, "tearDown called.");
669 }
670 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800671 String err = "Cannot tear down stream, device has been closed.";
672 Log.e(TAG, err);
673 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Eino-Ville Talvala14c09fa2015-07-15 16:04:04 -0700674 }
675
676 // LEGACY doesn't support actual teardown, so just a no-op
Eino-Ville Talvala14c09fa2015-07-15 16:04:04 -0700677 }
678
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700679 @Override
680 public IBinder asBinder() {
681 // This is solely intended to be used for in-process binding.
682 return null;
683 }
684}