blob: bc7b1260751e5f115dc4e1e6a21a95a110fa723d [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;
Shuzhen Wang0960fb42018-01-10 20:35:11 -080029import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -070030import android.hardware.camera2.params.OutputConfiguration;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080031import android.hardware.camera2.utils.SubmitInfo;
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;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080039import android.os.ServiceSpecificException;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070040import android.util.Log;
41import android.util.SparseArray;
42import android.view.Surface;
43
44import java.util.ArrayList;
45import java.util.List;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070046
Lazar Trsic8ea56f62015-07-07 17:31:20 +020047import static android.system.OsConstants.EACCES;
48import static android.system.OsConstants.ENODEV;
49
Ruben Brunkfeb50af2014-05-09 19:58:49 -070050/**
51 * Compatibility implementation of the Camera2 API binder interface.
52 *
53 * <p>
54 * This is intended to be called from the same process as client
55 * {@link android.hardware.camera2.CameraDevice}, and wraps a
56 * {@link android.hardware.camera2.legacy.LegacyCameraDevice} that emulates Camera2 service using
57 * the Camera1 API.
58 * </p>
59 *
60 * <p>
61 * Keep up to date with ICameraDeviceUser.aidl.
62 * </p>
63 */
Igor Murashkin66533622014-08-19 14:51:47 -070064@SuppressWarnings("deprecation")
Ruben Brunkfeb50af2014-05-09 19:58:49 -070065public class CameraDeviceUserShim implements ICameraDeviceUser {
66 private static final String TAG = "CameraDeviceUserShim";
67
Eino-Ville Talvalaa78791f2015-06-01 12:39:54 -070068 private static final boolean DEBUG = false;
Igor Murashkina296fec2014-06-23 14:44:09 -070069 private static final int OPEN_CAMERA_TIMEOUT_MS = 5000; // 5 sec (same as api1 cts timeout)
Ruben Brunkfeb50af2014-05-09 19:58:49 -070070
71 private final LegacyCameraDevice mLegacyDevice;
72
73 private final Object mConfigureLock = new Object();
74 private int mSurfaceIdCounter;
75 private boolean mConfiguring;
76 private final SparseArray<Surface> mSurfaces;
Igor Murashkina296fec2014-06-23 14:44:09 -070077 private final CameraCharacteristics mCameraCharacteristics;
78 private final CameraLooper mCameraInit;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070079 private final CameraCallbackThread mCameraCallbacks;
80
Ruben Brunkfeb50af2014-05-09 19:58:49 -070081
Igor Murashkina296fec2014-06-23 14:44:09 -070082 protected CameraDeviceUserShim(int cameraId, LegacyCameraDevice legacyCamera,
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070083 CameraCharacteristics characteristics, CameraLooper cameraInit,
84 CameraCallbackThread cameraCallbacks) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -070085 mLegacyDevice = legacyCamera;
86 mConfiguring = false;
87 mSurfaces = new SparseArray<Surface>();
Igor Murashkina296fec2014-06-23 14:44:09 -070088 mCameraCharacteristics = characteristics;
89 mCameraInit = cameraInit;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070090 mCameraCallbacks = cameraCallbacks;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070091
92 mSurfaceIdCounter = 0;
93 }
94
Lazar Trsic8ea56f62015-07-07 17:31:20 +020095 private static int translateErrorsFromCamera1(int errorCode) {
96 if (errorCode == -EACCES) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080097 return ICameraService.ERROR_PERMISSION_DENIED;
Lazar Trsic8ea56f62015-07-07 17:31:20 +020098 }
99
100 return errorCode;
101 }
102
Igor Murashkina296fec2014-06-23 14:44:09 -0700103 /**
104 * Create a separate looper/thread for the camera to run on; open the camera.
105 *
106 * <p>Since the camera automatically latches on to the current thread's looper,
107 * it's important that we have our own thread with our own looper to guarantee
108 * that the camera callbacks get correctly posted to our own thread.</p>
109 */
110 private static class CameraLooper implements Runnable, AutoCloseable {
111 private final int mCameraId;
112 private Looper mLooper;
113 private volatile int mInitErrors;
114 private final Camera mCamera = Camera.openUninitialized();
115 private final ConditionVariable mStartDone = new ConditionVariable();
116 private final Thread mThread;
117
118 /**
119 * Spin up a new thread, immediately open the camera in the background.
120 *
121 * <p>Use {@link #waitForOpen} to block until the camera is finished opening.</p>
122 *
123 * @param cameraId numeric camera Id
124 *
125 * @see #waitForOpen
126 */
127 public CameraLooper(int cameraId) {
128 mCameraId = cameraId;
129
130 mThread = new Thread(this);
131 mThread.start();
132 }
133
134 public Camera getCamera() {
135 return mCamera;
136 }
137
138 @Override
139 public void run() {
140 // Set up a looper to be used by camera.
141 Looper.prepare();
142
143 // Save the looper so that we can terminate this thread
144 // after we are done with it.
145 mLooper = Looper.myLooper();
Eino-Ville Talvaladb70a972015-06-03 16:27:11 -0700146 mInitErrors = mCamera.cameraInitUnspecified(mCameraId);
Igor Murashkina296fec2014-06-23 14:44:09 -0700147 mStartDone.open();
148 Looper.loop(); // Blocks forever until #close is called.
149 }
150
151 /**
152 * Quit the looper safely; then join until the thread shuts down.
153 */
154 @Override
155 public void close() {
156 if (mLooper == null) {
157 return;
158 }
159
160 mLooper.quitSafely();
161 try {
162 mThread.join();
163 } catch (InterruptedException e) {
164 throw new AssertionError(e);
165 }
166
167 mLooper = null;
168 }
169
170 /**
171 * Block until the camera opens; then return its initialization error code (if any).
172 *
173 * @param timeoutMs timeout in milliseconds
174 *
175 * @return int error code
176 *
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800177 * @throws ServiceSpecificException if the camera open times out with ({@code CAMERA_ERROR})
Igor Murashkina296fec2014-06-23 14:44:09 -0700178 */
179 public int waitForOpen(int timeoutMs) {
180 // Block until the camera is open asynchronously
181 if (!mStartDone.block(timeoutMs)) {
182 Log.e(TAG, "waitForOpen - Camera failed to open after timeout of "
183 + OPEN_CAMERA_TIMEOUT_MS + " ms");
184 try {
185 mCamera.release();
186 } catch (RuntimeException e) {
187 Log.e(TAG, "connectBinderShim - Failed to release camera after timeout ", e);
188 }
189
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800190 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION);
Igor Murashkina296fec2014-06-23 14:44:09 -0700191 }
192
193 return mInitErrors;
194 }
195 }
196
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700197 /**
198 * A thread to process callbacks to send back to the camera client.
199 *
200 * <p>This effectively emulates one-way binder semantics when in the same process as the
201 * callee.</p>
202 */
203 private static class CameraCallbackThread implements ICameraDeviceCallbacks {
204 private static final int CAMERA_ERROR = 0;
205 private static final int CAMERA_IDLE = 1;
206 private static final int CAPTURE_STARTED = 2;
207 private static final int RESULT_RECEIVED = 3;
Eino-Ville Talvalabe6d9852015-04-29 11:37:00 -0700208 private static final int PREPARED = 4;
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700209 private static final int REPEATING_REQUEST_ERROR = 5;
Shuzhen Wang88f1af22016-09-30 10:29:28 -0700210 private static final int REQUEST_QUEUE_EMPTY = 6;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700211
212 private final HandlerThread mHandlerThread;
213 private Handler mHandler;
214
215 private final ICameraDeviceCallbacks mCallbacks;
216
217 public CameraCallbackThread(ICameraDeviceCallbacks callbacks) {
218 mCallbacks = callbacks;
219
220 mHandlerThread = new HandlerThread("LegacyCameraCallback");
221 mHandlerThread.start();
222 }
223
224 public void close() {
225 mHandlerThread.quitSafely();
226 }
227
228 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700229 public void onDeviceError(final int errorCode, final CaptureResultExtras resultExtras) {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700230 Message msg = getHandler().obtainMessage(CAMERA_ERROR,
231 /*arg1*/ errorCode, /*arg2*/ 0,
232 /*obj*/ resultExtras);
233 getHandler().sendMessage(msg);
234 }
235
236 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700237 public void onDeviceIdle() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700238 Message msg = getHandler().obtainMessage(CAMERA_IDLE);
239 getHandler().sendMessage(msg);
240 }
241
242 @Override
243 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
244 Message msg = getHandler().obtainMessage(CAPTURE_STARTED,
245 /*arg1*/ (int) (timestamp & 0xFFFFFFFFL),
246 /*arg2*/ (int) ( (timestamp >> 32) & 0xFFFFFFFFL),
247 /*obj*/ resultExtras);
248 getHandler().sendMessage(msg);
249 }
250
251 @Override
252 public void onResultReceived(final CameraMetadataNative result,
Shuzhen Wang0960fb42018-01-10 20:35:11 -0800253 final CaptureResultExtras resultExtras,
254 PhysicalCaptureResultInfo physicalResults[]) {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700255 Object[] resultArray = new Object[] { result, resultExtras };
256 Message msg = getHandler().obtainMessage(RESULT_RECEIVED,
257 /*obj*/ resultArray);
258 getHandler().sendMessage(msg);
259 }
260
261 @Override
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700262 public void onPrepared(int streamId) {
Eino-Ville Talvalabe6d9852015-04-29 11:37:00 -0700263 Message msg = getHandler().obtainMessage(PREPARED,
264 /*arg1*/ streamId, /*arg2*/ 0);
265 getHandler().sendMessage(msg);
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700266 }
267
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700268 @Override
Yin-Chia Yeh8cd12e92017-09-05 18:14:21 -0700269 public void onRepeatingRequestError(long lastFrameNumber, int repeatingRequestId) {
270 Object[] objArray = new Object[] { lastFrameNumber, repeatingRequestId };
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700271 Message msg = getHandler().obtainMessage(REPEATING_REQUEST_ERROR,
Yin-Chia Yeh8cd12e92017-09-05 18:14:21 -0700272 /*obj*/ objArray);
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700273 getHandler().sendMessage(msg);
274 }
275
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700276 @Override
Shuzhen Wang88f1af22016-09-30 10:29:28 -0700277 public void onRequestQueueEmpty() {
278 Message msg = getHandler().obtainMessage(REQUEST_QUEUE_EMPTY,
279 /* arg1 */ 0, /* arg2 */ 0);
280 getHandler().sendMessage(msg);
281 }
282
283 @Override
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700284 public IBinder asBinder() {
285 // This is solely intended to be used for in-process binding.
286 return null;
287 }
288
289 private Handler getHandler() {
290 if (mHandler == null) {
291 mHandler = new CallbackHandler(mHandlerThread.getLooper());
292 }
293 return mHandler;
294 }
295
296 private class CallbackHandler extends Handler {
297 public CallbackHandler(Looper l) {
298 super(l);
299 }
300
Igor Murashkin66533622014-08-19 14:51:47 -0700301 @Override
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700302 public void handleMessage(Message msg) {
303 try {
304 switch (msg.what) {
305 case CAMERA_ERROR: {
306 int errorCode = msg.arg1;
307 CaptureResultExtras resultExtras = (CaptureResultExtras) msg.obj;
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700308 mCallbacks.onDeviceError(errorCode, resultExtras);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700309 break;
310 }
311 case CAMERA_IDLE:
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700312 mCallbacks.onDeviceIdle();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700313 break;
314 case CAPTURE_STARTED: {
315 long timestamp = msg.arg2 & 0xFFFFFFFFL;
316 timestamp = (timestamp << 32) | (msg.arg1 & 0xFFFFFFFFL);
317 CaptureResultExtras resultExtras = (CaptureResultExtras) msg.obj;
318 mCallbacks.onCaptureStarted(resultExtras, timestamp);
319 break;
320 }
321 case RESULT_RECEIVED: {
322 Object[] resultArray = (Object[]) msg.obj;
323 CameraMetadataNative result = (CameraMetadataNative) resultArray[0];
324 CaptureResultExtras resultExtras = (CaptureResultExtras) resultArray[1];
Shuzhen Wang0960fb42018-01-10 20:35:11 -0800325 mCallbacks.onResultReceived(result, resultExtras,
326 new PhysicalCaptureResultInfo[0]);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700327 break;
328 }
Eino-Ville Talvalabe6d9852015-04-29 11:37:00 -0700329 case PREPARED: {
330 int streamId = msg.arg1;
331 mCallbacks.onPrepared(streamId);
332 break;
333 }
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700334 case REPEATING_REQUEST_ERROR: {
Yin-Chia Yeh8cd12e92017-09-05 18:14:21 -0700335 Object[] objArray = (Object[]) msg.obj;
336 long lastFrameNumber = (Long) objArray[0];
337 int repeatingRequestId = (Integer) objArray[1];
338 mCallbacks.onRepeatingRequestError(lastFrameNumber, repeatingRequestId);
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700339 break;
340 }
Shuzhen Wang88f1af22016-09-30 10:29:28 -0700341 case REQUEST_QUEUE_EMPTY: {
342 mCallbacks.onRequestQueueEmpty();
343 break;
344 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700345 default:
346 throw new IllegalArgumentException(
347 "Unknown callback message " + msg.what);
348 }
349 } catch (RemoteException e) {
350 throw new IllegalStateException(
351 "Received remote exception during camera callback " + msg.what, e);
352 }
353 }
354 }
355 }
356
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700357 public static CameraDeviceUserShim connectBinderShim(ICameraDeviceCallbacks callbacks,
358 int cameraId) {
359 if (DEBUG) {
360 Log.d(TAG, "Opening shim Camera device");
361 }
Igor Murashkina296fec2014-06-23 14:44:09 -0700362
363 /*
364 * Put the camera open on a separate thread with its own looper; otherwise
365 * if the main thread is used then the callbacks might never get delivered
366 * (e.g. in CTS which run its own default looper only after tests)
367 */
368
369 CameraLooper init = new CameraLooper(cameraId);
370
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700371 CameraCallbackThread threadCallbacks = new CameraCallbackThread(callbacks);
372
Igor Murashkina296fec2014-06-23 14:44:09 -0700373 // TODO: Make this async instead of blocking
374 int initErrors = init.waitForOpen(OPEN_CAMERA_TIMEOUT_MS);
375 Camera legacyCamera = init.getCamera();
Igor Murashkina1d66272014-06-20 11:22:11 -0700376
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700377 // Check errors old HAL initialization
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800378 LegacyExceptionUtils.throwOnServiceError(initErrors);
Igor Murashkina1d66272014-06-20 11:22:11 -0700379
Igor Murashkin66533622014-08-19 14:51:47 -0700380 // Disable shutter sounds (this will work unconditionally) for api2 clients
381 legacyCamera.disableShutterSound();
382
Igor Murashkina296fec2014-06-23 14:44:09 -0700383 CameraInfo info = new CameraInfo();
384 Camera.getCameraInfo(cameraId, info);
385
Eino-Ville Talvalaeecc9042014-09-23 16:37:31 -0700386 Camera.Parameters legacyParameters = null;
387 try {
388 legacyParameters = legacyCamera.getParameters();
389 } catch (RuntimeException e) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800390 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION,
391 "Unable to get initial parameters: " + e.getMessage());
Eino-Ville Talvalaeecc9042014-09-23 16:37:31 -0700392 }
393
Igor Murashkina296fec2014-06-23 14:44:09 -0700394 CameraCharacteristics characteristics =
Eino-Ville Talvalaeecc9042014-09-23 16:37:31 -0700395 LegacyMetadataMapper.createCharacteristics(legacyParameters, info);
Igor Murashkindf6242e2014-07-01 18:06:13 -0700396 LegacyCameraDevice device = new LegacyCameraDevice(
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700397 cameraId, legacyCamera, characteristics, threadCallbacks);
398 return new CameraDeviceUserShim(cameraId, device, characteristics, init, threadCallbacks);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700399 }
400
401 @Override
402 public void disconnect() {
403 if (DEBUG) {
404 Log.d(TAG, "disconnect called.");
405 }
Igor Murashkina296fec2014-06-23 14:44:09 -0700406
Ruben Brunke663cb772014-09-16 13:18:31 -0700407 if (mLegacyDevice.isClosed()) {
408 Log.w(TAG, "Cannot disconnect, device has already been closed.");
409 }
410
Igor Murashkina296fec2014-06-23 14:44:09 -0700411 try {
412 mLegacyDevice.close();
413 } finally {
414 mCameraInit.close();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700415 mCameraCallbacks.close();
Igor Murashkina296fec2014-06-23 14:44:09 -0700416 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700417 }
418
419 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800420 public SubmitInfo submitRequest(CaptureRequest request, boolean streaming) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700421 if (DEBUG) {
422 Log.d(TAG, "submitRequest called.");
423 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700424 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800425 String err = "Cannot submit request, device has been closed.";
426 Log.e(TAG, err);
427 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700428 }
429
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700430 synchronized(mConfigureLock) {
431 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800432 String err = "Cannot submit request, configuration change in progress.";
433 Log.e(TAG, err);
434 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700435 }
436 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800437 return mLegacyDevice.submitRequest(request, streaming);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700438 }
439
440 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800441 public SubmitInfo submitRequestList(CaptureRequest[] request, boolean streaming) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700442 if (DEBUG) {
443 Log.d(TAG, "submitRequestList called.");
444 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700445 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800446 String err = "Cannot submit request list, device has been closed.";
447 Log.e(TAG, err);
448 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700449 }
450
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700451 synchronized(mConfigureLock) {
452 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800453 String err = "Cannot submit request, configuration change in progress.";
454 Log.e(TAG, err);
455 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700456 }
457 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800458 return mLegacyDevice.submitRequestList(request, streaming);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700459 }
460
461 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800462 public long cancelRequest(int requestId) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700463 if (DEBUG) {
464 Log.d(TAG, "cancelRequest called.");
465 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700466 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800467 String err = "Cannot cancel request, device has been closed.";
468 Log.e(TAG, err);
469 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700470 }
471
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700472 synchronized(mConfigureLock) {
473 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800474 String err = "Cannot cancel request, configuration change in progress.";
475 Log.e(TAG, err);
476 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700477 }
478 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800479 return mLegacyDevice.cancelRequest(requestId);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700480 }
481
482 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800483 public void beginConfigure() {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700484 if (DEBUG) {
485 Log.d(TAG, "beginConfigure called.");
486 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700487 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800488 String err = "Cannot begin configure, device has been closed.";
489 Log.e(TAG, err);
490 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700491 }
492
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700493 synchronized(mConfigureLock) {
494 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800495 String err = "Cannot begin configure, configuration change already in progress.";
496 Log.e(TAG, err);
497 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700498 }
499 mConfiguring = true;
500 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700501 }
502
503 @Override
Emilian Peev75a55702017-11-07 16:09:59 +0000504 public void endConfigure(int operatingMode, CameraMetadataNative sessionParams) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700505 if (DEBUG) {
506 Log.d(TAG, "endConfigure called.");
507 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700508 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800509 String err = "Cannot end configure, device has been closed.";
510 Log.e(TAG, err);
Yin-Chia Yehdaf20732017-08-10 15:41:50 -0700511 synchronized(mConfigureLock) {
512 mConfiguring = false;
513 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800514 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700515 }
516
Eino-Ville Talvala0e04e912017-02-28 17:49:41 -0800517 if (operatingMode != ICameraDeviceUser.NORMAL_MODE) {
518 String err = "LEGACY devices do not support this operating mode";
519 Log.e(TAG, err);
Yin-Chia Yehdaf20732017-08-10 15:41:50 -0700520 synchronized(mConfigureLock) {
521 mConfiguring = false;
522 }
Eino-Ville Talvala0e04e912017-02-28 17:49:41 -0800523 throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
524 }
525
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700526 SparseArray<Surface> surfaces = null;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700527 synchronized(mConfigureLock) {
528 if (!mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800529 String err = "Cannot end configure, no configuration change in progress.";
530 Log.e(TAG, err);
531 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700532 }
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700533 if (mSurfaces != null) {
534 surfaces = mSurfaces.clone();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700535 }
536 mConfiguring = false;
537 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800538 mLegacyDevice.configureOutputs(surfaces);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700539 }
540
541 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800542 public void deleteStream(int streamId) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700543 if (DEBUG) {
544 Log.d(TAG, "deleteStream called.");
545 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700546 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800547 String err = "Cannot delete stream, device has been closed.";
548 Log.e(TAG, err);
549 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700550 }
551
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700552 synchronized(mConfigureLock) {
553 if (!mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800554 String err = "Cannot delete stream, no configuration change in progress.";
555 Log.e(TAG, err);
556 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700557 }
558 int index = mSurfaces.indexOfKey(streamId);
559 if (index < 0) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800560 String err = "Cannot delete stream, stream id " + streamId + " doesn't exist.";
561 Log.e(TAG, err);
562 throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700563 }
564 mSurfaces.removeAt(index);
565 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700566 }
567
568 @Override
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700569 public int createStream(OutputConfiguration outputConfiguration) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700570 if (DEBUG) {
571 Log.d(TAG, "createStream called.");
572 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700573 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800574 String err = "Cannot create stream, device has been closed.";
575 Log.e(TAG, err);
576 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700577 }
578
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700579 synchronized(mConfigureLock) {
580 if (!mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800581 String err = "Cannot create stream, beginConfigure hasn't been called yet.";
582 Log.e(TAG, err);
583 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700584 }
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700585 if (outputConfiguration.getRotation() != OutputConfiguration.ROTATION_0) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800586 String err = "Cannot create stream, stream rotation is not supported.";
587 Log.e(TAG, err);
588 throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700589 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700590 int id = ++mSurfaceIdCounter;
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700591 mSurfaces.put(id, outputConfiguration.getSurface());
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700592 return id;
593 }
594 }
595
596 @Override
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800597 public void finalizeOutputConfigurations(int steamId, OutputConfiguration config) {
598 String err = "Finalizing output configuration is not supported on legacy devices";
Zhijun Hec8b181e2016-05-30 14:54:39 -0700599 Log.e(TAG, err);
600 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
601 }
602
603 @Override
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700604 public int createInputStream(int width, int height, int format) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800605 String err = "Creating input stream is not supported on legacy devices";
606 Log.e(TAG, err);
607 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700608 }
609
610 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800611 public Surface getInputSurface() {
612 String err = "Getting input surface is not supported on legacy devices";
613 Log.e(TAG, err);
614 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700615 }
616
617 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800618 public CameraMetadataNative createDefaultRequest(int templateId) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700619 if (DEBUG) {
620 Log.d(TAG, "createDefaultRequest called.");
621 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700622 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800623 String err = "Cannot create default request, device has been closed.";
624 Log.e(TAG, err);
625 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700626 }
Igor Murashkina296fec2014-06-23 14:44:09 -0700627
628 CameraMetadataNative template;
629 try {
630 template =
631 LegacyMetadataMapper.createRequestTemplate(mCameraCharacteristics, templateId);
632 } catch (IllegalArgumentException e) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800633 String err = "createDefaultRequest - invalid templateId specified";
634 Log.e(TAG, err);
635 throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
Igor Murashkina296fec2014-06-23 14:44:09 -0700636 }
637
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800638 return template;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700639 }
640
641 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800642 public CameraMetadataNative getCameraInfo() {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700643 if (DEBUG) {
644 Log.d(TAG, "getCameraInfo called.");
645 }
646 // TODO: implement getCameraInfo.
647 Log.e(TAG, "getCameraInfo unimplemented.");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800648 return null;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700649 }
650
651 @Override
Emilian Peev03233152017-10-27 16:01:20 +0100652 public void updateOutputConfiguration(int streamId, OutputConfiguration config) {
653 // TODO: b/63912484 implement updateOutputConfiguration.
654 }
655
656 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800657 public void waitUntilIdle() throws RemoteException {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700658 if (DEBUG) {
659 Log.d(TAG, "waitUntilIdle called.");
660 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700661 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800662 String err = "Cannot wait until idle, device has been closed.";
663 Log.e(TAG, err);
664 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700665 }
666
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700667 synchronized(mConfigureLock) {
668 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800669 String err = "Cannot wait until idle, configuration change in progress.";
670 Log.e(TAG, err);
671 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700672 }
673 }
674 mLegacyDevice.waitUntilIdle();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700675 }
676
677 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800678 public long flush() {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700679 if (DEBUG) {
680 Log.d(TAG, "flush called.");
681 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700682 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800683 String err = "Cannot flush, device has been closed.";
684 Log.e(TAG, err);
685 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700686 }
687
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700688 synchronized(mConfigureLock) {
689 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800690 String err = "Cannot flush, configuration change in progress.";
691 Log.e(TAG, err);
692 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700693 }
694 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800695 return mLegacyDevice.flush();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700696 }
697
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800698 public void prepare(int streamId) {
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700699 if (DEBUG) {
700 Log.d(TAG, "prepare called.");
701 }
702 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800703 String err = "Cannot prepare stream, device has been closed.";
704 Log.e(TAG, err);
705 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700706 }
707
Eino-Ville Talvalabe6d9852015-04-29 11:37:00 -0700708 // LEGACY doesn't support actual prepare, just signal success right away
709 mCameraCallbacks.onPrepared(streamId);
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700710 }
711
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800712 public void prepare2(int maxCount, int streamId) {
Ruben Brunk7ed1aaa2015-08-13 17:57:14 -0700713 // We don't support this in LEGACY mode.
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800714 prepare(streamId);
Ruben Brunk7ed1aaa2015-08-13 17:57:14 -0700715 }
716
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800717 public void tearDown(int streamId) {
Eino-Ville Talvala14c09fa2015-07-15 16:04:04 -0700718 if (DEBUG) {
719 Log.d(TAG, "tearDown called.");
720 }
721 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800722 String err = "Cannot tear down stream, device has been closed.";
723 Log.e(TAG, err);
724 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Eino-Ville Talvala14c09fa2015-07-15 16:04:04 -0700725 }
726
727 // LEGACY doesn't support actual teardown, so just a no-op
Eino-Ville Talvala14c09fa2015-07-15 16:04:04 -0700728 }
729
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700730 @Override
731 public IBinder asBinder() {
732 // This is solely intended to be used for in-process binding.
733 return null;
734 }
735}