Expose SensorPrivacy as SystemApi
Rename the apis to be more consistent.
Also expose to test api.
Have the aosp mark that it supports the toggle features by default.
Test: atest CtsSensorPrivacyTestCases
Bug: 162549680
Change-Id: Ib38c16adfc5cec931347e1a1891618983d78248b
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d79c11d..fc8c0fe 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -176,6 +176,7 @@
field public static final String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
field public static final String OBSERVE_NETWORK_POLICY = "android.permission.OBSERVE_NETWORK_POLICY";
field public static final String OBSERVE_ROLE_HOLDERS = "android.permission.OBSERVE_ROLE_HOLDERS";
+ field public static final String OBSERVE_SENSOR_PRIVACY = "android.permission.OBSERVE_SENSOR_PRIVACY";
field public static final String OPEN_ACCESSIBILITY_DETAILS_SETTINGS = "android.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS";
field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
@@ -2545,10 +2546,12 @@
field public static final String EXTRA_REQUEST_PERMISSIONS_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
+ field public static final String FEATURE_CAMERA_TOGGLE = "android.hardware.camera.toggle";
field public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub";
field public static final String FEATURE_CROSS_LAYER_BLUR = "android.software.cross_layer_blur";
field @Deprecated public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
field public static final String FEATURE_INCREMENTAL_DELIVERY_VERSION = "android.software.incremental_delivery_version";
+ field public static final String FEATURE_MICROPHONE_TOGGLE = "android.hardware.microphone.toggle";
field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
field public static final String FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION = "android.hardware.telephony.ims.singlereg";
@@ -2903,6 +2906,22 @@
method public boolean injectSensorData(android.hardware.Sensor, float[], int, long);
}
+ public final class SensorPrivacyManager {
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(int, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(int);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeSensorPrivacyListener(@NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+ }
+
+ public static interface SensorPrivacyManager.OnSensorPrivacyChangedListener {
+ method public void onSensorPrivacyChanged(boolean);
+ }
+
+ public static class SensorPrivacyManager.Sensors {
+ field public static final int CAMERA = 2; // 0x2
+ field public static final int MICROPHONE = 1; // 0x1
+ }
+
}
package android.hardware.biometrics {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index d7b43c0..ad60aca 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -696,8 +696,10 @@
method public void holdLock(android.os.IBinder, int);
method @RequiresPermission(android.Manifest.permission.KEEP_UNINSTALLED_PACKAGES) public void setKeepUninstalledPackages(@NonNull java.util.List<java.lang.String>);
field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
+ field public static final String FEATURE_CAMERA_TOGGLE = "android.hardware.camera.toggle";
field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
field public static final String FEATURE_HDMI_CEC = "android.hardware.hdmi.cec";
+ field public static final String FEATURE_MICROPHONE_TOGGLE = "android.hardware.microphone.toggle";
field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80
field public static final int MATCH_KNOWN_PACKAGES = 4202496; // 0x402000
field public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
@@ -858,11 +860,21 @@
package android.hardware {
public final class SensorPrivacyManager {
- method public boolean isIndividualSensorPrivacyEnabled(int);
- method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setIndividualSensorPrivacy(int, boolean);
- method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setIndividualSensorPrivacyForProfileGroup(int, boolean);
- field public static final int INDIVIDUAL_SENSOR_CAMERA = 2; // 0x2
- field public static final int INDIVIDUAL_SENSOR_MICROPHONE = 1; // 0x1
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(int, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(int);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeSensorPrivacyListener(@NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacy(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacyForProfileGroup(int, boolean);
+ }
+
+ public static interface SensorPrivacyManager.OnSensorPrivacyChangedListener {
+ method public void onSensorPrivacyChanged(boolean);
+ }
+
+ public static class SensorPrivacyManager.Sensors {
+ field public static final int CAMERA = 2; // 0x2
+ field public static final int MICROPHONE = 1; // 0x1
}
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f9122b1..668a7cf 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3623,11 +3623,26 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports a enabling/disabling sensor privacy for
- * camera. When sensory privacy for the camera is enabled no camera data is send to clients,
+ * microphone. When sensory privacy for the microphone is enabled no microphone data is sent to
+ * clients, e.g. all audio data is silent.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_MICROPHONE_TOGGLE = "android.hardware.microphone.toggle";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports a enabling/disabling sensor privacy for
+ * camera. When sensory privacy for the camera is enabled no camera data is sent to clients,
* e.g. the view finder in a camera app would appear blank.
*
* @hide
*/
+ @SystemApi
+ @TestApi
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_CAMERA_TOGGLE = "android.hardware.camera.toggle";
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index f4f9e17..e03c1f4 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
@@ -33,6 +34,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
/**
* This class provides access to the sensor privacy services; sensor privacy allows the
@@ -42,9 +44,21 @@
*
* @hide
*/
+@SystemApi
@TestApi
@SystemService(Context.SENSOR_PRIVACY_SERVICE)
public final class SensorPrivacyManager {
+
+ /**
+ * @hide
+ */
+ public static final boolean USE_MICROPHONE_TOGGLE = true;
+
+ /**
+ * @hide
+ */
+ public static final boolean USE_CAMERA_TOGGLE = true;
+
/**
* Unique Id of this manager to identify to the service
* @hide
@@ -58,28 +72,39 @@
public static final String EXTRA_SENSOR = SensorPrivacyManager.class.getName()
+ ".extra.sensor";
- /** Microphone
- * @hide */
- @TestApi
- public static final int INDIVIDUAL_SENSOR_MICROPHONE =
- SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
-
- /** Camera
- * @hide */
- @TestApi
- public static final int INDIVIDUAL_SENSOR_CAMERA =
- SensorPrivacyIndividualEnabledSensorProto.CAMERA;
-
/**
- * Individual sensors not listed in {@link Sensor}
+ * Individual sensors not listed in {@link Sensors}
* @hide
*/
- @IntDef(prefix = "INDIVIDUAL_SENSOR_", value = {
- INDIVIDUAL_SENSOR_MICROPHONE,
- INDIVIDUAL_SENSOR_CAMERA
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface IndividualSensor {}
+ @SystemApi
+ @TestApi
+ public static class Sensors {
+
+ private Sensors() {}
+
+ /** Microphone
+ * @hide */
+ @SystemApi
+ @TestApi
+ public static final int MICROPHONE = SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
+ /** Camera
+ * @hide */
+ @SystemApi
+ @TestApi
+ public static final int CAMERA = SensorPrivacyIndividualEnabledSensorProto.CAMERA;
+
+ /**
+ * Individual sensors not listed in {@link Sensors}
+ *
+ * @hide
+ */
+ @IntDef(value = {
+ MICROPHONE,
+ CAMERA
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Sensor {}
+ }
/**
* A class implementing this interface can register with the {@link
@@ -88,6 +113,8 @@
*
* @hide
*/
+ @SystemApi
+ @TestApi
public interface OnSensorPrivacyChangedListener {
/**
* Callback invoked when the sensor privacy state changes.
@@ -165,7 +192,8 @@
*
* @hide
*/
- public void addSensorPrivacyListener(final OnSensorPrivacyChangedListener listener) {
+ @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public void addSensorPrivacyListener(@NonNull final OnSensorPrivacyChangedListener listener) {
synchronized (mListeners) {
ISensorPrivacyListener iListener = mListeners.get(listener);
if (iListener == null) {
@@ -196,15 +224,37 @@
*
* @hide
*/
- public void addSensorPrivacyListener(@IndividualSensor int sensor,
- final OnSensorPrivacyChangedListener listener) {
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public void addSensorPrivacyListener(@Sensors.Sensor int sensor,
+ @NonNull OnSensorPrivacyChangedListener listener) {
+ addSensorPrivacyListener(sensor, 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 listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
+ * privacy changes.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull Executor executor,
+ @NonNull OnSensorPrivacyChangedListener listener) {
synchronized (mListeners) {
ISensorPrivacyListener iListener = mListeners.get(listener);
if (iListener == null) {
iListener = new ISensorPrivacyListener.Stub() {
@Override
public void onSensorPrivacyChanged(boolean enabled) {
- listener.onSensorPrivacyChanged(enabled);
+ executor.execute(() -> listener.onSensorPrivacyChanged(enabled));
}
};
mListeners.put(listener, iListener);
@@ -228,7 +278,10 @@
*
* @hide
*/
- public void removeSensorPrivacyListener(OnSensorPrivacyChangedListener listener) {
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public void removeSensorPrivacyListener(@NonNull OnSensorPrivacyChangedListener listener) {
synchronized (mListeners) {
ISensorPrivacyListener iListener = mListeners.get(listener);
if (iListener != null) {
@@ -249,6 +302,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public boolean isSensorPrivacyEnabled() {
try {
return mService.isSensorPrivacyEnabled();
@@ -264,8 +318,10 @@
*
* @hide
*/
+ @SystemApi
@TestApi
- public boolean isIndividualSensorPrivacyEnabled(@IndividualSensor int sensor) {
+ @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
try {
return mService.isIndividualSensorPrivacyEnabled(mContext.getUserId(), sensor);
} catch (RemoteException e) {
@@ -283,8 +339,7 @@
*/
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY)
- public void setIndividualSensorPrivacy(@IndividualSensor int sensor,
- boolean enable) {
+ public void setSensorPrivacy(@Sensors.Sensor int sensor, boolean enable) {
try {
mService.setIndividualSensorPrivacy(mContext.getUserId(), sensor, enable);
} catch (RemoteException e) {
@@ -303,7 +358,7 @@
*/
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY)
- public void setIndividualSensorPrivacyForProfileGroup(@IndividualSensor int sensor,
+ public void setSensorPrivacyForProfileGroup(@Sensors.Sensor int sensor,
boolean enable) {
try {
mService.setIndividualSensorPrivacyForProfileGroup(mContext.getUserId(), sensor,
@@ -321,7 +376,8 @@
*
* @hide
*/
- public void suppressIndividualSensorPrivacyReminders(@NonNull String packageName,
+ @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY)
+ public void suppressSensorPrivacyReminders(@NonNull String packageName,
boolean suppress) {
try {
mService.suppressIndividualSensorPrivacyReminders(mContext.getUserId(), packageName,
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 8982519..55af060 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -24,6 +24,7 @@
import android.content.ComponentName;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
+import android.hardware.SensorPrivacyManager;
import android.os.Build;
import android.os.CarrierAssociatedAppEntry;
import android.os.Environment;
@@ -1252,6 +1253,14 @@
addFeature(PackageManager.FEATURE_CROSS_LAYER_BLUR, 0);
}
+ if (SensorPrivacyManager.USE_MICROPHONE_TOGGLE) {
+ addFeature(PackageManager.FEATURE_MICROPHONE_TOGGLE, 0);
+ }
+
+ if (SensorPrivacyManager.USE_CAMERA_TOGGLE) {
+ addFeature(PackageManager.FEATURE_CAMERA_TOGGLE, 0);
+ }
+
for (String featureName : mUnavailableFeatures) {
removeFeature(featureName);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5dd8580..43d9651 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5421,6 +5421,12 @@
@hide -->
<permission android:name="android.permission.MANAGE_SENSOR_PRIVACY"
android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows sensor privacy changes to be observed.
+ @hide -->
+ <permission android:name="android.permission.OBSERVE_SENSOR_PRIVACY"
+ android:protectionLevel="signature|installer" />
+
<!-- @SystemApi Permission that protects the {@link Intent#ACTION_REVIEW_ACCESSIBILITY_SERVICES}
intent.
@hide -->
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 2594840..53fbb00 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -398,6 +398,7 @@
<!-- Permission required for CTS to test sensor privacy behavior -->
<uses-permission android:name="android.permission.MANAGE_SENSOR_PRIVACY" />
+ <uses-permission android:name="android.permission.OBSERVE_SENSOR_PRIVACY" />
<!-- Permission needed for CTS test - CallLogTest -->
<uses-permission android:name="com.android.voicemail.permission.READ_VOICEMAIL" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index fbe58c5..044216e 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -87,6 +87,7 @@
<uses-permission android:name="android.permission.MASTER_CLEAR" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.MANAGE_SENSOR_PRIVACY" />
+ <uses-permission android:name="android.permission.OBSERVE_SENSOR_PRIVACY" />
<!-- ActivityManager -->
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 9686c91f..79f0688 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -16,8 +16,8 @@
package com.android.systemui.appops;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
import static android.media.AudioManager.ACTION_MICROPHONE_MUTE_CHANGED;
import android.Manifest;
@@ -137,8 +137,8 @@
mAudioManager = audioManager;
mSensorPrivacyController = sensorPrivacyController;
mMicMuted = audioManager.isMicrophoneMute()
- || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
- mCameraDisabled = mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA);
+ || mSensorPrivacyController.isSensorBlocked(MICROPHONE);
+ mCameraDisabled = mSensorPrivacyController.isSensorBlocked(CAMERA);
mLocationManager = context.getSystemService(LocationManager.class);
mPackageManager = context.getPackageManager();
dumpManager.registerDumpable(TAG, this);
@@ -159,8 +159,8 @@
mSensorPrivacyController.addCallback(this);
mMicMuted = mAudioManager.isMicrophoneMute()
- || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
- mCameraDisabled = mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA);
+ || mSensorPrivacyController.isSensorBlocked(MICROPHONE);
+ mCameraDisabled = mSensorPrivacyController.isSensorBlocked(CAMERA);
mBGHandler.post(() -> mAudioRecordingCallback.onRecordingConfigChanged(
mAudioManager.getActiveRecordingConfigurations()));
@@ -583,16 +583,16 @@
@Override
public void onReceive(Context context, Intent intent) {
mMicMuted = mAudioManager.isMicrophoneMute()
- || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
+ || mSensorPrivacyController.isSensorBlocked(MICROPHONE);
updateSensorDisabledStatus();
}
@Override
public void onSensorBlockedChanged(int sensor, boolean blocked) {
mBGHandler.post(() -> {
- if (sensor == INDIVIDUAL_SENSOR_CAMERA) {
+ if (sensor == CAMERA) {
mCameraDisabled = blocked;
- } else if (sensor == INDIVIDUAL_SENSOR_MICROPHONE) {
+ } else if (sensor == MICROPHONE) {
mMicMuted = mAudioManager.isMicrophoneMute() || blocked;
}
updateSensorDisabledStatus();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
index 3841dac..70287cd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
@@ -16,10 +16,13 @@
package com.android.systemui.qs.tiles;
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.CAMERA;
+import static android.content.pm.PackageManager.FEATURE_CAMERA_TOGGLE;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
import static com.android.systemui.DejankUtils.whitelistIpcs;
+import android.hardware.SensorPrivacyManager;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
import android.os.Handler;
import android.os.Looper;
import android.provider.DeviceConfig;
@@ -58,8 +61,8 @@
@Override
public boolean isAvailable() {
- return /*getHost().getContext().getPackageManager().hasSystemFeature(FEATURE_CAMERA_TOGGLE)
- && */whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ return getHost().getContext().getPackageManager().hasSystemFeature(FEATURE_CAMERA_TOGGLE)
+ && whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
"camera_toggle_enabled",
false));
}
@@ -75,7 +78,7 @@
}
@Override
- public int getSensorId() {
+ public @Sensor int getSensorId() {
return CAMERA;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
index 2f0071a..e9b712d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
@@ -16,10 +16,13 @@
package com.android.systemui.qs.tiles;
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
+import static android.content.pm.PackageManager.FEATURE_MICROPHONE_TOGGLE;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
+import android.hardware.SensorPrivacyManager;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
import android.os.Handler;
import android.os.Looper;
import android.provider.DeviceConfig;
@@ -58,7 +61,9 @@
@Override
public boolean isAvailable() {
- return whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ return getHost().getContext().getPackageManager()
+ .hasSystemFeature(FEATURE_MICROPHONE_TOGGLE)
+ && whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
"mic_toggle_enabled",
false));
}
@@ -74,7 +79,7 @@
}
@Override
- public int getSensorId() {
+ public @Sensor int getSensorId() {
return MICROPHONE;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
index 00703e7..0c582bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
@@ -17,7 +17,7 @@
package com.android.systemui.qs.tiles;
import android.content.Intent;
-import android.hardware.SensorPrivacyManager.IndividualSensor;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
import android.os.Handler;
import android.os.Looper;
import android.service.quicksettings.Tile;
@@ -49,7 +49,7 @@
/**
* @return Id of the sensor that will be toggled
*/
- public abstract @IndividualSensor int getSensorId();
+ public abstract @Sensor int getSensorId();
/**
* @return icon for the QS tile
diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
index 9f182e1..6586137 100644
--- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
@@ -25,8 +25,8 @@
import android.content.res.Resources
import android.hardware.SensorPrivacyManager
import android.hardware.SensorPrivacyManager.EXTRA_SENSOR
-import android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA
-import android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE
+import android.hardware.SensorPrivacyManager.Sensors.CAMERA
+import android.hardware.SensorPrivacyManager.Sensors.MICROPHONE
import android.os.Bundle
import android.os.Handler
import android.text.Html
@@ -81,7 +81,7 @@
dismiss()
}
}
- if (!sensorPrivacyManager.isIndividualSensorPrivacyEnabled(sensor)) {
+ if (!sensorPrivacyManager.isSensorPrivacyEnabled(sensor)) {
finish()
return
}
@@ -89,9 +89,9 @@
mAlertParams.apply {
try {
mMessage = Html.fromHtml(getString(when (sensor) {
- INDIVIDUAL_SENSOR_MICROPHONE ->
+ MICROPHONE ->
R.string.sensor_privacy_start_use_mic_dialog_content
- INDIVIDUAL_SENSOR_CAMERA ->
+ CAMERA ->
R.string.sensor_privacy_start_use_camera_dialog_content
else -> Resources.ID_NULL
}, packageManager.getApplicationInfo(sensorUsePackageName, 0)
@@ -102,9 +102,9 @@
}
mIconId = when (sensor) {
- INDIVIDUAL_SENSOR_MICROPHONE ->
+ MICROPHONE ->
com.android.internal.R.drawable.perm_group_microphone
- INDIVIDUAL_SENSOR_CAMERA -> com.android.internal.R.drawable.perm_group_camera
+ CAMERA -> com.android.internal.R.drawable.perm_group_camera
else -> Resources.ID_NULL
}
@@ -121,7 +121,7 @@
override fun onStart() {
super.onStart()
- sensorPrivacyManager.suppressIndividualSensorPrivacyReminders(sensorUsePackageName, true)
+ sensorPrivacyManager.suppressSensorPrivacyReminders(sensorUsePackageName, true)
unsuppressImmediately = false
}
@@ -156,11 +156,11 @@
if (unsuppressImmediately) {
sensorPrivacyManager
- .suppressIndividualSensorPrivacyReminders(sensorUsePackageName, false)
+ .suppressSensorPrivacyReminders(sensorUsePackageName, false)
} else {
Handler(mainLooper).postDelayed({
sensorPrivacyManager
- .suppressIndividualSensorPrivacyReminders(sensorUsePackageName, false)
+ .suppressSensorPrivacyReminders(sensorUsePackageName, false)
}, SUPPRESS_REMINDERS_REMOVAL_DELAY_MILLIS)
}
}
@@ -170,7 +170,7 @@
}
private fun disableSensorPrivacy() {
- sensorPrivacyManager.setIndividualSensorPrivacyForProfileGroup(sensor, false)
+ sensorPrivacyManager.setSensorPrivacyForProfileGroup(sensor, false)
unsuppressImmediately = true
setResult(RESULT_OK)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
index a76d08a..7f935d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
@@ -16,17 +16,17 @@
package com.android.systemui.statusbar.policy;
-import android.hardware.SensorPrivacyManager.IndividualSensor;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
public interface IndividualSensorPrivacyController extends
CallbackController<IndividualSensorPrivacyController.Callback> {
void init();
- boolean isSensorBlocked(@IndividualSensor int sensor);
+ boolean isSensorBlocked(@Sensor int sensor);
- void setSensorBlocked(@IndividualSensor int sensor, boolean blocked);
+ void setSensorBlocked(@Sensor int sensor, boolean blocked);
interface Callback {
- void onSensorBlockedChanged(@IndividualSensor int sensor, boolean blocked);
+ void onSensorBlockedChanged(@Sensor int sensor, boolean blocked);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
index 32d15ed..295df05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
@@ -16,11 +16,11 @@
package com.android.systemui.statusbar.policy;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
import android.hardware.SensorPrivacyManager;
-import android.hardware.SensorPrivacyManager.IndividualSensor;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
import android.util.ArraySet;
import android.util.SparseBooleanArray;
@@ -30,8 +30,7 @@
public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPrivacyController {
- private static final int[] SENSORS = new int[] {INDIVIDUAL_SENSOR_CAMERA,
- INDIVIDUAL_SENSOR_MICROPHONE};
+ private static final int[] SENSORS = new int[] {CAMERA, MICROPHONE};
private final @NonNull SensorPrivacyManager mSensorPrivacyManager;
private final SparseBooleanArray mState = new SparseBooleanArray();
@@ -48,18 +47,18 @@
mSensorPrivacyManager.addSensorPrivacyListener(sensor,
(enabled) -> onSensorPrivacyChanged(sensor, enabled));
- mState.put(sensor, mSensorPrivacyManager.isIndividualSensorPrivacyEnabled(sensor));
+ mState.put(sensor, mSensorPrivacyManager.isSensorPrivacyEnabled(sensor));
}
}
@Override
- public boolean isSensorBlocked(@IndividualSensor int sensor) {
+ public boolean isSensorBlocked(@Sensor int sensor) {
return mState.get(sensor, false);
}
@Override
- public void setSensorBlocked(@IndividualSensor int sensor, boolean blocked) {
- mSensorPrivacyManager.setIndividualSensorPrivacyForProfileGroup(sensor, blocked);
+ public void setSensorBlocked(@Sensor int sensor, boolean blocked) {
+ mSensorPrivacyManager.setSensorPrivacyForProfileGroup(sensor, blocked);
}
@Override
@@ -72,7 +71,7 @@
mCallbacks.remove(listener);
}
- private void onSensorPrivacyChanged(@IndividualSensor int sensor, boolean blocked) {
+ private void onSensorPrivacyChanged(@Sensor int sensor, boolean blocked) {
mState.put(sensor, blocked);
for (Callback callback : mCallbacks) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 97cb873..2526990 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -16,8 +16,8 @@
package com.android.systemui.appops;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
import static junit.framework.TestCase.assertFalse;
@@ -125,9 +125,9 @@
when(mAudioManager.getActiveRecordingConfigurations())
.thenReturn(List.of(mPausedMockRecording));
- when(mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA))
+ when(mSensorPrivacyController.isSensorBlocked(CAMERA))
.thenReturn(false);
- when(mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA))
+ when(mSensorPrivacyController.isSensorBlocked(CAMERA))
.thenReturn(false);
mController = new AppOpsControllerImpl(
@@ -505,7 +505,7 @@
assertFalse(list.get(0).isDisabled());
// Add a camera op, and disable the microphone. The camera op should be the only op returned
- mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_MICROPHONE, true);
+ mController.onSensorBlockedChanged(MICROPHONE, true);
mController.onOpActiveChanged(
AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
mTestableLooper.processAllMessages();
@@ -515,7 +515,7 @@
// Re enable the microphone, and verify the op returns
- mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_MICROPHONE, false);
+ mController.onSensorBlockedChanged(MICROPHONE, false);
mTestableLooper.processAllMessages();
list = mController.getActiveAppOps();
@@ -538,7 +538,7 @@
assertFalse(list.get(0).isDisabled());
// Add an audio op, and disable the camera. The audio op should be the only op returned
- mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_CAMERA, true);
+ mController.onSensorBlockedChanged(CAMERA, true);
mController.onOpActiveChanged(
AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
mTestableLooper.processAllMessages();
@@ -547,7 +547,7 @@
assertEquals(AppOpsManager.OP_RECORD_AUDIO, list.get(0).getCode());
// Re enable the camera, and verify the op returns
- mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_CAMERA, false);
+ mController.onSensorBlockedChanged(CAMERA, false);
mTestableLooper.processAllMessages();
list = mController.getActiveAppOps();
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 84e429d..f2782f6 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -25,9 +25,9 @@
import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.hardware.SensorPrivacyManager.EXTRA_SENSOR;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
import static android.os.UserHandle.USER_SYSTEM;
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.CAMERA;
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
import static android.service.SensorPrivacyIndividualEnabledSensorProto.UNKNOWN;
import android.annotation.NonNull;
@@ -406,12 +406,12 @@
*/
@Override
public void setSensorPrivacy(boolean enable) {
+ enforceManageSensorPrivacyPermission();
// Keep the state consistent between all users to make it a single global state
forAllUsers(userId -> setSensorPrivacy(userId, enable));
}
private void setSensorPrivacy(@UserIdInt int userId, boolean enable) {
- enforceSensorPrivacyPermission();
synchronized (mLock) {
mEnabled.put(userId, enable);
persistSensorPrivacyStateLocked();
@@ -421,7 +421,7 @@
@Override
public void setIndividualSensorPrivacy(@UserIdInt int userId, int sensor, boolean enable) {
- enforceSensorPrivacyPermission();
+ enforceManageSensorPrivacyPermission();
synchronized (mLock) {
SparseBooleanArray userIndividualEnabled = mIndividualEnabled.get(userId,
new SparseBooleanArray());
@@ -448,6 +448,7 @@
@Override
public void setIndividualSensorPrivacyForProfileGroup(@UserIdInt int userId, int sensor,
boolean enable) {
+ enforceManageSensorPrivacyPermission();
int parentId = mUserManagerInternal.getProfileParentId(userId);
forAllUsers(userId2 -> {
if (parentId == mUserManagerInternal.getProfileParentId(userId2)) {
@@ -460,21 +461,35 @@
* Enforces the caller contains the necessary permission to change the state of sensor
* privacy.
*/
- private void enforceSensorPrivacyPermission() {
- if (mContext.checkCallingOrSelfPermission(
- MANAGE_SENSOR_PRIVACY) == PERMISSION_GRANTED) {
- return;
- }
- throw new SecurityException(
+ private void enforceManageSensorPrivacyPermission() {
+ enforcePermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY,
"Changing sensor privacy requires the following permission: "
+ MANAGE_SENSOR_PRIVACY);
}
/**
+ * Enforces the caller contains the necessary permission to observe changes to the sate of
+ * sensor privacy.
+ */
+ private void enforceObserveSensorPrivacyPermission() {
+ enforcePermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY,
+ "Observing sensor privacy changes requires the following permission: "
+ + android.Manifest.permission.OBSERVE_SENSOR_PRIVACY);
+ }
+
+ private void enforcePermission(String permission, String message) {
+ if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+ return;
+ }
+ throw new SecurityException(message);
+ }
+
+ /**
* Returns whether sensor privacy is enabled.
*/
@Override
public boolean isSensorPrivacyEnabled() {
+ enforceObserveSensorPrivacyPermission();
return isSensorPrivacyEnabled(USER_SYSTEM);
}
@@ -486,6 +501,7 @@
@Override
public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId, int sensor) {
+ enforceObserveSensorPrivacyPermission();
synchronized (mLock) {
SparseBooleanArray states = mIndividualEnabled.get(userId);
if (states == null) {
@@ -703,6 +719,7 @@
*/
@Override
public void addSensorPrivacyListener(ISensorPrivacyListener listener) {
+ enforceObserveSensorPrivacyPermission();
if (listener == null) {
throw new NullPointerException("listener cannot be null");
}
@@ -715,6 +732,7 @@
@Override
public void addIndividualSensorPrivacyListener(int userId, int sensor,
ISensorPrivacyListener listener) {
+ enforceObserveSensorPrivacyPermission();
if (listener == null) {
throw new NullPointerException("listener cannot be null");
}
@@ -726,6 +744,7 @@
*/
@Override
public void removeSensorPrivacyListener(ISensorPrivacyListener listener) {
+ enforceObserveSensorPrivacyPermission();
if (listener == null) {
throw new NullPointerException("listener cannot be null");
}
@@ -735,6 +754,7 @@
@Override
public void suppressIndividualSensorPrivacyReminders(int userId, String packageName,
IBinder token, boolean suppress) {
+ enforceManageSensorPrivacyPermission();
Objects.requireNonNull(packageName);
Objects.requireNonNull(token);
@@ -886,13 +906,13 @@
}
/**
- * Convert a string into a {@link SensorPrivacyManager.IndividualSensor id}.
+ * Convert a string into a {@link SensorPrivacyManager.Sensors.Sensor id}.
*
* @param sensor The name to convert
*
* @return The id corresponding to the name
*/
- private @SensorPrivacyManager.IndividualSensor int sensorStrToId(@Nullable String sensor) {
+ private @SensorPrivacyManager.Sensors.Sensor int sensorStrToId(@Nullable String sensor) {
if (sensor == null) {
return UNKNOWN;
}
@@ -950,7 +970,7 @@
return -1;
}
- enforceSensorPrivacyPermission();
+ enforceManageSensorPrivacyPermission();
synchronized (mLock) {
SparseBooleanArray individualEnabled =
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 81c1e45..dde45c4 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -295,7 +295,7 @@
};
SensorPrivacyManager manager = SensorPrivacyManager.getInstance(mContext);
manager.addSensorPrivacyListener(
- SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE, listener);
+ SensorPrivacyManager.Sensors.MICROPHONE, listener);
}
}
@@ -1079,8 +1079,8 @@
*/
private void sendMicrophoneDisableSettingUpdate() {
SensorPrivacyManager manager = SensorPrivacyManager.getInstance(mContext);
- boolean disabled = manager.isIndividualSensorPrivacyEnabled(
- SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE);
+ boolean disabled = manager.isSensorPrivacyEnabled(
+ SensorPrivacyManager.Sensors.MICROPHONE);
Log.d(TAG, "Mic Disabled Setting: " + disabled);
mContextHubWrapper.onMicrophoneDisableSettingChanged(disabled);
}