blob: f87d8c1401c530b147fdec351703424e74cd51b3 [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;
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700208 private static final int REPEATING_REQUEST_ERROR = 5;
Shuzhen Wang88f1af22016-09-30 10:29:28 -0700209 private static final int REQUEST_QUEUE_EMPTY = 6;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700210
211 private final HandlerThread mHandlerThread;
212 private Handler mHandler;
213
214 private final ICameraDeviceCallbacks mCallbacks;
215
216 public CameraCallbackThread(ICameraDeviceCallbacks callbacks) {
217 mCallbacks = callbacks;
218
219 mHandlerThread = new HandlerThread("LegacyCameraCallback");
220 mHandlerThread.start();
221 }
222
223 public void close() {
224 mHandlerThread.quitSafely();
225 }
226
227 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700228 public void onDeviceError(final int errorCode, final CaptureResultExtras resultExtras) {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700229 Message msg = getHandler().obtainMessage(CAMERA_ERROR,
230 /*arg1*/ errorCode, /*arg2*/ 0,
231 /*obj*/ resultExtras);
232 getHandler().sendMessage(msg);
233 }
234
235 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700236 public void onDeviceIdle() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700237 Message msg = getHandler().obtainMessage(CAMERA_IDLE);
238 getHandler().sendMessage(msg);
239 }
240
241 @Override
242 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
243 Message msg = getHandler().obtainMessage(CAPTURE_STARTED,
244 /*arg1*/ (int) (timestamp & 0xFFFFFFFFL),
245 /*arg2*/ (int) ( (timestamp >> 32) & 0xFFFFFFFFL),
246 /*obj*/ resultExtras);
247 getHandler().sendMessage(msg);
248 }
249
250 @Override
251 public void onResultReceived(final CameraMetadataNative result,
252 final CaptureResultExtras resultExtras) {
253 Object[] resultArray = new Object[] { result, resultExtras };
254 Message msg = getHandler().obtainMessage(RESULT_RECEIVED,
255 /*obj*/ resultArray);
256 getHandler().sendMessage(msg);
257 }
258
259 @Override
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700260 public void onPrepared(int streamId) {
Eino-Ville Talvalabe6d9852015-04-29 11:37:00 -0700261 Message msg = getHandler().obtainMessage(PREPARED,
262 /*arg1*/ streamId, /*arg2*/ 0);
263 getHandler().sendMessage(msg);
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700264 }
265
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700266 @Override
267 public void onRepeatingRequestError(long lastFrameNumber) {
268 Message msg = getHandler().obtainMessage(REPEATING_REQUEST_ERROR,
269 /*arg1*/ (int) (lastFrameNumber & 0xFFFFFFFFL),
270 /*arg2*/ (int) ( (lastFrameNumber >> 32) & 0xFFFFFFFFL));
271 getHandler().sendMessage(msg);
272 }
273
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700274 @Override
Shuzhen Wang88f1af22016-09-30 10:29:28 -0700275 public void onRequestQueueEmpty() {
276 Message msg = getHandler().obtainMessage(REQUEST_QUEUE_EMPTY,
277 /* arg1 */ 0, /* arg2 */ 0);
278 getHandler().sendMessage(msg);
279 }
280
281 @Override
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700282 public IBinder asBinder() {
283 // This is solely intended to be used for in-process binding.
284 return null;
285 }
286
287 private Handler getHandler() {
288 if (mHandler == null) {
289 mHandler = new CallbackHandler(mHandlerThread.getLooper());
290 }
291 return mHandler;
292 }
293
294 private class CallbackHandler extends Handler {
295 public CallbackHandler(Looper l) {
296 super(l);
297 }
298
Igor Murashkin66533622014-08-19 14:51:47 -0700299 @Override
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700300 public void handleMessage(Message msg) {
301 try {
302 switch (msg.what) {
303 case CAMERA_ERROR: {
304 int errorCode = msg.arg1;
305 CaptureResultExtras resultExtras = (CaptureResultExtras) msg.obj;
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700306 mCallbacks.onDeviceError(errorCode, resultExtras);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700307 break;
308 }
309 case CAMERA_IDLE:
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700310 mCallbacks.onDeviceIdle();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700311 break;
312 case CAPTURE_STARTED: {
313 long timestamp = msg.arg2 & 0xFFFFFFFFL;
314 timestamp = (timestamp << 32) | (msg.arg1 & 0xFFFFFFFFL);
315 CaptureResultExtras resultExtras = (CaptureResultExtras) msg.obj;
316 mCallbacks.onCaptureStarted(resultExtras, timestamp);
317 break;
318 }
319 case RESULT_RECEIVED: {
320 Object[] resultArray = (Object[]) msg.obj;
321 CameraMetadataNative result = (CameraMetadataNative) resultArray[0];
322 CaptureResultExtras resultExtras = (CaptureResultExtras) resultArray[1];
323 mCallbacks.onResultReceived(result, resultExtras);
324 break;
325 }
Eino-Ville Talvalabe6d9852015-04-29 11:37:00 -0700326 case PREPARED: {
327 int streamId = msg.arg1;
328 mCallbacks.onPrepared(streamId);
329 break;
330 }
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700331 case REPEATING_REQUEST_ERROR: {
332 long lastFrameNumber = msg.arg2 & 0xFFFFFFFFL;
333 lastFrameNumber = (lastFrameNumber << 32) | (msg.arg1 & 0xFFFFFFFFL);
334 mCallbacks.onRepeatingRequestError(lastFrameNumber);
335 break;
336 }
Shuzhen Wang88f1af22016-09-30 10:29:28 -0700337 case REQUEST_QUEUE_EMPTY: {
338 mCallbacks.onRequestQueueEmpty();
339 break;
340 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700341 default:
342 throw new IllegalArgumentException(
343 "Unknown callback message " + msg.what);
344 }
345 } catch (RemoteException e) {
346 throw new IllegalStateException(
347 "Received remote exception during camera callback " + msg.what, e);
348 }
349 }
350 }
351 }
352
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700353 public static CameraDeviceUserShim connectBinderShim(ICameraDeviceCallbacks callbacks,
354 int cameraId) {
355 if (DEBUG) {
356 Log.d(TAG, "Opening shim Camera device");
357 }
Igor Murashkina296fec2014-06-23 14:44:09 -0700358
359 /*
360 * Put the camera open on a separate thread with its own looper; otherwise
361 * if the main thread is used then the callbacks might never get delivered
362 * (e.g. in CTS which run its own default looper only after tests)
363 */
364
365 CameraLooper init = new CameraLooper(cameraId);
366
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700367 CameraCallbackThread threadCallbacks = new CameraCallbackThread(callbacks);
368
Igor Murashkina296fec2014-06-23 14:44:09 -0700369 // TODO: Make this async instead of blocking
370 int initErrors = init.waitForOpen(OPEN_CAMERA_TIMEOUT_MS);
371 Camera legacyCamera = init.getCamera();
Igor Murashkina1d66272014-06-20 11:22:11 -0700372
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700373 // Check errors old HAL initialization
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800374 LegacyExceptionUtils.throwOnServiceError(initErrors);
Igor Murashkina1d66272014-06-20 11:22:11 -0700375
Igor Murashkin66533622014-08-19 14:51:47 -0700376 // Disable shutter sounds (this will work unconditionally) for api2 clients
377 legacyCamera.disableShutterSound();
378
Igor Murashkina296fec2014-06-23 14:44:09 -0700379 CameraInfo info = new CameraInfo();
380 Camera.getCameraInfo(cameraId, info);
381
Eino-Ville Talvalaeecc9042014-09-23 16:37:31 -0700382 Camera.Parameters legacyParameters = null;
383 try {
384 legacyParameters = legacyCamera.getParameters();
385 } catch (RuntimeException e) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800386 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION,
387 "Unable to get initial parameters: " + e.getMessage());
Eino-Ville Talvalaeecc9042014-09-23 16:37:31 -0700388 }
389
Igor Murashkina296fec2014-06-23 14:44:09 -0700390 CameraCharacteristics characteristics =
Eino-Ville Talvalaeecc9042014-09-23 16:37:31 -0700391 LegacyMetadataMapper.createCharacteristics(legacyParameters, info);
Igor Murashkindf6242e2014-07-01 18:06:13 -0700392 LegacyCameraDevice device = new LegacyCameraDevice(
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700393 cameraId, legacyCamera, characteristics, threadCallbacks);
394 return new CameraDeviceUserShim(cameraId, device, characteristics, init, threadCallbacks);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700395 }
396
397 @Override
398 public void disconnect() {
399 if (DEBUG) {
400 Log.d(TAG, "disconnect called.");
401 }
Igor Murashkina296fec2014-06-23 14:44:09 -0700402
Ruben Brunke663cb772014-09-16 13:18:31 -0700403 if (mLegacyDevice.isClosed()) {
404 Log.w(TAG, "Cannot disconnect, device has already been closed.");
405 }
406
Igor Murashkina296fec2014-06-23 14:44:09 -0700407 try {
408 mLegacyDevice.close();
409 } finally {
410 mCameraInit.close();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700411 mCameraCallbacks.close();
Igor Murashkina296fec2014-06-23 14:44:09 -0700412 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700413 }
414
415 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800416 public SubmitInfo submitRequest(CaptureRequest request, boolean streaming) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700417 if (DEBUG) {
418 Log.d(TAG, "submitRequest called.");
419 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700420 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800421 String err = "Cannot submit request, device has been closed.";
422 Log.e(TAG, err);
423 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700424 }
425
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700426 synchronized(mConfigureLock) {
427 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800428 String err = "Cannot submit request, configuration change in progress.";
429 Log.e(TAG, err);
430 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700431 }
432 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800433 return mLegacyDevice.submitRequest(request, streaming);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700434 }
435
436 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800437 public SubmitInfo submitRequestList(CaptureRequest[] request, boolean streaming) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700438 if (DEBUG) {
439 Log.d(TAG, "submitRequestList called.");
440 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700441 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800442 String err = "Cannot submit request list, device has been closed.";
443 Log.e(TAG, err);
444 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700445 }
446
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700447 synchronized(mConfigureLock) {
448 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800449 String err = "Cannot submit request, configuration change in progress.";
450 Log.e(TAG, err);
451 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700452 }
453 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800454 return mLegacyDevice.submitRequestList(request, streaming);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700455 }
456
457 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800458 public long cancelRequest(int requestId) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700459 if (DEBUG) {
460 Log.d(TAG, "cancelRequest called.");
461 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700462 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800463 String err = "Cannot cancel request, device has been closed.";
464 Log.e(TAG, err);
465 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700466 }
467
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700468 synchronized(mConfigureLock) {
469 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800470 String err = "Cannot cancel request, configuration change in progress.";
471 Log.e(TAG, err);
472 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700473 }
474 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800475 return mLegacyDevice.cancelRequest(requestId);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700476 }
477
478 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800479 public void beginConfigure() {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700480 if (DEBUG) {
481 Log.d(TAG, "beginConfigure called.");
482 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700483 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800484 String err = "Cannot begin configure, device has been closed.";
485 Log.e(TAG, err);
486 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700487 }
488
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700489 synchronized(mConfigureLock) {
490 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800491 String err = "Cannot begin configure, configuration change already in progress.";
492 Log.e(TAG, err);
493 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700494 }
495 mConfiguring = true;
496 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700497 }
498
499 @Override
Eino-Ville Talvala0e04e912017-02-28 17:49:41 -0800500 public void endConfigure(int operatingMode) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700501 if (DEBUG) {
502 Log.d(TAG, "endConfigure called.");
503 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700504 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800505 String err = "Cannot end configure, device has been closed.";
506 Log.e(TAG, err);
507 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700508 }
509
Eino-Ville Talvala0e04e912017-02-28 17:49:41 -0800510 if (operatingMode != ICameraDeviceUser.NORMAL_MODE) {
511 String err = "LEGACY devices do not support this operating mode";
512 Log.e(TAG, err);
513 throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
514 }
515
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700516 SparseArray<Surface> surfaces = null;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700517 synchronized(mConfigureLock) {
518 if (!mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800519 String err = "Cannot end configure, no configuration change in progress.";
520 Log.e(TAG, err);
521 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700522 }
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700523 if (mSurfaces != null) {
524 surfaces = mSurfaces.clone();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700525 }
526 mConfiguring = false;
527 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800528 mLegacyDevice.configureOutputs(surfaces);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700529 }
530
531 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800532 public void deleteStream(int streamId) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700533 if (DEBUG) {
534 Log.d(TAG, "deleteStream called.");
535 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700536 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800537 String err = "Cannot delete stream, device has been closed.";
538 Log.e(TAG, err);
539 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700540 }
541
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700542 synchronized(mConfigureLock) {
543 if (!mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800544 String err = "Cannot delete stream, no configuration change in progress.";
545 Log.e(TAG, err);
546 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700547 }
548 int index = mSurfaces.indexOfKey(streamId);
549 if (index < 0) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800550 String err = "Cannot delete stream, stream id " + streamId + " doesn't exist.";
551 Log.e(TAG, err);
552 throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700553 }
554 mSurfaces.removeAt(index);
555 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700556 }
557
558 @Override
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700559 public int createStream(OutputConfiguration outputConfiguration) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700560 if (DEBUG) {
561 Log.d(TAG, "createStream called.");
562 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700563 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800564 String err = "Cannot create stream, device has been closed.";
565 Log.e(TAG, err);
566 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700567 }
568
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700569 synchronized(mConfigureLock) {
570 if (!mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800571 String err = "Cannot create stream, beginConfigure hasn't been called yet.";
572 Log.e(TAG, err);
573 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700574 }
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700575 if (outputConfiguration.getRotation() != OutputConfiguration.ROTATION_0) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800576 String err = "Cannot create stream, stream rotation is not supported.";
577 Log.e(TAG, err);
578 throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700579 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700580 int id = ++mSurfaceIdCounter;
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700581 mSurfaces.put(id, outputConfiguration.getSurface());
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700582 return id;
583 }
584 }
585
586 @Override
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800587 public void finalizeOutputConfigurations(int steamId, OutputConfiguration config) {
588 String err = "Finalizing output configuration is not supported on legacy devices";
Zhijun Hec8b181e2016-05-30 14:54:39 -0700589 Log.e(TAG, err);
590 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
591 }
592
593 @Override
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700594 public int createInputStream(int width, int height, int format) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800595 String err = "Creating input stream is not supported on legacy devices";
596 Log.e(TAG, err);
597 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700598 }
599
600 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800601 public Surface getInputSurface() {
602 String err = "Getting input surface is not supported on legacy devices";
603 Log.e(TAG, err);
604 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700605 }
606
607 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800608 public CameraMetadataNative createDefaultRequest(int templateId) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700609 if (DEBUG) {
610 Log.d(TAG, "createDefaultRequest called.");
611 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700612 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800613 String err = "Cannot create default request, device has been closed.";
614 Log.e(TAG, err);
615 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700616 }
Igor Murashkina296fec2014-06-23 14:44:09 -0700617
618 CameraMetadataNative template;
619 try {
620 template =
621 LegacyMetadataMapper.createRequestTemplate(mCameraCharacteristics, templateId);
622 } catch (IllegalArgumentException e) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800623 String err = "createDefaultRequest - invalid templateId specified";
624 Log.e(TAG, err);
625 throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
Igor Murashkina296fec2014-06-23 14:44:09 -0700626 }
627
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800628 return template;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700629 }
630
631 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800632 public CameraMetadataNative getCameraInfo() {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700633 if (DEBUG) {
634 Log.d(TAG, "getCameraInfo called.");
635 }
636 // TODO: implement getCameraInfo.
637 Log.e(TAG, "getCameraInfo unimplemented.");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800638 return null;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700639 }
640
641 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800642 public void waitUntilIdle() throws RemoteException {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700643 if (DEBUG) {
644 Log.d(TAG, "waitUntilIdle called.");
645 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700646 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800647 String err = "Cannot wait until idle, device has been closed.";
648 Log.e(TAG, err);
649 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700650 }
651
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700652 synchronized(mConfigureLock) {
653 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800654 String err = "Cannot wait until idle, configuration change in progress.";
655 Log.e(TAG, err);
656 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700657 }
658 }
659 mLegacyDevice.waitUntilIdle();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700660 }
661
662 @Override
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800663 public long flush() {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700664 if (DEBUG) {
665 Log.d(TAG, "flush called.");
666 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700667 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800668 String err = "Cannot flush, device has been closed.";
669 Log.e(TAG, err);
670 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Ruben Brunke663cb772014-09-16 13:18:31 -0700671 }
672
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700673 synchronized(mConfigureLock) {
674 if (mConfiguring) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800675 String err = "Cannot flush, configuration change in progress.";
676 Log.e(TAG, err);
677 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700678 }
679 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800680 return mLegacyDevice.flush();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700681 }
682
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800683 public void prepare(int streamId) {
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700684 if (DEBUG) {
685 Log.d(TAG, "prepare called.");
686 }
687 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800688 String err = "Cannot prepare stream, device has been closed.";
689 Log.e(TAG, err);
690 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700691 }
692
Eino-Ville Talvalabe6d9852015-04-29 11:37:00 -0700693 // LEGACY doesn't support actual prepare, just signal success right away
694 mCameraCallbacks.onPrepared(streamId);
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700695 }
696
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800697 public void prepare2(int maxCount, int streamId) {
Ruben Brunk7ed1aaa2015-08-13 17:57:14 -0700698 // We don't support this in LEGACY mode.
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800699 prepare(streamId);
Ruben Brunk7ed1aaa2015-08-13 17:57:14 -0700700 }
701
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800702 public void tearDown(int streamId) {
Eino-Ville Talvala14c09fa2015-07-15 16:04:04 -0700703 if (DEBUG) {
704 Log.d(TAG, "tearDown called.");
705 }
706 if (mLegacyDevice.isClosed()) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800707 String err = "Cannot tear down stream, device has been closed.";
708 Log.e(TAG, err);
709 throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
Eino-Ville Talvala14c09fa2015-07-15 16:04:04 -0700710 }
711
712 // LEGACY doesn't support actual teardown, so just a no-op
Eino-Ville Talvala14c09fa2015-07-15 16:04:04 -0700713 }
714
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700715 @Override
716 public IBinder asBinder() {
717 // This is solely intended to be used for in-process binding.
718 return null;
719 }
720}