Loading core/java/android/hardware/ISensorPrivacyListener.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,6 @@ oneway interface ISensorPrivacyListener { // the ones in // frameworks/native/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl // =============== Beginning of transactions used on native side as well ====================== void onSensorPrivacyChanged(boolean enabled); void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled); // =============== End of transactions used on native side as well ============================ } core/java/android/hardware/ISensorPrivacyManager.aidl +9 −12 Original line number Diff line number Diff line Loading @@ -24,34 +24,31 @@ interface ISensorPrivacyManager { // the ones in // frameworks/native/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl // =============== Beginning of transactions used on native side as well ====================== boolean supportsSensorToggle(int sensor); boolean supportsSensorToggle(int toggleType, int sensor); void addSensorPrivacyListener(in ISensorPrivacyListener listener); void addIndividualSensorPrivacyListener(int userId, int sensor, in ISensorPrivacyListener listener); void addToggleSensorPrivacyListener(in ISensorPrivacyListener listener); void removeSensorPrivacyListener(in ISensorPrivacyListener listener); void removeIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener); void removeToggleSensorPrivacyListener(in ISensorPrivacyListener listener); boolean isSensorPrivacyEnabled(); boolean isIndividualSensorPrivacyEnabled(int userId, int sensor); boolean isCombinedToggleSensorPrivacyEnabled(int sensor); boolean isToggleSensorPrivacyEnabled(int toggleType, int sensor); void setSensorPrivacy(boolean enable); void setIndividualSensorPrivacy(int userId, int source, int sensor, boolean enable); void setToggleSensorPrivacy(int userId, int source, int sensor, boolean enable); void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable); void setToggleSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable); // =============== End of transactions used on native side as well ============================ void suppressIndividualSensorPrivacyReminders(int userId, int sensor, IBinder token, void suppressToggleSensorPrivacyReminders(int userId, int sensor, IBinder token, boolean suppress); void addUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener); void removeUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener); void showSensorUseDialog(int sensor); } No newline at end of file core/java/android/hardware/SensorPrivacyManager.java +229 −71 Original line number Diff line number Diff line Loading @@ -36,7 +36,6 @@ import android.service.SensorPrivacyToggleSourceProto; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -73,8 +72,6 @@ public final class SensorPrivacyManager { public static final String EXTRA_ALL_SENSORS = SensorPrivacyManager.class.getName() + ".extra.all_sensors"; private final SparseArray<Boolean> mToggleSupportCache = new SparseArray<>(); /** * Sensor constants which are used in {@link SensorPrivacyManager} */ Loading Loading @@ -241,8 +238,55 @@ public final class SensorPrivacyManager { void onSensorPrivacyChanged(int sensor, boolean enabled); } /** * A class implementing this interface can register with the {@link * android.hardware.SensorPrivacyManager} to receive notification when the sensor privacy * state changes. * * @hide */ public interface OnToggleSensorPrivacyChangedListener { /** * A class containing information about what the sensor privacy state has changed to. */ class SensorPrivacyChangedParams { private int mToggleType; private int mSensor; private boolean mEnabled; private SensorPrivacyChangedParams(int toggleType, int sensor, boolean enabled) { mToggleType = toggleType; mSensor = sensor; mEnabled = enabled; } public @ToggleTypes.ToggleType int getToggleType() { return mToggleType; } public @Sensors.Sensor int getSensor() { return mSensor; } public boolean isEnabled() { return mEnabled; } } /** * Callback invoked when the sensor privacy state changes. * * @param params Parameters describing the new state */ void onSensorPrivacyChanged(@NonNull SensorPrivacyChangedParams params); } private static final Object sInstanceLock = new Object(); private final Object mLock = new Object(); @GuardedBy("sInstanceLock") private static SensorPrivacyManager sInstance; Loading @@ -252,12 +296,46 @@ public final class SensorPrivacyManager { @NonNull private final ISensorPrivacyManager mService; @GuardedBy("mLock") private final ArrayMap<Pair<Integer, Integer>, Boolean> mToggleSupportCache = new ArrayMap<>(); @NonNull private final ArrayMap<OnAllSensorPrivacyChangedListener, ISensorPrivacyListener> mListeners; /** Registered listeners */ @GuardedBy("mLock") @NonNull private final ArrayMap<OnToggleSensorPrivacyChangedListener, Executor> mToggleListeners = new ArrayMap<>(); /** Listeners registered using the deprecated APIs and which * OnToggleSensorPrivacyChangedListener they're using. */ @GuardedBy("mLock") @NonNull private final ArrayMap<Pair<Integer, OnSensorPrivacyChangedListener>, OnToggleSensorPrivacyChangedListener> mLegacyToggleListeners = new ArrayMap<>(); /** The singleton ISensorPrivacyListener for IPC which will be used to dispatch to local * listeners */ @NonNull private final ISensorPrivacyListener mIToggleListener = new ISensorPrivacyListener.Stub() { @Override public void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled) { synchronized (mLock) { for (int i = 0; i < mToggleListeners.size(); i++) { OnToggleSensorPrivacyChangedListener listener = mToggleListeners.keyAt(i); mToggleListeners.valueAt(i).execute(() -> listener .onSensorPrivacyChanged(new OnToggleSensorPrivacyChangedListener .SensorPrivacyChangedParams(toggleType, sensor, enabled))); } } } }; /** Whether the singleton ISensorPrivacyListener has been registered */ @GuardedBy("mLock") @NonNull private final ArrayMap<Pair<OnSensorPrivacyChangedListener, Integer>, ISensorPrivacyListener> mIndividualListeners; private boolean mToggleListenerRegistered = false; /** * Private constructor to ensure only a single instance is created. Loading @@ -266,7 +344,6 @@ public final class SensorPrivacyManager { mContext = context; mService = service; mListeners = new ArrayMap<>(); mIndividualListeners = new ArrayMap<>(); } /** Loading Loading @@ -295,19 +372,35 @@ public final class SensorPrivacyManager { * @return whether the toggle for the sensor is supported on this device. */ public boolean supportsSensorToggle(@Sensors.Sensor int sensor) { return supportsSensorToggle(ToggleTypes.SOFTWARE, sensor); } /** * Checks if the given toggle is supported on this device * @param sensor The sensor to check * @return whether the toggle for the sensor is supported on this device. * * @hide */ public boolean supportsSensorToggle(@ToggleTypes.ToggleType int toggleType, @Sensors.Sensor int sensor) { try { Boolean val = mToggleSupportCache.get(sensor); Pair key = new Pair(toggleType, sensor); synchronized (mLock) { Boolean val = mToggleSupportCache.get(key); if (val == null) { val = mService.supportsSensorToggle(sensor); mToggleSupportCache.put(sensor, val); val = mService.supportsSensorToggle(toggleType, sensor); mToggleSupportCache.put(key, val); } return val; } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * Loading @@ -315,6 +408,8 @@ public final class SensorPrivacyManager { * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor * privacy changes. * * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} * * @hide */ @SystemApi Loading @@ -325,6 +420,7 @@ public final class SensorPrivacyManager { } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * Loading @@ -333,15 +429,18 @@ public final class SensorPrivacyManager { * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor * privacy changes. * * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @UserIdInt int userId, public void addSensorPrivacyListener(@Sensors.Sensor int sensor, int userId, @NonNull OnSensorPrivacyChangedListener listener) { addSensorPrivacyListener(sensor, userId, mContext.getMainExecutor(), listener); addSensorPrivacyListener(sensor, mContext.getMainExecutor(), listener); } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * Loading @@ -350,67 +449,77 @@ public final class SensorPrivacyManager { * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor * privacy changes. * * {@link #addSensorPrivacyListener(Executor, OnToggleSensorPrivacyChangedListener)} * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull Executor executor, @NonNull OnSensorPrivacyChangedListener listener) { Pair<OnSensorPrivacyChangedListener, Integer> key = new Pair<>(listener, sensor); synchronized (mIndividualListeners) { ISensorPrivacyListener iListener = mIndividualListeners.get(key); if (iListener == null) { iListener = new ISensorPrivacyListener.Stub() { @Override public void onSensorPrivacyChanged(boolean enabled) { executor.execute(() -> listener.onSensorPrivacyChanged(sensor, enabled)); Pair<Integer, OnSensorPrivacyChangedListener> pair = new Pair(sensor, listener); OnToggleSensorPrivacyChangedListener toggleListener = params -> { if (params.getSensor() == sensor) { listener.onSensorPrivacyChanged(params.getSensor(), params.isEnabled()); } }; mIndividualListeners.put(key, iListener); } try { mService.addUserGlobalIndividualSensorPrivacyListener(sensor, iListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); synchronized (mLock) { mLegacyToggleListeners.put(pair, toggleListener); addSensorPrivacyListenerLocked(executor, toggleListener); } } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * * @param listener the OnToggleSensorPrivacyChangedListener to be notified when the state of * sensor privacy changes. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(@NonNull OnToggleSensorPrivacyChangedListener listener) { addSensorPrivacyListener(mContext.getMainExecutor(), listener); } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * * @param sensor the sensor to listen to changes to * @param executor the executor to dispatch the callback on * @param userId the user's id * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor * privacy changes. * @param listener the OnToggleSensorPrivacyChangedListener to be notified when the state of * sensor privacy changes. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @UserIdInt int userId, @NonNull Executor executor, @NonNull OnSensorPrivacyChangedListener listener) { synchronized (mIndividualListeners) { ISensorPrivacyListener iListener = mIndividualListeners.get(listener); if (iListener == null) { iListener = new ISensorPrivacyListener.Stub() { @Override public void onSensorPrivacyChanged(boolean enabled) { executor.execute(() -> listener.onSensorPrivacyChanged(sensor, enabled)); public void addSensorPrivacyListener(@NonNull Executor executor, @NonNull OnToggleSensorPrivacyChangedListener listener) { synchronized (mLock) { addSensorPrivacyListenerLocked(executor, listener); } }; mIndividualListeners.put(new Pair<>(listener, sensor), iListener); } @GuardedBy("mLock") private void addSensorPrivacyListenerLocked(@NonNull Executor executor, @NonNull OnToggleSensorPrivacyChangedListener listener) { if (!mToggleListenerRegistered) { try { mService.addIndividualSensorPrivacyListener(userId, sensor, iListener); mService.addToggleSensorPrivacyListener(mIToggleListener); mToggleListenerRegistered = true; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); e.rethrowFromSystemServer(); } } if (mToggleListeners.containsKey(listener)) { throw new IllegalArgumentException("listener is already registered"); } mToggleListeners.put(listener, executor); } /** Loading @@ -420,30 +529,60 @@ public final class SensorPrivacyManager { * @param listener the OnSensorPrivacyChangedListener to be unregistered from notifications when * sensor privacy changes. * * {@link #removeSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} with * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} or * {@link #addSensorPrivacyListener(Executor, OnToggleSensorPrivacyChangedListener)} * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull OnSensorPrivacyChangedListener listener) { synchronized (mListeners) { for (int i = 0; i < mIndividualListeners.size(); i++) { Pair<OnSensorPrivacyChangedListener, Integer> pair = mIndividualListeners.keyAt(i); if (pair.second == sensor && pair.first.equals(listener)) { try { mService.removeIndividualSensorPrivacyListener(sensor, mIndividualListeners.valueAt(i)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); Pair<Integer, OnSensorPrivacyChangedListener> pair = new Pair(sensor, listener); synchronized (mLock) { OnToggleSensorPrivacyChangedListener onToggleSensorPrivacyChangedListener = mLegacyToggleListeners.remove(pair); if (onToggleSensorPrivacyChangedListener != null) { removeSensorPrivacyListenerLocked(onToggleSensorPrivacyChangedListener); } } } /** * Unregisters the specified listener from receiving notifications when the state of any sensor * privacy changes. * * @param listener the {@link OnToggleSensorPrivacyChangedListener} to be unregistered from * notifications when sensor privacy changes. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeSensorPrivacyListener( @NonNull OnToggleSensorPrivacyChangedListener listener) { synchronized (mLock) { removeSensorPrivacyListenerLocked(listener); } mIndividualListeners.removeAt(i--); } @GuardedBy("mLock") private void removeSensorPrivacyListenerLocked( @NonNull OnToggleSensorPrivacyChangedListener listener) { mToggleListeners.remove(listener); if (mToggleListeners.size() == 0) { try { mService.removeToggleSensorPrivacyListener(mIToggleListener); mToggleListenerRegistered = false; } catch (RemoteException e) { e.rethrowFromSystemServer(); } } } /** * Returns whether sensor privacy is currently enabled for a specific sensor. * Returns whether sensor privacy is currently enabled by software control for a specific * sensor. * * @return true if sensor privacy is currently enabled, false otherwise. * Loading @@ -452,20 +591,38 @@ public final class SensorPrivacyManager { @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor) { return isSensorPrivacyEnabled(sensor, UserHandle.USER_CURRENT); return isSensorPrivacyEnabled(ToggleTypes.SOFTWARE, sensor); } /** * Returns whether sensor privacy is currently enabled for a specific sensor. * * @return true if sensor privacy is currently enabled, false otherwise. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(@ToggleTypes.ToggleType int toggleType, @Sensors.Sensor int sensor) { try { return mService.isToggleSensorPrivacyEnabled(toggleType, sensor); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns whether sensor privacy is currently enabled for a specific sensor. * Combines the state of the SW + HW toggles and returns the actual privacy state. * * @return true if sensor privacy is currently enabled, false otherwise. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor, @UserIdInt int userId) { public boolean isToggleSensorPrivacyEnabled(@Sensors.Sensor int sensor) { try { return mService.isIndividualSensorPrivacyEnabled(userId, sensor); return mService.isCombinedToggleSensorPrivacyEnabled(sensor); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading Loading @@ -524,7 +681,7 @@ public final class SensorPrivacyManager { public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor, boolean enable, @UserIdInt int userId) { try { mService.setIndividualSensorPrivacy(userId, source, sensor, enable); mService.setToggleSensorPrivacy(userId, source, sensor, enable); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading Loading @@ -561,7 +718,7 @@ public final class SensorPrivacyManager { public void setSensorPrivacyForProfileGroup(@Sources.Source int source, @Sensors.Sensor int sensor, boolean enable, @UserIdInt int userId) { try { mService.setIndividualSensorPrivacyForProfileGroup(userId, source, sensor, enable); mService.setToggleSensorPrivacyForProfileGroup(userId, source, sensor, enable); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading Loading @@ -592,7 +749,7 @@ public final class SensorPrivacyManager { public void suppressSensorPrivacyReminders(int sensor, boolean suppress, @UserIdInt int userId) { try { mService.suppressIndividualSensorPrivacyReminders(userId, sensor, mService.suppressToggleSensorPrivacyReminders(userId, sensor, token, suppress); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); Loading Loading @@ -667,7 +824,8 @@ public final class SensorPrivacyManager { if (iListener == null) { iListener = new ISensorPrivacyListener.Stub() { @Override public void onSensorPrivacyChanged(boolean enabled) { public void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled) { listener.onAllSensorPrivacyChanged(enabled); } }; Loading core/res/res/values/config.xml +5 −1 Original line number Diff line number Diff line Loading @@ -5473,10 +5473,14 @@ <!-- On-device package for providing companion device associations. --> <string name="config_systemCompanionDeviceProvider" translatable="false"></string> <!-- Whether this device is supporting the microphone toggle --> <!-- Whether this device is supporting the software microphone toggle --> <bool name="config_supportsMicToggle">false</bool> <!-- Whether this device is supporting the camera toggle --> <bool name="config_supportsCamToggle">false</bool> <!-- Whether this device is supporting the hardware microphone toggle --> <bool name="config_supportsHardwareMicToggle">false</bool> <!-- Whether this device is supporting the hardware camera toggle --> <bool name="config_supportsHardwareCamToggle">false</bool> <!-- List containing the allowed install sources for accessibility service. --> <string-array name="config_accessibility_allowed_install_source" translatable="false"/> Loading core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -4649,6 +4649,8 @@ <java-symbol type="bool" name="config_supportsMicToggle" /> <java-symbol type="bool" name="config_supportsCamToggle" /> <java-symbol type="bool" name="config_supportsHardwareMicToggle" /> <java-symbol type="bool" name="config_supportsHardwareCamToggle" /> <java-symbol type="dimen" name="starting_surface_icon_size" /> <java-symbol type="dimen" name="starting_surface_default_icon_size" /> Loading Loading
core/java/android/hardware/ISensorPrivacyListener.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,6 @@ oneway interface ISensorPrivacyListener { // the ones in // frameworks/native/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl // =============== Beginning of transactions used on native side as well ====================== void onSensorPrivacyChanged(boolean enabled); void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled); // =============== End of transactions used on native side as well ============================ }
core/java/android/hardware/ISensorPrivacyManager.aidl +9 −12 Original line number Diff line number Diff line Loading @@ -24,34 +24,31 @@ interface ISensorPrivacyManager { // the ones in // frameworks/native/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl // =============== Beginning of transactions used on native side as well ====================== boolean supportsSensorToggle(int sensor); boolean supportsSensorToggle(int toggleType, int sensor); void addSensorPrivacyListener(in ISensorPrivacyListener listener); void addIndividualSensorPrivacyListener(int userId, int sensor, in ISensorPrivacyListener listener); void addToggleSensorPrivacyListener(in ISensorPrivacyListener listener); void removeSensorPrivacyListener(in ISensorPrivacyListener listener); void removeIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener); void removeToggleSensorPrivacyListener(in ISensorPrivacyListener listener); boolean isSensorPrivacyEnabled(); boolean isIndividualSensorPrivacyEnabled(int userId, int sensor); boolean isCombinedToggleSensorPrivacyEnabled(int sensor); boolean isToggleSensorPrivacyEnabled(int toggleType, int sensor); void setSensorPrivacy(boolean enable); void setIndividualSensorPrivacy(int userId, int source, int sensor, boolean enable); void setToggleSensorPrivacy(int userId, int source, int sensor, boolean enable); void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable); void setToggleSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable); // =============== End of transactions used on native side as well ============================ void suppressIndividualSensorPrivacyReminders(int userId, int sensor, IBinder token, void suppressToggleSensorPrivacyReminders(int userId, int sensor, IBinder token, boolean suppress); void addUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener); void removeUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener); void showSensorUseDialog(int sensor); } No newline at end of file
core/java/android/hardware/SensorPrivacyManager.java +229 −71 Original line number Diff line number Diff line Loading @@ -36,7 +36,6 @@ import android.service.SensorPrivacyToggleSourceProto; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -73,8 +72,6 @@ public final class SensorPrivacyManager { public static final String EXTRA_ALL_SENSORS = SensorPrivacyManager.class.getName() + ".extra.all_sensors"; private final SparseArray<Boolean> mToggleSupportCache = new SparseArray<>(); /** * Sensor constants which are used in {@link SensorPrivacyManager} */ Loading Loading @@ -241,8 +238,55 @@ public final class SensorPrivacyManager { void onSensorPrivacyChanged(int sensor, boolean enabled); } /** * A class implementing this interface can register with the {@link * android.hardware.SensorPrivacyManager} to receive notification when the sensor privacy * state changes. * * @hide */ public interface OnToggleSensorPrivacyChangedListener { /** * A class containing information about what the sensor privacy state has changed to. */ class SensorPrivacyChangedParams { private int mToggleType; private int mSensor; private boolean mEnabled; private SensorPrivacyChangedParams(int toggleType, int sensor, boolean enabled) { mToggleType = toggleType; mSensor = sensor; mEnabled = enabled; } public @ToggleTypes.ToggleType int getToggleType() { return mToggleType; } public @Sensors.Sensor int getSensor() { return mSensor; } public boolean isEnabled() { return mEnabled; } } /** * Callback invoked when the sensor privacy state changes. * * @param params Parameters describing the new state */ void onSensorPrivacyChanged(@NonNull SensorPrivacyChangedParams params); } private static final Object sInstanceLock = new Object(); private final Object mLock = new Object(); @GuardedBy("sInstanceLock") private static SensorPrivacyManager sInstance; Loading @@ -252,12 +296,46 @@ public final class SensorPrivacyManager { @NonNull private final ISensorPrivacyManager mService; @GuardedBy("mLock") private final ArrayMap<Pair<Integer, Integer>, Boolean> mToggleSupportCache = new ArrayMap<>(); @NonNull private final ArrayMap<OnAllSensorPrivacyChangedListener, ISensorPrivacyListener> mListeners; /** Registered listeners */ @GuardedBy("mLock") @NonNull private final ArrayMap<OnToggleSensorPrivacyChangedListener, Executor> mToggleListeners = new ArrayMap<>(); /** Listeners registered using the deprecated APIs and which * OnToggleSensorPrivacyChangedListener they're using. */ @GuardedBy("mLock") @NonNull private final ArrayMap<Pair<Integer, OnSensorPrivacyChangedListener>, OnToggleSensorPrivacyChangedListener> mLegacyToggleListeners = new ArrayMap<>(); /** The singleton ISensorPrivacyListener for IPC which will be used to dispatch to local * listeners */ @NonNull private final ISensorPrivacyListener mIToggleListener = new ISensorPrivacyListener.Stub() { @Override public void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled) { synchronized (mLock) { for (int i = 0; i < mToggleListeners.size(); i++) { OnToggleSensorPrivacyChangedListener listener = mToggleListeners.keyAt(i); mToggleListeners.valueAt(i).execute(() -> listener .onSensorPrivacyChanged(new OnToggleSensorPrivacyChangedListener .SensorPrivacyChangedParams(toggleType, sensor, enabled))); } } } }; /** Whether the singleton ISensorPrivacyListener has been registered */ @GuardedBy("mLock") @NonNull private final ArrayMap<Pair<OnSensorPrivacyChangedListener, Integer>, ISensorPrivacyListener> mIndividualListeners; private boolean mToggleListenerRegistered = false; /** * Private constructor to ensure only a single instance is created. Loading @@ -266,7 +344,6 @@ public final class SensorPrivacyManager { mContext = context; mService = service; mListeners = new ArrayMap<>(); mIndividualListeners = new ArrayMap<>(); } /** Loading Loading @@ -295,19 +372,35 @@ public final class SensorPrivacyManager { * @return whether the toggle for the sensor is supported on this device. */ public boolean supportsSensorToggle(@Sensors.Sensor int sensor) { return supportsSensorToggle(ToggleTypes.SOFTWARE, sensor); } /** * Checks if the given toggle is supported on this device * @param sensor The sensor to check * @return whether the toggle for the sensor is supported on this device. * * @hide */ public boolean supportsSensorToggle(@ToggleTypes.ToggleType int toggleType, @Sensors.Sensor int sensor) { try { Boolean val = mToggleSupportCache.get(sensor); Pair key = new Pair(toggleType, sensor); synchronized (mLock) { Boolean val = mToggleSupportCache.get(key); if (val == null) { val = mService.supportsSensorToggle(sensor); mToggleSupportCache.put(sensor, val); val = mService.supportsSensorToggle(toggleType, sensor); mToggleSupportCache.put(key, val); } return val; } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * Loading @@ -315,6 +408,8 @@ public final class SensorPrivacyManager { * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor * privacy changes. * * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} * * @hide */ @SystemApi Loading @@ -325,6 +420,7 @@ public final class SensorPrivacyManager { } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * Loading @@ -333,15 +429,18 @@ public final class SensorPrivacyManager { * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor * privacy changes. * * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @UserIdInt int userId, public void addSensorPrivacyListener(@Sensors.Sensor int sensor, int userId, @NonNull OnSensorPrivacyChangedListener listener) { addSensorPrivacyListener(sensor, userId, mContext.getMainExecutor(), listener); addSensorPrivacyListener(sensor, mContext.getMainExecutor(), listener); } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * Loading @@ -350,67 +449,77 @@ public final class SensorPrivacyManager { * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor * privacy changes. * * {@link #addSensorPrivacyListener(Executor, OnToggleSensorPrivacyChangedListener)} * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull Executor executor, @NonNull OnSensorPrivacyChangedListener listener) { Pair<OnSensorPrivacyChangedListener, Integer> key = new Pair<>(listener, sensor); synchronized (mIndividualListeners) { ISensorPrivacyListener iListener = mIndividualListeners.get(key); if (iListener == null) { iListener = new ISensorPrivacyListener.Stub() { @Override public void onSensorPrivacyChanged(boolean enabled) { executor.execute(() -> listener.onSensorPrivacyChanged(sensor, enabled)); Pair<Integer, OnSensorPrivacyChangedListener> pair = new Pair(sensor, listener); OnToggleSensorPrivacyChangedListener toggleListener = params -> { if (params.getSensor() == sensor) { listener.onSensorPrivacyChanged(params.getSensor(), params.isEnabled()); } }; mIndividualListeners.put(key, iListener); } try { mService.addUserGlobalIndividualSensorPrivacyListener(sensor, iListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); synchronized (mLock) { mLegacyToggleListeners.put(pair, toggleListener); addSensorPrivacyListenerLocked(executor, toggleListener); } } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * * @param listener the OnToggleSensorPrivacyChangedListener to be notified when the state of * sensor privacy changes. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(@NonNull OnToggleSensorPrivacyChangedListener listener) { addSensorPrivacyListener(mContext.getMainExecutor(), listener); } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * * @param sensor the sensor to listen to changes to * @param executor the executor to dispatch the callback on * @param userId the user's id * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor * privacy changes. * @param listener the OnToggleSensorPrivacyChangedListener to be notified when the state of * sensor privacy changes. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @UserIdInt int userId, @NonNull Executor executor, @NonNull OnSensorPrivacyChangedListener listener) { synchronized (mIndividualListeners) { ISensorPrivacyListener iListener = mIndividualListeners.get(listener); if (iListener == null) { iListener = new ISensorPrivacyListener.Stub() { @Override public void onSensorPrivacyChanged(boolean enabled) { executor.execute(() -> listener.onSensorPrivacyChanged(sensor, enabled)); public void addSensorPrivacyListener(@NonNull Executor executor, @NonNull OnToggleSensorPrivacyChangedListener listener) { synchronized (mLock) { addSensorPrivacyListenerLocked(executor, listener); } }; mIndividualListeners.put(new Pair<>(listener, sensor), iListener); } @GuardedBy("mLock") private void addSensorPrivacyListenerLocked(@NonNull Executor executor, @NonNull OnToggleSensorPrivacyChangedListener listener) { if (!mToggleListenerRegistered) { try { mService.addIndividualSensorPrivacyListener(userId, sensor, iListener); mService.addToggleSensorPrivacyListener(mIToggleListener); mToggleListenerRegistered = true; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); e.rethrowFromSystemServer(); } } if (mToggleListeners.containsKey(listener)) { throw new IllegalArgumentException("listener is already registered"); } mToggleListeners.put(listener, executor); } /** Loading @@ -420,30 +529,60 @@ public final class SensorPrivacyManager { * @param listener the OnSensorPrivacyChangedListener to be unregistered from notifications when * sensor privacy changes. * * {@link #removeSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} with * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} or * {@link #addSensorPrivacyListener(Executor, OnToggleSensorPrivacyChangedListener)} * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull OnSensorPrivacyChangedListener listener) { synchronized (mListeners) { for (int i = 0; i < mIndividualListeners.size(); i++) { Pair<OnSensorPrivacyChangedListener, Integer> pair = mIndividualListeners.keyAt(i); if (pair.second == sensor && pair.first.equals(listener)) { try { mService.removeIndividualSensorPrivacyListener(sensor, mIndividualListeners.valueAt(i)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); Pair<Integer, OnSensorPrivacyChangedListener> pair = new Pair(sensor, listener); synchronized (mLock) { OnToggleSensorPrivacyChangedListener onToggleSensorPrivacyChangedListener = mLegacyToggleListeners.remove(pair); if (onToggleSensorPrivacyChangedListener != null) { removeSensorPrivacyListenerLocked(onToggleSensorPrivacyChangedListener); } } } /** * Unregisters the specified listener from receiving notifications when the state of any sensor * privacy changes. * * @param listener the {@link OnToggleSensorPrivacyChangedListener} to be unregistered from * notifications when sensor privacy changes. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeSensorPrivacyListener( @NonNull OnToggleSensorPrivacyChangedListener listener) { synchronized (mLock) { removeSensorPrivacyListenerLocked(listener); } mIndividualListeners.removeAt(i--); } @GuardedBy("mLock") private void removeSensorPrivacyListenerLocked( @NonNull OnToggleSensorPrivacyChangedListener listener) { mToggleListeners.remove(listener); if (mToggleListeners.size() == 0) { try { mService.removeToggleSensorPrivacyListener(mIToggleListener); mToggleListenerRegistered = false; } catch (RemoteException e) { e.rethrowFromSystemServer(); } } } /** * Returns whether sensor privacy is currently enabled for a specific sensor. * Returns whether sensor privacy is currently enabled by software control for a specific * sensor. * * @return true if sensor privacy is currently enabled, false otherwise. * Loading @@ -452,20 +591,38 @@ public final class SensorPrivacyManager { @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor) { return isSensorPrivacyEnabled(sensor, UserHandle.USER_CURRENT); return isSensorPrivacyEnabled(ToggleTypes.SOFTWARE, sensor); } /** * Returns whether sensor privacy is currently enabled for a specific sensor. * * @return true if sensor privacy is currently enabled, false otherwise. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(@ToggleTypes.ToggleType int toggleType, @Sensors.Sensor int sensor) { try { return mService.isToggleSensorPrivacyEnabled(toggleType, sensor); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns whether sensor privacy is currently enabled for a specific sensor. * Combines the state of the SW + HW toggles and returns the actual privacy state. * * @return true if sensor privacy is currently enabled, false otherwise. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor, @UserIdInt int userId) { public boolean isToggleSensorPrivacyEnabled(@Sensors.Sensor int sensor) { try { return mService.isIndividualSensorPrivacyEnabled(userId, sensor); return mService.isCombinedToggleSensorPrivacyEnabled(sensor); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading Loading @@ -524,7 +681,7 @@ public final class SensorPrivacyManager { public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor, boolean enable, @UserIdInt int userId) { try { mService.setIndividualSensorPrivacy(userId, source, sensor, enable); mService.setToggleSensorPrivacy(userId, source, sensor, enable); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading Loading @@ -561,7 +718,7 @@ public final class SensorPrivacyManager { public void setSensorPrivacyForProfileGroup(@Sources.Source int source, @Sensors.Sensor int sensor, boolean enable, @UserIdInt int userId) { try { mService.setIndividualSensorPrivacyForProfileGroup(userId, source, sensor, enable); mService.setToggleSensorPrivacyForProfileGroup(userId, source, sensor, enable); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading Loading @@ -592,7 +749,7 @@ public final class SensorPrivacyManager { public void suppressSensorPrivacyReminders(int sensor, boolean suppress, @UserIdInt int userId) { try { mService.suppressIndividualSensorPrivacyReminders(userId, sensor, mService.suppressToggleSensorPrivacyReminders(userId, sensor, token, suppress); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); Loading Loading @@ -667,7 +824,8 @@ public final class SensorPrivacyManager { if (iListener == null) { iListener = new ISensorPrivacyListener.Stub() { @Override public void onSensorPrivacyChanged(boolean enabled) { public void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled) { listener.onAllSensorPrivacyChanged(enabled); } }; Loading
core/res/res/values/config.xml +5 −1 Original line number Diff line number Diff line Loading @@ -5473,10 +5473,14 @@ <!-- On-device package for providing companion device associations. --> <string name="config_systemCompanionDeviceProvider" translatable="false"></string> <!-- Whether this device is supporting the microphone toggle --> <!-- Whether this device is supporting the software microphone toggle --> <bool name="config_supportsMicToggle">false</bool> <!-- Whether this device is supporting the camera toggle --> <bool name="config_supportsCamToggle">false</bool> <!-- Whether this device is supporting the hardware microphone toggle --> <bool name="config_supportsHardwareMicToggle">false</bool> <!-- Whether this device is supporting the hardware camera toggle --> <bool name="config_supportsHardwareCamToggle">false</bool> <!-- List containing the allowed install sources for accessibility service. --> <string-array name="config_accessibility_allowed_install_source" translatable="false"/> Loading
core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -4649,6 +4649,8 @@ <java-symbol type="bool" name="config_supportsMicToggle" /> <java-symbol type="bool" name="config_supportsCamToggle" /> <java-symbol type="bool" name="config_supportsHardwareMicToggle" /> <java-symbol type="bool" name="config_supportsHardwareCamToggle" /> <java-symbol type="dimen" name="starting_surface_icon_size" /> <java-symbol type="dimen" name="starting_surface_default_icon_size" /> Loading