Loading core/java/android/hardware/CameraStatus.java +3 −0 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,7 @@ public class CameraStatus implements Parcelable { public String cameraId; public String cameraId; public int status; public int status; public String[] unavailablePhysicalCameras; public String[] unavailablePhysicalCameras; public String clientPackage; @Override @Override public int describeContents() { public int describeContents() { Loading @@ -42,12 +43,14 @@ public class CameraStatus implements Parcelable { out.writeString(cameraId); out.writeString(cameraId); out.writeInt(status); out.writeInt(status); out.writeStringArray(unavailablePhysicalCameras); out.writeStringArray(unavailablePhysicalCameras); out.writeString(clientPackage); } } public void readFromParcel(Parcel in) { public void readFromParcel(Parcel in) { cameraId = in.readString(); cameraId = in.readString(); status = in.readInt(); status = in.readInt(); unavailablePhysicalCameras = in.readStringArray(); unavailablePhysicalCameras = in.readStringArray(); clientPackage = in.readString(); } } public static final @android.annotation.NonNull Parcelable.Creator<CameraStatus> CREATOR = public static final @android.annotation.NonNull Parcelable.Creator<CameraStatus> CREATOR = Loading core/java/android/hardware/camera2/CameraManager.java +75 −14 Original line number Original line Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.SystemService; import android.annotation.TestApi; import android.annotation.TestApi; import android.content.Context; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.CameraStatus; import android.hardware.CameraStatus; import android.hardware.ICameraService; import android.hardware.ICameraService; import android.hardware.ICameraServiceListener; import android.hardware.ICameraServiceListener; Loading Loading @@ -90,12 +91,19 @@ public final class CameraManager { private final Context mContext; private final Context mContext; private final Object mLock = new Object(); private final Object mLock = new Object(); private static final String CAMERA_OPEN_CLOSE_LISTENER_PERMISSION = "android.permission.CAMERA_OPEN_CLOSE_LISTENER"; private final boolean mHasOpenCloseListenerPermission; /** /** * @hide * @hide */ */ public CameraManager(Context context) { public CameraManager(Context context) { synchronized(mLock) { synchronized(mLock) { mContext = context; mContext = context; mHasOpenCloseListenerPermission = mContext.checkSelfPermission(CAMERA_OPEN_CLOSE_LISTENER_PERMISSION) == PackageManager.PERMISSION_GRANTED; } } } } Loading Loading @@ -253,7 +261,7 @@ public final class CameraManager { public void registerAvailabilityCallback(@NonNull AvailabilityCallback callback, public void registerAvailabilityCallback(@NonNull AvailabilityCallback callback, @Nullable Handler handler) { @Nullable Handler handler) { CameraManagerGlobal.get().registerAvailabilityCallback(callback, CameraManagerGlobal.get().registerAvailabilityCallback(callback, CameraDeviceImpl.checkAndWrapHandler(handler)); CameraDeviceImpl.checkAndWrapHandler(handler), mHasOpenCloseListenerPermission); } } /** /** Loading @@ -274,7 +282,8 @@ public final class CameraManager { if (executor == null) { if (executor == null) { throw new IllegalArgumentException("executor was null"); throw new IllegalArgumentException("executor was null"); } } CameraManagerGlobal.get().registerAvailabilityCallback(callback, executor); CameraManagerGlobal.get().registerAvailabilityCallback(callback, executor, mHasOpenCloseListenerPermission); } } /** /** Loading Loading @@ -1303,6 +1312,8 @@ public final class CameraManager { // Camera ID -> (physical camera ID -> Status map) // Camera ID -> (physical camera ID -> Status map) private final ArrayMap<String, ArrayList<String>> mUnavailablePhysicalDevices = private final ArrayMap<String, ArrayList<String>> mUnavailablePhysicalDevices = new ArrayMap<String, ArrayList<String>>(); new ArrayMap<String, ArrayList<String>>(); // Opened Camera ID -> apk name map private final ArrayMap<String, String> mOpenedDevices = new ArrayMap<String, String>(); private final Set<Set<String>> mConcurrentCameraIdCombinations = private final Set<Set<String>> mConcurrentCameraIdCombinations = new ArraySet<Set<String>>(); new ArraySet<Set<String>>(); Loading @@ -1325,6 +1336,7 @@ public final class CameraManager { // Access only through getCameraService to deal with binder death // Access only through getCameraService to deal with binder death private ICameraService mCameraService; private ICameraService mCameraService; private boolean mHasOpenCloseListenerPermission = false; // Singleton, don't allow construction // Singleton, don't allow construction private CameraManagerGlobal() { private CameraManagerGlobal() { Loading Loading @@ -1403,6 +1415,12 @@ public final class CameraManager { c.cameraId, unavailPhysicalCamera); c.cameraId, unavailPhysicalCamera); } } } } if (mHasOpenCloseListenerPermission && c.status == ICameraServiceListener.STATUS_NOT_AVAILABLE && !c.clientPackage.isEmpty()) { onCameraOpenedLocked(c.cameraId, c.clientPackage); } } } mCameraService = cameraService; mCameraService = cameraService; } catch(ServiceSpecificException e) { } catch(ServiceSpecificException e) { Loading Loading @@ -1893,6 +1911,12 @@ public final class CameraManager { ICameraServiceListener.STATUS_NOT_PRESENT); ICameraServiceListener.STATUS_NOT_PRESENT); } } } } } for (int i = 0; i < mOpenedDevices.size(); i++) { String id = mOpenedDevices.keyAt(i); String clientPackageId = mOpenedDevices.valueAt(i); postSingleCameraOpenedUpdate(callback, executor, id, clientPackageId); } } } } Loading Loading @@ -2058,9 +2082,15 @@ public final class CameraManager { * * * @param callback the new callback to send camera availability notices to * @param callback the new callback to send camera availability notices to * @param executor The executor which should invoke the callback. May not be null. * @param executor The executor which should invoke the callback. May not be null. * @param hasOpenCloseListenerPermission whether the client has permission for * onCameraOpened/onCameraClosed callback */ */ public void registerAvailabilityCallback(AvailabilityCallback callback, Executor executor) { public void registerAvailabilityCallback(AvailabilityCallback callback, Executor executor, boolean hasOpenCloseListenerPermission) { synchronized (mLock) { synchronized (mLock) { // In practice, this permission doesn't change. So we don't need one flag for each // callback object. mHasOpenCloseListenerPermission = hasOpenCloseListenerPermission; connectCameraServiceLocked(); connectCameraServiceLocked(); Executor oldExecutor = mCallbackMap.put(callback, executor); Executor oldExecutor = mCallbackMap.put(callback, executor); Loading Loading @@ -2152,6 +2182,28 @@ public final class CameraManager { @Override @Override public void onCameraOpened(String cameraId, String clientPackageId) { public void onCameraOpened(String cameraId, String clientPackageId) { synchronized (mLock) { synchronized (mLock) { onCameraOpenedLocked(cameraId, clientPackageId); } } private void onCameraOpenedLocked(String cameraId, String clientPackageId) { String oldApk = mOpenedDevices.put(cameraId, clientPackageId); if (oldApk != null) { if (oldApk.equals(clientPackageId)) { Log.w(TAG, "onCameraOpened was previously called for " + oldApk + " and is now again called for the same package name, " + "so no new client visible update will be sent"); return; } else { Log.w(TAG, "onCameraOpened was previously called for " + oldApk + " and is now called for " + clientPackageId + " without onCameraClosed being called first"); } } final int callbackCount = mCallbackMap.size(); final int callbackCount = mCallbackMap.size(); for (int i = 0; i < callbackCount; i++) { for (int i = 0; i < callbackCount; i++) { Executor executor = mCallbackMap.valueAt(i); Executor executor = mCallbackMap.valueAt(i); Loading @@ -2160,11 +2212,17 @@ public final class CameraManager { postSingleCameraOpenedUpdate(callback, executor, cameraId, clientPackageId); postSingleCameraOpenedUpdate(callback, executor, cameraId, clientPackageId); } } } } } @Override @Override public void onCameraClosed(String cameraId) { public void onCameraClosed(String cameraId) { synchronized (mLock) { synchronized (mLock) { onCameraClosedLocked(cameraId); } } private void onCameraClosedLocked(String cameraId) { mOpenedDevices.remove(cameraId); final int callbackCount = mCallbackMap.size(); final int callbackCount = mCallbackMap.size(); for (int i = 0; i < callbackCount; i++) { for (int i = 0; i < callbackCount; i++) { Executor executor = mCallbackMap.valueAt(i); Executor executor = mCallbackMap.valueAt(i); Loading @@ -2173,7 +2231,6 @@ public final class CameraManager { postSingleCameraClosedUpdate(callback, executor, cameraId); postSingleCameraClosedUpdate(callback, executor, cameraId); } } } } } /** /** * Try to connect to camera service after some delay if any client registered camera * Try to connect to camera service after some delay if any client registered camera Loading Loading @@ -2229,6 +2286,10 @@ public final class CameraManager { for (int i = mDeviceStatus.size() - 1; i >= 0; i--) { for (int i = mDeviceStatus.size() - 1; i >= 0; i--) { String cameraId = mDeviceStatus.keyAt(i); String cameraId = mDeviceStatus.keyAt(i); onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, cameraId); onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, cameraId); if (mHasOpenCloseListenerPermission) { onCameraClosedLocked(cameraId); } } } for (int i = 0; i < mTorchStatus.size(); i++) { for (int i = 0; i < mTorchStatus.size(); i++) { String cameraId = mTorchStatus.keyAt(i); String cameraId = mTorchStatus.keyAt(i); Loading Loading
core/java/android/hardware/CameraStatus.java +3 −0 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,7 @@ public class CameraStatus implements Parcelable { public String cameraId; public String cameraId; public int status; public int status; public String[] unavailablePhysicalCameras; public String[] unavailablePhysicalCameras; public String clientPackage; @Override @Override public int describeContents() { public int describeContents() { Loading @@ -42,12 +43,14 @@ public class CameraStatus implements Parcelable { out.writeString(cameraId); out.writeString(cameraId); out.writeInt(status); out.writeInt(status); out.writeStringArray(unavailablePhysicalCameras); out.writeStringArray(unavailablePhysicalCameras); out.writeString(clientPackage); } } public void readFromParcel(Parcel in) { public void readFromParcel(Parcel in) { cameraId = in.readString(); cameraId = in.readString(); status = in.readInt(); status = in.readInt(); unavailablePhysicalCameras = in.readStringArray(); unavailablePhysicalCameras = in.readStringArray(); clientPackage = in.readString(); } } public static final @android.annotation.NonNull Parcelable.Creator<CameraStatus> CREATOR = public static final @android.annotation.NonNull Parcelable.Creator<CameraStatus> CREATOR = Loading
core/java/android/hardware/camera2/CameraManager.java +75 −14 Original line number Original line Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.SystemService; import android.annotation.TestApi; import android.annotation.TestApi; import android.content.Context; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.CameraStatus; import android.hardware.CameraStatus; import android.hardware.ICameraService; import android.hardware.ICameraService; import android.hardware.ICameraServiceListener; import android.hardware.ICameraServiceListener; Loading Loading @@ -90,12 +91,19 @@ public final class CameraManager { private final Context mContext; private final Context mContext; private final Object mLock = new Object(); private final Object mLock = new Object(); private static final String CAMERA_OPEN_CLOSE_LISTENER_PERMISSION = "android.permission.CAMERA_OPEN_CLOSE_LISTENER"; private final boolean mHasOpenCloseListenerPermission; /** /** * @hide * @hide */ */ public CameraManager(Context context) { public CameraManager(Context context) { synchronized(mLock) { synchronized(mLock) { mContext = context; mContext = context; mHasOpenCloseListenerPermission = mContext.checkSelfPermission(CAMERA_OPEN_CLOSE_LISTENER_PERMISSION) == PackageManager.PERMISSION_GRANTED; } } } } Loading Loading @@ -253,7 +261,7 @@ public final class CameraManager { public void registerAvailabilityCallback(@NonNull AvailabilityCallback callback, public void registerAvailabilityCallback(@NonNull AvailabilityCallback callback, @Nullable Handler handler) { @Nullable Handler handler) { CameraManagerGlobal.get().registerAvailabilityCallback(callback, CameraManagerGlobal.get().registerAvailabilityCallback(callback, CameraDeviceImpl.checkAndWrapHandler(handler)); CameraDeviceImpl.checkAndWrapHandler(handler), mHasOpenCloseListenerPermission); } } /** /** Loading @@ -274,7 +282,8 @@ public final class CameraManager { if (executor == null) { if (executor == null) { throw new IllegalArgumentException("executor was null"); throw new IllegalArgumentException("executor was null"); } } CameraManagerGlobal.get().registerAvailabilityCallback(callback, executor); CameraManagerGlobal.get().registerAvailabilityCallback(callback, executor, mHasOpenCloseListenerPermission); } } /** /** Loading Loading @@ -1303,6 +1312,8 @@ public final class CameraManager { // Camera ID -> (physical camera ID -> Status map) // Camera ID -> (physical camera ID -> Status map) private final ArrayMap<String, ArrayList<String>> mUnavailablePhysicalDevices = private final ArrayMap<String, ArrayList<String>> mUnavailablePhysicalDevices = new ArrayMap<String, ArrayList<String>>(); new ArrayMap<String, ArrayList<String>>(); // Opened Camera ID -> apk name map private final ArrayMap<String, String> mOpenedDevices = new ArrayMap<String, String>(); private final Set<Set<String>> mConcurrentCameraIdCombinations = private final Set<Set<String>> mConcurrentCameraIdCombinations = new ArraySet<Set<String>>(); new ArraySet<Set<String>>(); Loading @@ -1325,6 +1336,7 @@ public final class CameraManager { // Access only through getCameraService to deal with binder death // Access only through getCameraService to deal with binder death private ICameraService mCameraService; private ICameraService mCameraService; private boolean mHasOpenCloseListenerPermission = false; // Singleton, don't allow construction // Singleton, don't allow construction private CameraManagerGlobal() { private CameraManagerGlobal() { Loading Loading @@ -1403,6 +1415,12 @@ public final class CameraManager { c.cameraId, unavailPhysicalCamera); c.cameraId, unavailPhysicalCamera); } } } } if (mHasOpenCloseListenerPermission && c.status == ICameraServiceListener.STATUS_NOT_AVAILABLE && !c.clientPackage.isEmpty()) { onCameraOpenedLocked(c.cameraId, c.clientPackage); } } } mCameraService = cameraService; mCameraService = cameraService; } catch(ServiceSpecificException e) { } catch(ServiceSpecificException e) { Loading Loading @@ -1893,6 +1911,12 @@ public final class CameraManager { ICameraServiceListener.STATUS_NOT_PRESENT); ICameraServiceListener.STATUS_NOT_PRESENT); } } } } } for (int i = 0; i < mOpenedDevices.size(); i++) { String id = mOpenedDevices.keyAt(i); String clientPackageId = mOpenedDevices.valueAt(i); postSingleCameraOpenedUpdate(callback, executor, id, clientPackageId); } } } } Loading Loading @@ -2058,9 +2082,15 @@ public final class CameraManager { * * * @param callback the new callback to send camera availability notices to * @param callback the new callback to send camera availability notices to * @param executor The executor which should invoke the callback. May not be null. * @param executor The executor which should invoke the callback. May not be null. * @param hasOpenCloseListenerPermission whether the client has permission for * onCameraOpened/onCameraClosed callback */ */ public void registerAvailabilityCallback(AvailabilityCallback callback, Executor executor) { public void registerAvailabilityCallback(AvailabilityCallback callback, Executor executor, boolean hasOpenCloseListenerPermission) { synchronized (mLock) { synchronized (mLock) { // In practice, this permission doesn't change. So we don't need one flag for each // callback object. mHasOpenCloseListenerPermission = hasOpenCloseListenerPermission; connectCameraServiceLocked(); connectCameraServiceLocked(); Executor oldExecutor = mCallbackMap.put(callback, executor); Executor oldExecutor = mCallbackMap.put(callback, executor); Loading Loading @@ -2152,6 +2182,28 @@ public final class CameraManager { @Override @Override public void onCameraOpened(String cameraId, String clientPackageId) { public void onCameraOpened(String cameraId, String clientPackageId) { synchronized (mLock) { synchronized (mLock) { onCameraOpenedLocked(cameraId, clientPackageId); } } private void onCameraOpenedLocked(String cameraId, String clientPackageId) { String oldApk = mOpenedDevices.put(cameraId, clientPackageId); if (oldApk != null) { if (oldApk.equals(clientPackageId)) { Log.w(TAG, "onCameraOpened was previously called for " + oldApk + " and is now again called for the same package name, " + "so no new client visible update will be sent"); return; } else { Log.w(TAG, "onCameraOpened was previously called for " + oldApk + " and is now called for " + clientPackageId + " without onCameraClosed being called first"); } } final int callbackCount = mCallbackMap.size(); final int callbackCount = mCallbackMap.size(); for (int i = 0; i < callbackCount; i++) { for (int i = 0; i < callbackCount; i++) { Executor executor = mCallbackMap.valueAt(i); Executor executor = mCallbackMap.valueAt(i); Loading @@ -2160,11 +2212,17 @@ public final class CameraManager { postSingleCameraOpenedUpdate(callback, executor, cameraId, clientPackageId); postSingleCameraOpenedUpdate(callback, executor, cameraId, clientPackageId); } } } } } @Override @Override public void onCameraClosed(String cameraId) { public void onCameraClosed(String cameraId) { synchronized (mLock) { synchronized (mLock) { onCameraClosedLocked(cameraId); } } private void onCameraClosedLocked(String cameraId) { mOpenedDevices.remove(cameraId); final int callbackCount = mCallbackMap.size(); final int callbackCount = mCallbackMap.size(); for (int i = 0; i < callbackCount; i++) { for (int i = 0; i < callbackCount; i++) { Executor executor = mCallbackMap.valueAt(i); Executor executor = mCallbackMap.valueAt(i); Loading @@ -2173,7 +2231,6 @@ public final class CameraManager { postSingleCameraClosedUpdate(callback, executor, cameraId); postSingleCameraClosedUpdate(callback, executor, cameraId); } } } } } /** /** * Try to connect to camera service after some delay if any client registered camera * Try to connect to camera service after some delay if any client registered camera Loading Loading @@ -2229,6 +2286,10 @@ public final class CameraManager { for (int i = mDeviceStatus.size() - 1; i >= 0; i--) { for (int i = mDeviceStatus.size() - 1; i >= 0; i--) { String cameraId = mDeviceStatus.keyAt(i); String cameraId = mDeviceStatus.keyAt(i); onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, cameraId); onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, cameraId); if (mHasOpenCloseListenerPermission) { onCameraClosedLocked(cameraId); } } } for (int i = 0; i < mTorchStatus.size(); i++) { for (int i = 0; i < mTorchStatus.size(); i++) { String cameraId = mTorchStatus.keyAt(i); String cameraId = mTorchStatus.keyAt(i); Loading