blob: 536c2e13389b55fe7897b3547cfe2fddc9442d5e [file] [log] [blame]
Eino-Ville Talvalab2675542012-12-12 13:29:45 -08001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070017package android.hardware.camera2;
Eino-Ville Talvalab2675542012-12-12 13:29:45 -080018
Emilian Peev9129aa22018-03-20 15:39:34 +000019import android.annotation.CallbackExecutor;
Eino-Ville Talvala8b905572015-05-14 15:43:01 -070020import android.annotation.NonNull;
21import android.annotation.Nullable;
Eino-Ville Talvala19d96a12017-07-13 12:07:20 -070022import android.annotation.RequiresPermission;
23import android.annotation.SystemService;
Igor Murashkine363fbb2013-06-25 20:26:06 +000024import android.content.Context;
Igor Murashkin4961bc82014-06-17 12:04:07 -070025import android.hardware.CameraInfo;
Eino-Ville Talvala283ae234f2016-12-08 13:38:52 -080026import android.hardware.CameraStatus;
Eino-Ville Talvala19d96a12017-07-13 12:07:20 -070027import android.hardware.ICameraService;
28import android.hardware.ICameraServiceListener;
Emilian Peev9a0ec8c2018-02-28 14:53:30 +000029import android.hardware.camera2.impl.CameraDeviceImpl;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070030import android.hardware.camera2.impl.CameraMetadataNative;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070031import android.hardware.camera2.legacy.CameraDeviceUserShim;
Igor Murashkin4961bc82014-06-17 12:04:07 -070032import android.hardware.camera2.legacy.LegacyMetadataMapper;
Chien-Yu Chenafa91392015-02-11 11:23:28 -080033import android.os.Binder;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080034import android.os.DeadObjectException;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070035import android.os.Handler;
Eino-Ville Talvala19d96a12017-07-13 12:07:20 -070036import android.os.IBinder;
Igor Murashkine363fbb2013-06-25 20:26:06 +000037import android.os.RemoteException;
38import android.os.ServiceManager;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080039import android.os.ServiceSpecificException;
Eino-Ville Talvala19d96a12017-07-13 12:07:20 -070040import android.os.SystemProperties;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070041import android.util.ArrayMap;
Eino-Ville Talvala19d96a12017-07-13 12:07:20 -070042import android.util.Log;
Emilian Peev423cbd72018-11-10 18:37:45 +000043import android.util.Size;
44import android.view.Display;
45import android.view.WindowManager;
Igor Murashkine363fbb2013-06-25 20:26:06 +000046
47import java.util.ArrayList;
Yin-Chia Yehf8aa7bc2018-03-09 15:48:16 -080048import java.util.Arrays;
49import java.util.Comparator;
Emilian Peev9a0ec8c2018-02-28 14:53:30 +000050import java.util.concurrent.Executor;
51import java.util.concurrent.Executors;
52import java.util.concurrent.RejectedExecutionException;
53import java.util.concurrent.ScheduledExecutorService;
54import java.util.concurrent.TimeUnit;
Igor Murashkine363fbb2013-06-25 20:26:06 +000055
Eino-Ville Talvalab2675542012-12-12 13:29:45 -080056/**
Eino-Ville Talvalab67a3b32014-06-06 13:07:20 -070057 * <p>A system service manager for detecting, characterizing, and connecting to
Eino-Ville Talvalab2675542012-12-12 13:29:45 -080058 * {@link CameraDevice CameraDevices}.</p>
59 *
Eino-Ville Talvalab2675542012-12-12 13:29:45 -080060 * <p>For more details about communicating with camera devices, read the Camera
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070061 * developer guide or the {@link android.hardware.camera2 camera2}
Eino-Ville Talvalab2675542012-12-12 13:29:45 -080062 * package documentation.</p>
63 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060064@SystemService(Context.CAMERA_SERVICE)
Eino-Ville Talvalab2675542012-12-12 13:29:45 -080065public final class CameraManager {
66
Ruben Brunk85c43882014-02-21 17:40:51 -080067 private static final String TAG = "CameraManager";
Eino-Ville Talvalaa78791f2015-06-01 12:39:54 -070068 private final boolean DEBUG = false;
Ruben Brunk85c43882014-02-21 17:40:51 -080069
Igor Murashkine363fbb2013-06-25 20:26:06 +000070 private static final int USE_CALLING_UID = -1;
71
Igor Murashkin4961bc82014-06-17 12:04:07 -070072 @SuppressWarnings("unused")
73 private static final int API_VERSION_1 = 1;
74 private static final int API_VERSION_2 = 2;
75
Eino-Ville Talvala57176122015-08-14 13:11:16 -070076 private static final int CAMERA_TYPE_BACKWARD_COMPATIBLE = 0;
77 private static final int CAMERA_TYPE_ALL = 1;
78
Igor Murashkine363fbb2013-06-25 20:26:06 +000079 private ArrayList<String> mDeviceIdList;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070080
Igor Murashkine363fbb2013-06-25 20:26:06 +000081 private final Context mContext;
82 private final Object mLock = new Object();
83
84 /**
Eino-Ville Talvalab2675542012-12-12 13:29:45 -080085 * @hide
86 */
Igor Murashkine363fbb2013-06-25 20:26:06 +000087 public CameraManager(Context context) {
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -070088 synchronized(mLock) {
89 mContext = context;
Igor Murashkine363fbb2013-06-25 20:26:06 +000090 }
Eino-Ville Talvalab2675542012-12-12 13:29:45 -080091 }
92
93 /**
Ruben Brunk0f2be132015-04-17 14:23:40 -070094 * Return the list of currently connected camera devices by identifier, including
95 * cameras that may be in use by other camera API clients.
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070096 *
97 * <p>Non-removable cameras use integers starting at 0 for their
Eino-Ville Talvalab2675542012-12-12 13:29:45 -080098 * identifiers, while removable cameras have a unique identifier for each
99 * individual device, even if they are the same model.</p>
100 *
Shuzhen Wang123deefc2018-08-20 12:00:05 -0700101 * <p>This list doesn't contain physical cameras that can only used as part of a logical
102 * multi-camera device.</p>
103 *
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800104 * @return The list of currently connected camera devices.
105 */
Eino-Ville Talvala8b905572015-05-14 15:43:01 -0700106 @NonNull
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700107 public String[] getCameraIdList() throws CameraAccessException {
Eino-Ville Talvala283ae234f2016-12-08 13:38:52 -0800108 return CameraManagerGlobal.get().getCameraIdList();
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800109 }
110
111 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700112 * Register a callback to be notified about camera device availability.
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800113 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700114 * <p>Registering the same callback again will replace the handler with the
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700115 * new one provided.</p>
Igor Murashkine363fbb2013-06-25 20:26:06 +0000116 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700117 * <p>The first time a callback is registered, it is immediately called
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700118 * with the availability status of all currently known camera devices.</p>
119 *
Ruben Brunk0f2be132015-04-17 14:23:40 -0700120 * <p>{@link AvailabilityCallback#onCameraUnavailable(String)} will be called whenever a camera
121 * device is opened by any camera API client. As of API level 23, other camera API clients may
122 * still be able to open such a camera device, evicting the existing client if they have higher
123 * priority than the existing client of a camera device. See open() for more details.</p>
124 *
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700125 * <p>Since this callback will be registered with the camera service, remember to unregister it
126 * once it is no longer needed; otherwise the callback will continue to receive events
127 * indefinitely and it may prevent other resources from being released. Specifically, the
128 * callbacks will be invoked independently of the general activity lifecycle and independently
129 * of the state of individual CameraManager instances.</p>
130 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700131 * @param callback the new callback to send camera availability notices to
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800132 * @param handler The handler on which the callback should be invoked, or {@code null} to use
133 * the current thread's {@link android.os.Looper looper}.
134 *
135 * @throws IllegalArgumentException if the handler is {@code null} but the current thread has
136 * no looper.
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800137 */
Eino-Ville Talvala8b905572015-05-14 15:43:01 -0700138 public void registerAvailabilityCallback(@NonNull AvailabilityCallback callback,
139 @Nullable Handler handler) {
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000140 CameraManagerGlobal.get().registerAvailabilityCallback(callback,
141 CameraDeviceImpl.checkAndWrapHandler(handler));
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800142 }
143
144 /**
Emilian Peev9129aa22018-03-20 15:39:34 +0000145 * Register a callback to be notified about camera device availability.
146 *
147 * <p>The behavior of this method matches that of
148 * {@link #registerAvailabilityCallback(AvailabilityCallback, Handler)},
149 * except that it uses {@link java.util.concurrent.Executor} as an argument
150 * instead of {@link android.os.Handler}.</p>
151 *
152 * @param executor The executor which will be used to invoke the callback.
153 * @param callback the new callback to send camera availability notices to
154 *
155 * @throws IllegalArgumentException if the executor is {@code null}.
156 */
157 public void registerAvailabilityCallback(@NonNull @CallbackExecutor Executor executor,
158 @NonNull AvailabilityCallback callback) {
159 if (executor == null) {
160 throw new IllegalArgumentException("executor was null");
161 }
162 CameraManagerGlobal.get().registerAvailabilityCallback(callback, executor);
163 }
164
165 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700166 * Remove a previously-added callback; the callback will no longer receive connection and
167 * disconnection callbacks.
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800168 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700169 * <p>Removing a callback that isn't registered has no effect.</p>
Igor Murashkine363fbb2013-06-25 20:26:06 +0000170 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700171 * @param callback The callback to remove from the notification list
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800172 */
Eino-Ville Talvala8b905572015-05-14 15:43:01 -0700173 public void unregisterAvailabilityCallback(@NonNull AvailabilityCallback callback) {
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700174 CameraManagerGlobal.get().unregisterAvailabilityCallback(callback);
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800175 }
176
177 /**
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800178 * Register a callback to be notified about torch mode status.
179 *
180 * <p>Registering the same callback again will replace the handler with the
181 * new one provided.</p>
182 *
183 * <p>The first time a callback is registered, it is immediately called
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700184 * with the torch mode status of all currently known camera devices with a flash unit.</p>
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800185 *
186 * <p>Since this callback will be registered with the camera service, remember to unregister it
187 * once it is no longer needed; otherwise the callback will continue to receive events
188 * indefinitely and it may prevent other resources from being released. Specifically, the
189 * callbacks will be invoked independently of the general activity lifecycle and independently
190 * of the state of individual CameraManager instances.</p>
191 *
192 * @param callback The new callback to send torch mode status to
193 * @param handler The handler on which the callback should be invoked, or {@code null} to use
194 * the current thread's {@link android.os.Looper looper}.
195 *
196 * @throws IllegalArgumentException if the handler is {@code null} but the current thread has
197 * no looper.
198 */
Eino-Ville Talvala8b905572015-05-14 15:43:01 -0700199 public void registerTorchCallback(@NonNull TorchCallback callback, @Nullable Handler handler) {
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000200 CameraManagerGlobal.get().registerTorchCallback(callback,
201 CameraDeviceImpl.checkAndWrapHandler(handler));
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800202 }
203
204 /**
Emilian Peev9129aa22018-03-20 15:39:34 +0000205 * Register a callback to be notified about torch mode status.
206 *
207 * <p>The behavior of this method matches that of
208 * {@link #registerTorchCallback(TorchCallback, Handler)},
209 * except that it uses {@link java.util.concurrent.Executor} as an argument
210 * instead of {@link android.os.Handler}.</p>
211 *
212 * @param executor The executor which will be used to invoke the callback
213 * @param callback The new callback to send torch mode status to
214 *
215 * @throws IllegalArgumentException if the executor is {@code null}.
216 */
217 public void registerTorchCallback(@NonNull @CallbackExecutor Executor executor,
218 @NonNull TorchCallback callback) {
219 if (executor == null) {
220 throw new IllegalArgumentException("executor was null");
221 }
222 CameraManagerGlobal.get().registerTorchCallback(callback, executor);
223 }
224
225 /**
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800226 * Remove a previously-added callback; the callback will no longer receive torch mode status
227 * callbacks.
228 *
229 * <p>Removing a callback that isn't registered has no effect.</p>
230 *
231 * @param callback The callback to remove from the notification list
232 */
Eino-Ville Talvala8b905572015-05-14 15:43:01 -0700233 public void unregisterTorchCallback(@NonNull TorchCallback callback) {
Chien-Yu Chenafa91392015-02-11 11:23:28 -0800234 CameraManagerGlobal.get().unregisterTorchCallback(callback);
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800235 }
236
Emilian Peev423cbd72018-11-10 18:37:45 +0000237 private Size getDisplaySize() {
238 Size ret = new Size(0, 0);
239
240 try {
241 WindowManager windowManager =
242 (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
243 Display display = windowManager.getDefaultDisplay();
244
245 int width = display.getWidth();
246 int height = display.getHeight();
247
248 if (height > width) {
249 height = width;
250 width = display.getHeight();
251 }
252
253 ret = new Size(width, height);
254 } catch (Exception e) {
255 Log.e(TAG, "getDisplaySize Failed. " + e.toString());
256 }
257
258 return ret;
259 }
260
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800261 /**
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800262 * <p>Query the capabilities of a camera device. These capabilities are
263 * immutable for a given camera.</p>
264 *
Shuzhen Wang123deefc2018-08-20 12:00:05 -0700265 * <p>From API level 29, this function can also be used to query the capabilities of physical
266 * cameras that can only be used as part of logical multi-camera. These cameras cannot not be
267 * opened directly via {@link #openCamera}</p>
268 *
269 * @param cameraId The id of the camera device to query. This could be either a standalone
270 * camera ID which can be directly opened by {@link #openCamera}, or a physical camera ID that
271 * can only used as part of a logical multi-camera.
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800272 * @return The properties of the given camera
273 *
274 * @throws IllegalArgumentException if the cameraId does not match any
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700275 * known camera device.
Eino-Ville Talvala8b905572015-05-14 15:43:01 -0700276 * @throws CameraAccessException if the camera device has been disconnected.
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800277 *
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700278 * @see #getCameraIdList
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800279 * @see android.app.admin.DevicePolicyManager#setCameraDisabled
280 */
Eino-Ville Talvala8b905572015-05-14 15:43:01 -0700281 @NonNull
282 public CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId)
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800283 throws CameraAccessException {
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700284 CameraCharacteristics characteristics = null;
Eino-Ville Talvala19d96a12017-07-13 12:07:20 -0700285 if (CameraManagerGlobal.sCameraServiceDisabled) {
286 throw new IllegalArgumentException("No cameras available on device");
287 }
Igor Murashkine363fbb2013-06-25 20:26:06 +0000288 synchronized (mLock) {
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700289 /*
290 * Get the camera characteristics from the camera service directly if it supports it,
291 * otherwise get them from the legacy shim instead.
292 */
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700293 ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700294 if (cameraService == null) {
295 throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
296 "Camera service is currently unavailable");
297 }
Igor Murashkin4961bc82014-06-17 12:04:07 -0700298 try {
Emilian Peev423cbd72018-11-10 18:37:45 +0000299 Size displaySize = getDisplaySize();
300
Shuzhen Wang123deefc2018-08-20 12:00:05 -0700301 // First check isHiddenPhysicalCamera to avoid supportsCamera2ApiLocked throwing
302 // exception in case cameraId is a hidden physical camera.
303 if (!isHiddenPhysicalCamera(cameraId) && !supportsCamera2ApiLocked(cameraId)) {
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700304 // Legacy backwards compatibility path; build static info from the camera
305 // parameters
Eino-Ville Talvala283ae234f2016-12-08 13:38:52 -0800306 int id = Integer.parseInt(cameraId);
307
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800308 String parameters = cameraService.getLegacyParameters(id);
Igor Murashkin4961bc82014-06-17 12:04:07 -0700309
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800310 CameraInfo info = cameraService.getCameraInfo(id);
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700311
Emilian Peev423cbd72018-11-10 18:37:45 +0000312 characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info,
313 id, displaySize);
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700314 } else {
315 // Normal path: Get the camera characteristics directly from the camera service
Eino-Ville Talvala283ae234f2016-12-08 13:38:52 -0800316 CameraMetadataNative info = cameraService.getCameraCharacteristics(cameraId);
Emilian Peev423cbd72018-11-10 18:37:45 +0000317 if (!isHiddenPhysicalCamera(cameraId)) {
318 try {
319 info.setCameraId(Integer.parseInt(cameraId));
320 } catch (NumberFormatException e) {
321 Log.e(TAG, "Failed to parse camera Id " + cameraId + " to integer");
322 }
323 }
324 info.setDisplaySize(displaySize);
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700325
326 characteristics = new CameraCharacteristics(info);
327 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800328 } catch (ServiceSpecificException e) {
329 throwAsPublicException(e);
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700330 } catch (RemoteException e) {
331 // Camera service died - act as if the camera was disconnected
332 throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
333 "Camera service is currently unavailable", e);
Igor Murashkin4961bc82014-06-17 12:04:07 -0700334 }
Zhijun He20011882013-09-25 10:05:59 -0700335 }
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700336 return characteristics;
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800337 }
338
339 /**
Ruben Brunk0f2be132015-04-17 14:23:40 -0700340 * Helper for opening a connection to a camera with the given ID.
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800341 *
342 * @param cameraId The unique identifier of the camera device to open
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700343 * @param callback The callback for the camera. Must not be null.
Emilian Peev9129aa22018-03-20 15:39:34 +0000344 * @param executor The executor to invoke the callback with. Must not be null.
Eino-Ville Talvala62deabc2016-07-08 12:11:11 -0700345 * @param uid The UID of the application actually opening the camera.
346 * Must be USE_CALLING_UID unless the caller is a service
347 * that is trusted to open the device on behalf of an
348 * application and to forward the real UID.
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800349 *
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800350 * @throws CameraAccessException if the camera is disabled by device policy,
Ruben Brunk0f2be132015-04-17 14:23:40 -0700351 * too many camera devices are already open, or the cameraId does not match
Ruben Brunk66ef6452013-08-08 13:05:30 -0700352 * any currently available camera device.
353 *
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800354 * @throws SecurityException if the application does not have permission to
355 * access the camera
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700356 * @throws IllegalArgumentException if callback or handler is null.
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700357 * @return A handle to the newly-created camera device.
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800358 *
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700359 * @see #getCameraIdList
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800360 * @see android.app.admin.DevicePolicyManager#setCameraDisabled
361 */
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700362 private CameraDevice openCameraDeviceUserAsync(String cameraId,
Emilian Peev9129aa22018-03-20 15:39:34 +0000363 CameraDevice.StateCallback callback, Executor executor, final int uid)
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700364 throws CameraAccessException {
Ruben Brunk57493682014-05-27 18:58:08 -0700365 CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700366 CameraDevice device = null;
Igor Murashkine363fbb2013-06-25 20:26:06 +0000367
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800368 synchronized (mLock) {
Igor Murashkin70725502013-06-25 20:27:06 +0000369
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800370 ICameraDeviceUser cameraUser = null;
Igor Murashkin70725502013-06-25 20:27:06 +0000371
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800372 android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
373 new android.hardware.camera2.impl.CameraDeviceImpl(
374 cameraId,
375 callback,
Emilian Peev9129aa22018-03-20 15:39:34 +0000376 executor,
Chien-Yu Chen3d2b5fe2017-04-05 16:42:31 -0700377 characteristics,
378 mContext.getApplicationInfo().targetSdkVersion);
Igor Murashkin70725502013-06-25 20:27:06 +0000379
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800380 ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700381
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800382 try {
383 if (supportsCamera2ApiLocked(cameraId)) {
384 // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
385 ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
386 if (cameraService == null) {
387 throw new ServiceSpecificException(
388 ICameraService.ERROR_DISCONNECTED,
389 "Camera service is currently unavailable");
390 }
Eino-Ville Talvala283ae234f2016-12-08 13:38:52 -0800391 cameraUser = cameraService.connectDevice(callbacks, cameraId,
Eino-Ville Talvala62deabc2016-07-08 12:11:11 -0700392 mContext.getOpPackageName(), uid);
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800393 } else {
394 // Use legacy camera implementation for HAL1 devices
Eino-Ville Talvala283ae234f2016-12-08 13:38:52 -0800395 int id;
396 try {
397 id = Integer.parseInt(cameraId);
398 } catch (NumberFormatException e) {
399 throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
400 + cameraId);
401 }
402
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800403 Log.i(TAG, "Using legacy camera HAL.");
Emilian Peev423cbd72018-11-10 18:37:45 +0000404 cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id,
405 getDisplaySize());
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800406 }
407 } catch (ServiceSpecificException e) {
408 if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
409 throw new AssertionError("Should've gone down the shim path");
410 } else if (e.errorCode == ICameraService.ERROR_CAMERA_IN_USE ||
411 e.errorCode == ICameraService.ERROR_MAX_CAMERAS_IN_USE ||
412 e.errorCode == ICameraService.ERROR_DISABLED ||
413 e.errorCode == ICameraService.ERROR_DISCONNECTED ||
414 e.errorCode == ICameraService.ERROR_INVALID_OPERATION) {
415 // Received one of the known connection errors
416 // The remote camera device cannot be connected to, so
417 // set the local camera to the startup error state
418 deviceImpl.setRemoteFailure(e);
419
420 if (e.errorCode == ICameraService.ERROR_DISABLED ||
421 e.errorCode == ICameraService.ERROR_DISCONNECTED ||
422 e.errorCode == ICameraService.ERROR_CAMERA_IN_USE) {
423 // Per API docs, these failures call onError and throw
424 throwAsPublicException(e);
425 }
426 } else {
427 // Unexpected failure - rethrow
428 throwAsPublicException(e);
429 }
430 } catch (RemoteException e) {
431 // Camera service died - act as if it's a CAMERA_DISCONNECTED case
432 ServiceSpecificException sse = new ServiceSpecificException(
433 ICameraService.ERROR_DISCONNECTED,
434 "Camera service is currently unavailable");
435 deviceImpl.setRemoteFailure(sse);
436 throwAsPublicException(sse);
437 }
438
439 // TODO: factor out callback to be non-nested, then move setter to constructor
440 // For now, calling setRemoteDevice will fire initial
441 // onOpened/onUnconfigured callbacks.
Shuzhen Wang78392932016-03-04 15:26:01 -0800442 // This function call may post onDisconnected and throw CAMERA_DISCONNECTED if
443 // cameraUser dies during setup.
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800444 deviceImpl.setRemoteDevice(cameraUser);
445 device = deviceImpl;
Igor Murashkine363fbb2013-06-25 20:26:06 +0000446 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800447
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700448 return device;
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800449 }
450
451 /**
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700452 * Open a connection to a camera with the given ID.
453 *
454 * <p>Use {@link #getCameraIdList} to get the list of available camera
455 * devices. Note that even if an id is listed, open may fail if the device
456 * is disconnected between the calls to {@link #getCameraIdList} and
Ruben Brunk0f2be132015-04-17 14:23:40 -0700457 * {@link #openCamera}, or if a higher-priority camera API client begins using the
458 * camera device.</p>
459 *
460 * <p>As of API level 23, devices for which the
461 * {@link AvailabilityCallback#onCameraUnavailable(String)} callback has been called due to the
462 * device being in use by a lower-priority, background camera API client can still potentially
463 * be opened by calling this method when the calling camera API client has a higher priority
464 * than the current camera API client using this device. In general, if the top, foreground
465 * activity is running within your application process, your process will be given the highest
466 * priority when accessing the camera, and this method will succeed even if the camera device is
467 * in use by another camera API client. Any lower-priority application that loses control of the
468 * camera in this way will receive an
469 * {@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected} callback.</p>
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700470 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700471 * <p>Once the camera is successfully opened, {@link CameraDevice.StateCallback#onOpened} will
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700472 * be invoked with the newly opened {@link CameraDevice}. The camera device can then be set up
473 * for operation by calling {@link CameraDevice#createCaptureSession} and
474 * {@link CameraDevice#createCaptureRequest}</p>
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700475 *
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700476 * <!--
477 * <p>Since the camera device will be opened asynchronously, any asynchronous operations done
478 * on the returned CameraDevice instance will be queued up until the device startup has
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700479 * completed and the callback's {@link CameraDevice.StateCallback#onOpened onOpened} method is
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700480 * called. The pending operations are then processed in order.</p>
481 * -->
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700482 * <p>If the camera becomes disconnected during initialization
483 * after this function call returns,
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700484 * {@link CameraDevice.StateCallback#onDisconnected} with a
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700485 * {@link CameraDevice} in the disconnected state (and
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700486 * {@link CameraDevice.StateCallback#onOpened} will be skipped).</p>
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700487 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700488 * <p>If opening the camera device fails, then the device callback's
489 * {@link CameraDevice.StateCallback#onError onError} method will be called, and subsequent
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700490 * calls on the camera device will throw a {@link CameraAccessException}.</p>
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700491 *
492 * @param cameraId
493 * The unique identifier of the camera device to open
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700494 * @param callback
495 * The callback which is invoked once the camera is opened
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700496 * @param handler
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700497 * The handler on which the callback should be invoked, or
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700498 * {@code null} to use the current thread's {@link android.os.Looper looper}.
499 *
500 * @throws CameraAccessException if the camera is disabled by device policy,
Ruben Brunk0f2be132015-04-17 14:23:40 -0700501 * has been disconnected, or is being used by a higher-priority camera API client.
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700502 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700503 * @throws IllegalArgumentException if cameraId or the callback was null,
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700504 * or the cameraId does not match any currently or previously available
Shuzhen Wang123deefc2018-08-20 12:00:05 -0700505 * camera device returned by {@link #getCameraIdList}.
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700506 *
507 * @throws SecurityException if the application does not have permission to
508 * access the camera
509 *
510 * @see #getCameraIdList
511 * @see android.app.admin.DevicePolicyManager#setCameraDisabled
512 */
Eino-Ville Talvala8b905572015-05-14 15:43:01 -0700513 @RequiresPermission(android.Manifest.permission.CAMERA)
514 public void openCamera(@NonNull String cameraId,
515 @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700516 throws CameraAccessException {
517
Emilian Peev9129aa22018-03-20 15:39:34 +0000518 openCameraForUid(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler),
519 USE_CALLING_UID);
520 }
521
522 /**
523 * Open a connection to a camera with the given ID.
524 *
525 * <p>The behavior of this method matches that of
526 * {@link #openCamera(String, StateCallback, Handler)}, except that it uses
527 * {@link java.util.concurrent.Executor} as an argument instead of
528 * {@link android.os.Handler}.</p>
529 *
530 * @param cameraId
531 * The unique identifier of the camera device to open
532 * @param executor
533 * The executor which will be used when invoking the callback.
534 * @param callback
535 * The callback which is invoked once the camera is opened
536 *
537 * @throws CameraAccessException if the camera is disabled by device policy,
538 * has been disconnected, or is being used by a higher-priority camera API client.
539 *
540 * @throws IllegalArgumentException if cameraId, the callback or the executor was null,
541 * or the cameraId does not match any currently or previously available
542 * camera device.
543 *
544 * @throws SecurityException if the application does not have permission to
545 * access the camera
546 *
547 * @see #getCameraIdList
548 * @see android.app.admin.DevicePolicyManager#setCameraDisabled
549 */
550 @RequiresPermission(android.Manifest.permission.CAMERA)
551 public void openCamera(@NonNull String cameraId,
552 @NonNull @CallbackExecutor Executor executor,
553 @NonNull final CameraDevice.StateCallback callback)
554 throws CameraAccessException {
555 if (executor == null) {
556 throw new IllegalArgumentException("executor was null");
557 }
558 openCameraForUid(cameraId, callback, executor, USE_CALLING_UID);
Eino-Ville Talvala62deabc2016-07-08 12:11:11 -0700559 }
560
561 /**
562 * Open a connection to a camera with the given ID, on behalf of another application
563 * specified by clientUid.
564 *
565 * <p>The behavior of this method matches that of {@link #openCamera}, except that it allows
566 * the caller to specify the UID to use for permission/etc verification. This can only be
567 * done by services trusted by the camera subsystem to act on behalf of applications and
568 * to forward the real UID.</p>
569 *
570 * @param clientUid
571 * The UID of the application on whose behalf the camera is being opened.
572 * Must be USE_CALLING_UID unless the caller is a trusted service.
573 *
574 * @hide
575 */
576 public void openCameraForUid(@NonNull String cameraId,
Emilian Peev9129aa22018-03-20 15:39:34 +0000577 @NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor,
Eino-Ville Talvala62deabc2016-07-08 12:11:11 -0700578 int clientUid)
579 throws CameraAccessException {
580
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700581 if (cameraId == null) {
582 throw new IllegalArgumentException("cameraId was null");
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700583 } else if (callback == null) {
584 throw new IllegalArgumentException("callback was null");
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700585 }
Eino-Ville Talvala19d96a12017-07-13 12:07:20 -0700586 if (CameraManagerGlobal.sCameraServiceDisabled) {
587 throw new IllegalArgumentException("No cameras available on device");
588 }
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700589
Emilian Peev9129aa22018-03-20 15:39:34 +0000590 openCameraDeviceUserAsync(cameraId, callback, executor, clientUid);
Igor Murashkin5c9eaf62013-09-10 19:35:24 -0700591 }
592
593 /**
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800594 * Set the flash unit's torch mode of the camera of the given ID without opening the camera
595 * device.
596 *
597 * <p>Use {@link #getCameraIdList} to get the list of available camera devices and use
598 * {@link #getCameraCharacteristics} to check whether the camera device has a flash unit.
599 * Note that even if a camera device has a flash unit, turning on the torch mode may fail
600 * if the camera device or other camera resources needed to turn on the torch mode are in use.
601 * </p>
602 *
603 * <p> If {@link #setTorchMode} is called to turn on or off the torch mode successfully,
604 * {@link CameraManager.TorchCallback#onTorchModeChanged} will be invoked.
605 * However, even if turning on the torch mode is successful, the application does not have the
606 * exclusive ownership of the flash unit or the camera device. The torch mode will be turned
607 * off and becomes unavailable when the camera device that the flash unit belongs to becomes
Chien-Yu Chenafa91392015-02-11 11:23:28 -0800608 * unavailable or when other camera resources to keep the torch on become unavailable (
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800609 * {@link CameraManager.TorchCallback#onTorchModeUnavailable} will be invoked). Also,
610 * other applications are free to call {@link #setTorchMode} to turn off the torch mode (
Chien-Yu Chenafa91392015-02-11 11:23:28 -0800611 * {@link CameraManager.TorchCallback#onTorchModeChanged} will be invoked). If the latest
612 * application that turned on the torch mode exits, the torch mode will be turned off.
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800613 *
614 * @param cameraId
615 * The unique identifier of the camera device that the flash unit belongs to.
616 * @param enabled
617 * The desired state of the torch mode for the target camera device. Set to
618 * {@code true} to turn on the torch mode. Set to {@code false} to turn off the
619 * torch mode.
620 *
621 * @throws CameraAccessException if it failed to access the flash unit.
622 * {@link CameraAccessException#CAMERA_IN_USE} will be thrown if the camera device
623 * is in use. {@link CameraAccessException#MAX_CAMERAS_IN_USE} will be thrown if
624 * other camera resources needed to turn on the torch mode are in use.
Chien-Yu Chenafa91392015-02-11 11:23:28 -0800625 * {@link CameraAccessException#CAMERA_DISCONNECTED} will be thrown if camera
626 * service is not available.
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800627 *
628 * @throws IllegalArgumentException if cameraId was null, cameraId doesn't match any currently
629 * or previously available camera device, or the camera device doesn't have a
630 * flash unit.
631 */
Eino-Ville Talvala8b905572015-05-14 15:43:01 -0700632 public void setTorchMode(@NonNull String cameraId, boolean enabled)
633 throws CameraAccessException {
Eino-Ville Talvala19d96a12017-07-13 12:07:20 -0700634 if (CameraManagerGlobal.sCameraServiceDisabled) {
635 throw new IllegalArgumentException("No cameras available on device");
636 }
Chien-Yu Chenafa91392015-02-11 11:23:28 -0800637 CameraManagerGlobal.get().setTorchMode(cameraId, enabled);
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800638 }
639
640 /**
Ruben Brunk0f2be132015-04-17 14:23:40 -0700641 * A callback for camera devices becoming available or unavailable to open.
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700642 *
643 * <p>Cameras become available when they are no longer in use, or when a new
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800644 * removable camera is connected. They become unavailable when some
645 * application or service starts using a camera, or when a removable camera
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700646 * is disconnected.</p>
647 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700648 * <p>Extend this callback and pass an instance of the subclass to
649 * {@link CameraManager#registerAvailabilityCallback} to be notified of such availability
Eino-Ville Talvalab67a3b32014-06-06 13:07:20 -0700650 * changes.</p>
651 *
Philip P. Moltmann85e1d502015-10-26 08:50:04 -0700652 * @see #registerAvailabilityCallback
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800653 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700654 public static abstract class AvailabilityCallback {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700655
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800656 /**
657 * A new camera has become available to use.
658 *
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700659 * <p>The default implementation of this method does nothing.</p>
660 *
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800661 * @param cameraId The unique identifier of the new camera.
662 */
Eino-Ville Talvala8b905572015-05-14 15:43:01 -0700663 public void onCameraAvailable(@NonNull String cameraId) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700664 // default empty implementation
665 }
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800666
667 /**
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700668 * A previously-available camera has become unavailable for use.
669 *
670 * <p>If an application had an active CameraDevice instance for the
671 * now-disconnected camera, that application will receive a
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700672 * {@link CameraDevice.StateCallback#onDisconnected disconnection error}.</p>
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700673 *
674 * <p>The default implementation of this method does nothing.</p>
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800675 *
676 * @param cameraId The unique identifier of the disconnected camera.
677 */
Eino-Ville Talvala8b905572015-05-14 15:43:01 -0700678 public void onCameraUnavailable(@NonNull String cameraId) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700679 // default empty implementation
680 }
Eino-Ville Talvalab2675542012-12-12 13:29:45 -0800681 }
Igor Murashkine363fbb2013-06-25 20:26:06 +0000682
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700683 /**
Chien-Yu Chenafa91392015-02-11 11:23:28 -0800684 * A callback for camera flash torch modes becoming unavailable, disabled, or enabled.
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800685 *
Chien-Yu Chenafa91392015-02-11 11:23:28 -0800686 * <p>The torch mode becomes unavailable when the camera device it belongs to becomes
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700687 * unavailable or other camera resources it needs become busy due to other higher priority
Chien-Yu Chenafa91392015-02-11 11:23:28 -0800688 * camera activities. The torch mode becomes disabled when it was turned off or when the camera
689 * device it belongs to is no longer in use and other camera resources it needs are no longer
690 * busy. A camera's torch mode is turned off when an application calls {@link #setTorchMode} to
691 * turn off the camera's torch mode, or when an application turns on another camera's torch mode
692 * if keeping multiple torch modes on simultaneously is not supported. The torch mode becomes
693 * enabled when it is turned on via {@link #setTorchMode}.</p>
694 *
695 * <p>The torch mode is available to set via {@link #setTorchMode} only when it's in a disabled
696 * or enabled state.</p>
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800697 *
698 * <p>Extend this callback and pass an instance of the subclass to
699 * {@link CameraManager#registerTorchCallback} to be notified of such status changes.
700 * </p>
701 *
Chien-Yu Chen8062d312015-05-12 14:24:10 -0700702 * @see #registerTorchCallback
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800703 */
704 public static abstract class TorchCallback {
705 /**
Chien-Yu Chenafa91392015-02-11 11:23:28 -0800706 * A camera's torch mode has become unavailable to set via {@link #setTorchMode}.
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800707 *
708 * <p>If torch mode was previously turned on by calling {@link #setTorchMode}, it will be
709 * turned off before {@link CameraManager.TorchCallback#onTorchModeUnavailable} is
Chien-Yu Chenafa91392015-02-11 11:23:28 -0800710 * invoked. {@link #setTorchMode} will fail until the torch mode has entered a disabled or
711 * enabled state again.</p>
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800712 *
713 * <p>The default implementation of this method does nothing.</p>
714 *
715 * @param cameraId The unique identifier of the camera whose torch mode has become
716 * unavailable.
717 */
Eino-Ville Talvala8b905572015-05-14 15:43:01 -0700718 public void onTorchModeUnavailable(@NonNull String cameraId) {
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800719 // default empty implementation
720 }
721
722 /**
Chien-Yu Chenafa91392015-02-11 11:23:28 -0800723 * A camera's torch mode has become enabled or disabled and can be changed via
724 * {@link #setTorchMode}.
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800725 *
726 * <p>The default implementation of this method does nothing.</p>
727 *
728 * @param cameraId The unique identifier of the camera whose torch mode has been changed.
729 *
730 * @param enabled The state that the torch mode of the camera has been changed to.
Chien-Yu Chenafa91392015-02-11 11:23:28 -0800731 * {@code true} when the torch mode has become on and available to be turned
732 * off. {@code false} when the torch mode has becomes off and available to
733 * be turned on.
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800734 */
Eino-Ville Talvala8b905572015-05-14 15:43:01 -0700735 public void onTorchModeChanged(@NonNull String cameraId, boolean enabled) {
Chien-Yu Chenc8c109b2015-01-09 15:52:37 -0800736 // default empty implementation
737 }
738 }
739
740 /**
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800741 * Convert ServiceSpecificExceptions and Binder RemoteExceptions from camera binder interfaces
742 * into the correct public exceptions.
743 *
744 * @hide
745 */
746 public static void throwAsPublicException(Throwable t) throws CameraAccessException {
747 if (t instanceof ServiceSpecificException) {
748 ServiceSpecificException e = (ServiceSpecificException) t;
749 int reason = CameraAccessException.CAMERA_ERROR;
750 switch(e.errorCode) {
751 case ICameraService.ERROR_DISCONNECTED:
752 reason = CameraAccessException.CAMERA_DISCONNECTED;
753 break;
754 case ICameraService.ERROR_DISABLED:
755 reason = CameraAccessException.CAMERA_DISABLED;
756 break;
757 case ICameraService.ERROR_CAMERA_IN_USE:
758 reason = CameraAccessException.CAMERA_IN_USE;
759 break;
760 case ICameraService.ERROR_MAX_CAMERAS_IN_USE:
761 reason = CameraAccessException.MAX_CAMERAS_IN_USE;
762 break;
763 case ICameraService.ERROR_DEPRECATED_HAL:
764 reason = CameraAccessException.CAMERA_DEPRECATED_HAL;
765 break;
766 case ICameraService.ERROR_ILLEGAL_ARGUMENT:
767 case ICameraService.ERROR_ALREADY_EXISTS:
768 throw new IllegalArgumentException(e.getMessage(), e);
769 case ICameraService.ERROR_PERMISSION_DENIED:
770 throw new SecurityException(e.getMessage(), e);
771 case ICameraService.ERROR_TIMED_OUT:
772 case ICameraService.ERROR_INVALID_OPERATION:
773 default:
774 reason = CameraAccessException.CAMERA_ERROR;
775 }
776 throw new CameraAccessException(reason, e.getMessage(), e);
777 } else if (t instanceof DeadObjectException) {
778 throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
779 "Camera service has died unexpectedly",
780 t);
781 } else if (t instanceof RemoteException) {
782 throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
783 " which should never happen.", t);
784 } else if (t instanceof RuntimeException) {
785 RuntimeException e = (RuntimeException) t;
786 throw e;
787 }
788 }
789
790 /**
Igor Murashkin4961bc82014-06-17 12:04:07 -0700791 * Queries the camera service if it supports the camera2 api directly, or needs a shim.
792 *
793 * @param cameraId a non-{@code null} camera identifier
794 * @return {@code false} if the legacy shim needs to be used, {@code true} otherwise.
795 */
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700796 private boolean supportsCamera2ApiLocked(String cameraId) {
797 return supportsCameraApiLocked(cameraId, API_VERSION_2);
Igor Murashkin4961bc82014-06-17 12:04:07 -0700798 }
799
800 /**
801 * Queries the camera service if it supports a camera api directly, or needs a shim.
802 *
803 * @param cameraId a non-{@code null} camera identifier
804 * @param apiVersion the version, i.e. {@code API_VERSION_1} or {@code API_VERSION_2}
805 * @return {@code true} if connecting will work for that device version.
806 */
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700807 private boolean supportsCameraApiLocked(String cameraId, int apiVersion) {
Igor Murashkin4961bc82014-06-17 12:04:07 -0700808 /*
809 * Possible return values:
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700810 * - NO_ERROR => CameraX API is supported
811 * - CAMERA_DEPRECATED_HAL => CameraX API is *not* supported (thrown as an exception)
812 * - Remote exception => If the camera service died
Igor Murashkin4961bc82014-06-17 12:04:07 -0700813 *
814 * Anything else is an unexpected error we don't want to recover from.
815 */
Igor Murashkin4961bc82014-06-17 12:04:07 -0700816 try {
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700817 ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700818 // If no camera service, no support
819 if (cameraService == null) return false;
Igor Murashkin4961bc82014-06-17 12:04:07 -0700820
Eino-Ville Talvala283ae234f2016-12-08 13:38:52 -0800821 return cameraService.supportsCameraApi(cameraId, apiVersion);
Igor Murashkin4961bc82014-06-17 12:04:07 -0700822 } catch (RemoteException e) {
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700823 // Camera service is now down, no support for any API level
824 }
825 return false;
826 }
827
828 /**
Shuzhen Wang123deefc2018-08-20 12:00:05 -0700829 * Queries the camera service if a cameraId is a hidden physical camera that belongs to a
830 * logical camera device.
831 *
832 * A hidden physical camera is a camera that cannot be opened by the application. But it
833 * can be used as part of a logical camera.
834 *
835 * @param cameraId a non-{@code null} camera identifier
836 * @return {@code true} if cameraId is a hidden physical camera device
837 */
838 private boolean isHiddenPhysicalCamera(String cameraId) {
839 try {
840 ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
841 // If no camera service, no support
842 if (cameraService == null) return false;
843
844 return cameraService.isHiddenPhysicalCamera(cameraId);
845 } catch (RemoteException e) {
846 // Camera service is now down, no support for any API level
847 }
848 return false;
849 }
850
851 /**
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700852 * A per-process global camera manager instance, to retain a connection to the camera service,
853 * and to distribute camera availability notices to API-registered callbacks
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700854 */
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700855 private static final class CameraManagerGlobal extends ICameraServiceListener.Stub
856 implements IBinder.DeathRecipient {
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700857
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700858 private static final String TAG = "CameraManagerGlobal";
Eino-Ville Talvalaa78791f2015-06-01 12:39:54 -0700859 private final boolean DEBUG = false;
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700860
Chien-Yu Chen0f69b462015-07-13 16:37:13 -0700861 private final int CAMERA_SERVICE_RECONNECT_DELAY_MS = 1000;
862
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700863 // Singleton instance
864 private static final CameraManagerGlobal gCameraManager =
865 new CameraManagerGlobal();
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700866
867 /**
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700868 * This must match the ICameraService definition
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -0700869 */
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700870 private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
Igor Murashkine363fbb2013-06-25 20:26:06 +0000871
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000872 private final ScheduledExecutorService mScheduler = Executors.newScheduledThreadPool(1);
Igor Murashkine363fbb2013-06-25 20:26:06 +0000873 // Camera ID -> Status map
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700874 private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>();
Igor Murashkine363fbb2013-06-25 20:26:06 +0000875
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000876 // Registered availablility callbacks and their executors
877 private final ArrayMap<AvailabilityCallback, Executor> mCallbackMap =
878 new ArrayMap<AvailabilityCallback, Executor>();
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700879
Chien-Yu Chenafa91392015-02-11 11:23:28 -0800880 // torch client binder to set the torch mode with.
881 private Binder mTorchClientBinder = new Binder();
882
883 // Camera ID -> Torch status map
884 private final ArrayMap<String, Integer> mTorchStatus = new ArrayMap<String, Integer>();
885
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000886 // Registered torch callbacks and their executors
887 private final ArrayMap<TorchCallback, Executor> mTorchCallbackMap =
888 new ArrayMap<TorchCallback, Executor>();
Chien-Yu Chenafa91392015-02-11 11:23:28 -0800889
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700890 private final Object mLock = new Object();
891
892 // Access only through getCameraService to deal with binder death
893 private ICameraService mCameraService;
894
895 // Singleton, don't allow construction
896 private CameraManagerGlobal() {
897 }
898
Eino-Ville Talvala19d96a12017-07-13 12:07:20 -0700899 public static final boolean sCameraServiceDisabled =
900 SystemProperties.getBoolean("config.disable_cameraservice", false);
901
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700902 public static CameraManagerGlobal get() {
903 return gCameraManager;
904 }
Igor Murashkine363fbb2013-06-25 20:26:06 +0000905
906 @Override
907 public IBinder asBinder() {
908 return this;
909 }
910
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700911 /**
912 * Return a best-effort ICameraService.
913 *
914 * <p>This will be null if the camera service is not currently available. If the camera
915 * service has died since the last use of the camera service, will try to reconnect to the
916 * service.</p>
917 */
918 public ICameraService getCameraService() {
919 synchronized(mLock) {
Eino-Ville Talvala2ef01732015-05-30 17:56:37 -0700920 connectCameraServiceLocked();
Eino-Ville Talvala19d96a12017-07-13 12:07:20 -0700921 if (mCameraService == null && !sCameraServiceDisabled) {
Eino-Ville Talvala2ef01732015-05-30 17:56:37 -0700922 Log.e(TAG, "Camera service is unavailable");
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700923 }
924 return mCameraService;
925 }
926 }
927
928 /**
929 * Connect to the camera service if it's available, and set up listeners.
Eino-Ville Talvala2ef01732015-05-30 17:56:37 -0700930 * If the service is already connected, do nothing.
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700931 *
932 * <p>Sets mCameraService to a valid pointer or null if the connection does not succeed.</p>
933 */
934 private void connectCameraServiceLocked() {
Eino-Ville Talvala2ef01732015-05-30 17:56:37 -0700935 // Only reconnect if necessary
Eino-Ville Talvala19d96a12017-07-13 12:07:20 -0700936 if (mCameraService != null || sCameraServiceDisabled) return;
Eino-Ville Talvala2ef01732015-05-30 17:56:37 -0700937
938 Log.i(TAG, "Connecting to camera service");
939
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700940 IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME);
941 if (cameraServiceBinder == null) {
942 // Camera service is now down, leave mCameraService as null
943 return;
944 }
945 try {
946 cameraServiceBinder.linkToDeath(this, /*flags*/ 0);
947 } catch (RemoteException e) {
948 // Camera service is now down, leave mCameraService as null
949 return;
950 }
951
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800952 ICameraService cameraService = ICameraService.Stub.asInterface(cameraServiceBinder);
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700953
954 try {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800955 CameraMetadataNative.setupGlobalVendorTagDescriptor();
956 } catch (ServiceSpecificException e) {
957 handleRecoverableSetupErrors(e);
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700958 }
959
960 try {
Eino-Ville Talvala283ae234f2016-12-08 13:38:52 -0800961 CameraStatus[] cameraStatuses = cameraService.addListener(this);
962 for (CameraStatus c : cameraStatuses) {
963 onStatusChangedLocked(c.status, c.cameraId);
964 }
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700965 mCameraService = cameraService;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800966 } catch(ServiceSpecificException e) {
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700967 // Unexpected failure
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800968 throw new IllegalStateException("Failed to register a camera service listener", e);
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -0700969 } catch (RemoteException e) {
970 // Camera service is now down, leave mCameraService as null
971 }
972 }
973
Eino-Ville Talvala283ae234f2016-12-08 13:38:52 -0800974 /**
975 * Get a list of all camera IDs that are at least PRESENT; ignore devices that are
976 * NOT_PRESENT or ENUMERATING, since they cannot be used by anyone.
977 */
978 public String[] getCameraIdList() {
979 String[] cameraIds = null;
980 synchronized(mLock) {
981 // Try to make sure we have an up-to-date list of camera devices.
982 connectCameraServiceLocked();
983
984 int idCount = 0;
985 for (int i = 0; i < mDeviceStatus.size(); i++) {
986 int status = mDeviceStatus.valueAt(i);
987 if (status == ICameraServiceListener.STATUS_NOT_PRESENT ||
988 status == ICameraServiceListener.STATUS_ENUMERATING) continue;
989 idCount++;
990 }
991 cameraIds = new String[idCount];
992 idCount = 0;
993 for (int i = 0; i < mDeviceStatus.size(); i++) {
994 int status = mDeviceStatus.valueAt(i);
995 if (status == ICameraServiceListener.STATUS_NOT_PRESENT ||
996 status == ICameraServiceListener.STATUS_ENUMERATING) continue;
997 cameraIds[idCount] = mDeviceStatus.keyAt(i);
998 idCount++;
999 }
1000 }
Yin-Chia Yehf8aa7bc2018-03-09 15:48:16 -08001001
1002 // The sort logic must match the logic in
1003 // libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds
1004 Arrays.sort(cameraIds, new Comparator<String>() {
1005 @Override
1006 public int compare(String s1, String s2) {
1007 int s1Int = 0, s2Int = 0;
1008 try {
1009 s1Int = Integer.parseInt(s1);
1010 } catch (NumberFormatException e) {
1011 s1Int = -1;
1012 }
1013
1014 try {
1015 s2Int = Integer.parseInt(s2);
1016 } catch (NumberFormatException e) {
1017 s2Int = -1;
1018 }
1019
1020 // Uint device IDs first
1021 if (s1Int >= 0 && s2Int >= 0) {
1022 return s1Int - s2Int;
1023 } else if (s1Int >= 0) {
1024 return -1;
1025 } else if (s2Int >= 0) {
1026 return 1;
1027 } else {
1028 // Simple string compare if both id are not uint
1029 return s1.compareTo(s2);
1030 }
1031 }});
Eino-Ville Talvala283ae234f2016-12-08 13:38:52 -08001032 return cameraIds;
1033 }
1034
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001035 public void setTorchMode(String cameraId, boolean enabled) throws CameraAccessException {
1036 synchronized(mLock) {
1037
1038 if (cameraId == null) {
1039 throw new IllegalArgumentException("cameraId was null");
1040 }
1041
1042 ICameraService cameraService = getCameraService();
1043 if (cameraService == null) {
1044 throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
1045 "Camera service is currently unavailable");
1046 }
1047
1048 try {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001049 cameraService.setTorchMode(cameraId, enabled, mTorchClientBinder);
1050 } catch(ServiceSpecificException e) {
1051 throwAsPublicException(e);
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001052 } catch (RemoteException e) {
1053 throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
1054 "Camera service is currently unavailable");
1055 }
1056 }
1057 }
1058
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001059 private void handleRecoverableSetupErrors(ServiceSpecificException e) {
1060 switch (e.errorCode) {
1061 case ICameraService.ERROR_DISCONNECTED:
1062 Log.w(TAG, e.getMessage());
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001063 break;
1064 default:
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001065 throw new IllegalStateException(e);
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001066 }
1067 }
1068
Igor Murashkine363fbb2013-06-25 20:26:06 +00001069 private boolean isAvailable(int status) {
1070 switch (status) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001071 case ICameraServiceListener.STATUS_PRESENT:
Igor Murashkine363fbb2013-06-25 20:26:06 +00001072 return true;
1073 default:
1074 return false;
1075 }
1076 }
1077
1078 private boolean validStatus(int status) {
1079 switch (status) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001080 case ICameraServiceListener.STATUS_NOT_PRESENT:
1081 case ICameraServiceListener.STATUS_PRESENT:
1082 case ICameraServiceListener.STATUS_ENUMERATING:
1083 case ICameraServiceListener.STATUS_NOT_AVAILABLE:
Igor Murashkine363fbb2013-06-25 20:26:06 +00001084 return true;
1085 default:
1086 return false;
1087 }
1088 }
1089
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001090 private boolean validTorchStatus(int status) {
1091 switch (status) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001092 case ICameraServiceListener.TORCH_STATUS_NOT_AVAILABLE:
1093 case ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON:
1094 case ICameraServiceListener.TORCH_STATUS_AVAILABLE_OFF:
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001095 return true;
1096 default:
1097 return false;
1098 }
1099 }
1100
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001101 private void postSingleUpdate(final AvailabilityCallback callback, final Executor executor,
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001102 final String id, final int status) {
1103 if (isAvailable(status)) {
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001104 final long ident = Binder.clearCallingIdentity();
1105 try {
1106 executor.execute(
1107 new Runnable() {
1108 @Override
1109 public void run() {
1110 callback.onCameraAvailable(id);
1111 }
1112 });
1113 } finally {
1114 Binder.restoreCallingIdentity(ident);
1115 }
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001116 } else {
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001117 final long ident = Binder.clearCallingIdentity();
1118 try {
1119 executor.execute(
1120 new Runnable() {
1121 @Override
1122 public void run() {
1123 callback.onCameraUnavailable(id);
1124 }
1125 });
1126 } finally {
1127 Binder.restoreCallingIdentity(ident);
1128 }
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001129 }
1130 }
1131
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001132 private void postSingleTorchUpdate(final TorchCallback callback, final Executor executor,
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001133 final String id, final int status) {
1134 switch(status) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001135 case ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON:
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001136 case ICameraServiceListener.TORCH_STATUS_AVAILABLE_OFF: {
1137 final long ident = Binder.clearCallingIdentity();
1138 try {
1139 executor.execute(() -> {
1140 callback.onTorchModeChanged(id, status ==
1141 ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON);
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001142 });
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001143 } finally {
1144 Binder.restoreCallingIdentity(ident);
1145 }
1146 }
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001147 break;
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001148 default: {
1149 final long ident = Binder.clearCallingIdentity();
1150 try {
1151 executor.execute(() -> {
1152 callback.onTorchModeUnavailable(id);
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001153 });
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001154 } finally {
1155 Binder.restoreCallingIdentity(ident);
1156 }
1157 }
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001158 break;
1159 }
1160 }
1161
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001162 /**
1163 * Send the state of all known cameras to the provided listener, to initialize
1164 * the listener's knowledge of camera state.
1165 */
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001166 private void updateCallbackLocked(AvailabilityCallback callback, Executor executor) {
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001167 for (int i = 0; i < mDeviceStatus.size(); i++) {
1168 String id = mDeviceStatus.keyAt(i);
1169 Integer status = mDeviceStatus.valueAt(i);
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001170 postSingleUpdate(callback, executor, id, status);
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001171 }
1172 }
1173
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001174 private void onStatusChangedLocked(int status, String id) {
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001175 if (DEBUG) {
Igor Murashkine363fbb2013-06-25 20:26:06 +00001176 Log.v(TAG,
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001177 String.format("Camera id %s has status changed to 0x%x", id, status));
1178 }
Igor Murashkine363fbb2013-06-25 20:26:06 +00001179
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001180 if (!validStatus(status)) {
1181 Log.e(TAG, String.format("Ignoring invalid device %s status 0x%x", id,
1182 status));
1183 return;
1184 }
Igor Murashkine363fbb2013-06-25 20:26:06 +00001185
Yin-Chia Yeh0c961162018-01-02 11:17:58 -08001186 Integer oldStatus;
1187 if (status == ICameraServiceListener.STATUS_NOT_PRESENT) {
1188 oldStatus = mDeviceStatus.remove(id);
1189 } else {
1190 oldStatus = mDeviceStatus.put(id, status);
1191 }
Igor Murashkine363fbb2013-06-25 20:26:06 +00001192
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001193 if (oldStatus != null && oldStatus == status) {
1194 if (DEBUG) {
Igor Murashkine363fbb2013-06-25 20:26:06 +00001195 Log.v(TAG, String.format(
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001196 "Device status changed to 0x%x, which is what it already was",
1197 status));
Igor Murashkine363fbb2013-06-25 20:26:06 +00001198 }
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001199 return;
1200 }
Igor Murashkine363fbb2013-06-25 20:26:06 +00001201
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001202 // TODO: consider abstracting out this state minimization + transition
1203 // into a separate
1204 // more easily testable class
1205 // i.e. (new State()).addState(STATE_AVAILABLE)
1206 // .addState(STATE_NOT_AVAILABLE)
1207 // .addTransition(STATUS_PRESENT, STATE_AVAILABLE),
1208 // .addTransition(STATUS_NOT_PRESENT, STATE_NOT_AVAILABLE)
1209 // .addTransition(STATUS_ENUMERATING, STATE_NOT_AVAILABLE);
1210 // .addTransition(STATUS_NOT_AVAILABLE, STATE_NOT_AVAILABLE);
Igor Murashkine363fbb2013-06-25 20:26:06 +00001211
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001212 // Translate all the statuses to either 'available' or 'not available'
1213 // available -> available => no new update
1214 // not available -> not available => no new update
1215 if (oldStatus != null && isAvailable(status) == isAvailable(oldStatus)) {
1216 if (DEBUG) {
Igor Murashkine363fbb2013-06-25 20:26:06 +00001217 Log.v(TAG,
1218 String.format(
Andreas Gampe02ffb2a2015-03-15 14:43:31 -07001219 "Device status was previously available (%b), " +
1220 " and is now again available (%b)" +
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001221 "so no new client visible update will be sent",
Andreas Gampe02ffb2a2015-03-15 14:43:31 -07001222 isAvailable(oldStatus), isAvailable(status)));
Igor Murashkine363fbb2013-06-25 20:26:06 +00001223 }
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001224 return;
1225 }
Igor Murashkine363fbb2013-06-25 20:26:06 +00001226
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001227 final int callbackCount = mCallbackMap.size();
1228 for (int i = 0; i < callbackCount; i++) {
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001229 Executor executor = mCallbackMap.valueAt(i);
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001230 final AvailabilityCallback callback = mCallbackMap.keyAt(i);
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001231
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001232 postSingleUpdate(callback, executor, id, status);
Eino-Ville Talvalabd9b1062014-07-22 11:12:24 -07001233 }
1234 } // onStatusChangedLocked
1235
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001236 private void updateTorchCallbackLocked(TorchCallback callback, Executor executor) {
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001237 for (int i = 0; i < mTorchStatus.size(); i++) {
1238 String id = mTorchStatus.keyAt(i);
1239 Integer status = mTorchStatus.valueAt(i);
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001240 postSingleTorchUpdate(callback, executor, id, status);
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001241 }
1242 }
1243
1244 private void onTorchStatusChangedLocked(int status, String id) {
1245 if (DEBUG) {
1246 Log.v(TAG,
1247 String.format("Camera id %s has torch status changed to 0x%x", id, status));
1248 }
1249
1250 if (!validTorchStatus(status)) {
1251 Log.e(TAG, String.format("Ignoring invalid device %s torch status 0x%x", id,
1252 status));
1253 return;
1254 }
1255
1256 Integer oldStatus = mTorchStatus.put(id, status);
1257 if (oldStatus != null && oldStatus == status) {
1258 if (DEBUG) {
1259 Log.v(TAG, String.format(
1260 "Torch status changed to 0x%x, which is what it already was",
1261 status));
1262 }
1263 return;
1264 }
1265
1266 final int callbackCount = mTorchCallbackMap.size();
1267 for (int i = 0; i < callbackCount; i++) {
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001268 final Executor executor = mTorchCallbackMap.valueAt(i);
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001269 final TorchCallback callback = mTorchCallbackMap.keyAt(i);
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001270 postSingleTorchUpdate(callback, executor, id, status);
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001271 }
1272 } // onTorchStatusChangedLocked
1273
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001274 /**
1275 * Register a callback to be notified about camera device availability with the
1276 * global listener singleton.
1277 *
1278 * @param callback the new callback to send camera availability notices to
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001279 * @param executor The executor which should invoke the callback. May not be null.
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001280 */
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001281 public void registerAvailabilityCallback(AvailabilityCallback callback, Executor executor) {
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001282 synchronized (mLock) {
Eino-Ville Talvala2ef01732015-05-30 17:56:37 -07001283 connectCameraServiceLocked();
1284
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001285 Executor oldExecutor = mCallbackMap.put(callback, executor);
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001286 // For new callbacks, provide initial availability information
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001287 if (oldExecutor == null) {
1288 updateCallbackLocked(callback, executor);
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001289 }
Chien-Yu Chen0ac408e2016-03-17 10:51:25 -07001290
1291 // If not connected to camera service, schedule a reconnect to camera service.
1292 if (mCameraService == null) {
1293 scheduleCameraServiceReconnectionLocked();
1294 }
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001295 }
1296 }
1297
1298 /**
1299 * Remove a previously-added callback; the callback will no longer receive connection and
1300 * disconnection callbacks, and is no longer referenced by the global listener singleton.
1301 *
1302 * @param callback The callback to remove from the notification list
1303 */
1304 public void unregisterAvailabilityCallback(AvailabilityCallback callback) {
1305 synchronized (mLock) {
1306 mCallbackMap.remove(callback);
1307 }
1308 }
1309
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001310 public void registerTorchCallback(TorchCallback callback, Executor executor) {
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001311 synchronized(mLock) {
Eino-Ville Talvala2ef01732015-05-30 17:56:37 -07001312 connectCameraServiceLocked();
1313
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001314 Executor oldExecutor = mTorchCallbackMap.put(callback, executor);
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001315 // For new callbacks, provide initial torch information
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001316 if (oldExecutor == null) {
1317 updateTorchCallbackLocked(callback, executor);
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001318 }
Chien-Yu Chen0ac408e2016-03-17 10:51:25 -07001319
1320 // If not connected to camera service, schedule a reconnect to camera service.
1321 if (mCameraService == null) {
1322 scheduleCameraServiceReconnectionLocked();
1323 }
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001324 }
1325 }
1326
1327 public void unregisterTorchCallback(TorchCallback callback) {
1328 synchronized(mLock) {
1329 mTorchCallbackMap.remove(callback);
1330 }
1331 }
1332
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001333 /**
1334 * Callback from camera service notifying the process about camera availability changes
1335 */
1336 @Override
Eino-Ville Talvala283ae234f2016-12-08 13:38:52 -08001337 public void onStatusChanged(int status, String cameraId) throws RemoteException {
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001338 synchronized(mLock) {
Eino-Ville Talvala283ae234f2016-12-08 13:38:52 -08001339 onStatusChangedLocked(status, cameraId);
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001340 }
1341 }
1342
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001343 @Override
1344 public void onTorchStatusChanged(int status, String cameraId) throws RemoteException {
1345 synchronized (mLock) {
1346 onTorchStatusChangedLocked(status, cameraId);
1347 }
1348 }
1349
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001350 /**
Chien-Yu Chen0f69b462015-07-13 16:37:13 -07001351 * Try to connect to camera service after some delay if any client registered camera
1352 * availability callback or torch status callback.
1353 */
1354 private void scheduleCameraServiceReconnectionLocked() {
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001355 if (mCallbackMap.isEmpty() && mTorchCallbackMap.isEmpty()) {
Chien-Yu Chen0f69b462015-07-13 16:37:13 -07001356 // Not necessary to reconnect camera service if no client registers a callback.
1357 return;
1358 }
1359
1360 if (DEBUG) {
1361 Log.v(TAG, "Reconnecting Camera Service in " + CAMERA_SERVICE_RECONNECT_DELAY_MS +
1362 " ms");
1363 }
1364
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001365 try {
1366 mScheduler.schedule(() -> {
1367 ICameraService cameraService = getCameraService();
1368 if (cameraService == null) {
1369 synchronized(mLock) {
1370 if (DEBUG) {
1371 Log.v(TAG, "Reconnecting Camera Service failed.");
Chien-Yu Chen0f69b462015-07-13 16:37:13 -07001372 }
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001373 scheduleCameraServiceReconnectionLocked();
Chien-Yu Chen0f69b462015-07-13 16:37:13 -07001374 }
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001375 }
1376 }, CAMERA_SERVICE_RECONNECT_DELAY_MS, TimeUnit.MILLISECONDS);
1377 } catch (RejectedExecutionException e) {
1378 Log.e(TAG, "Failed to schedule camera service re-connect: " + e);
1379 }
Chien-Yu Chen0f69b462015-07-13 16:37:13 -07001380 }
1381
1382 /**
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001383 * Listener for camera service death.
1384 *
1385 * <p>The camera service isn't supposed to die under any normal circumstances, but can be
1386 * turned off during debug, or crash due to bugs. So detect that and null out the interface
1387 * object, so that the next calls to the manager can try to reconnect.</p>
1388 */
1389 public void binderDied() {
1390 synchronized(mLock) {
1391 // Only do this once per service death
1392 if (mCameraService == null) return;
1393
1394 mCameraService = null;
1395
Chien-Yu Chen0f69b462015-07-13 16:37:13 -07001396 // Tell listeners that the cameras and torch modes are unavailable and schedule a
1397 // reconnection to camera service. When camera service is reconnected, the camera
1398 // and torch statuses will be updated.
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001399 for (int i = 0; i < mDeviceStatus.size(); i++) {
1400 String cameraId = mDeviceStatus.keyAt(i);
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001401 onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, cameraId);
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001402 }
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001403 for (int i = 0; i < mTorchStatus.size(); i++) {
1404 String cameraId = mTorchStatus.keyAt(i);
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001405 onTorchStatusChangedLocked(ICameraServiceListener.TORCH_STATUS_NOT_AVAILABLE,
1406 cameraId);
Chien-Yu Chenafa91392015-02-11 11:23:28 -08001407 }
1408
Chien-Yu Chen0f69b462015-07-13 16:37:13 -07001409 scheduleCameraServiceReconnectionLocked();
Eino-Ville Talvala4c9c7a52014-10-22 14:39:31 -07001410 }
1411 }
1412
1413 } // CameraManagerGlobal
1414
Igor Murashkine363fbb2013-06-25 20:26:06 +00001415} // CameraManager