summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java68
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java97
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt10
4 files changed, 140 insertions, 45 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 9708d9a02edc..c28a9ebb98e9 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -20,6 +20,7 @@ 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.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -33,6 +34,7 @@ import android.os.UserHandle;
import android.permission.PermissionManager;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import androidx.annotation.WorkerThread;
@@ -96,19 +98,58 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
private final SparseArray<ArrayList<AudioRecordingConfiguration>> mRecordingsByUid =
new SparseArray<>();
- protected static final int[] OPS = new int[] {
- AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION,
- AppOpsManager.OP_CAMERA,
- AppOpsManager.OP_PHONE_CALL_CAMERA,
- AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
+ @VisibleForTesting
+ protected static final int[] OPS_MIC = new int[] {
AppOpsManager.OP_RECORD_AUDIO,
- AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
- AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO,
AppOpsManager.OP_PHONE_CALL_MICROPHONE,
+ AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
+ AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO
+ };
+
+ protected static final int[] OPS_CAMERA = new int[] {
+ AppOpsManager.OP_CAMERA,
+ AppOpsManager.OP_PHONE_CALL_CAMERA
+ };
+
+ protected static final int[] OPS_LOC = new int[] {
+ AppOpsManager.OP_FINE_LOCATION,
AppOpsManager.OP_COARSE_LOCATION,
- AppOpsManager.OP_FINE_LOCATION
+ AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION
};
+ protected static final int[] OPS_OTHERS = new int[] {
+ AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
+ AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO
+ };
+
+
+ protected static final int[] OPS = concatOps(OPS_MIC, OPS_CAMERA, OPS_LOC, OPS_OTHERS);
+
+ /**
+ * @param opArrays the given op arrays.
+ * @return the concatenations of the given op arrays. Null arrays are treated as empty.
+ */
+ private static int[] concatOps(@Nullable int[]...opArrays) {
+ if (opArrays == null) {
+ return new int[0];
+ }
+ int totalLength = 0;
+ for (int[] opArray : opArrays) {
+ if (opArray == null || opArray.length == 0) {
+ continue;
+ }
+ totalLength += opArray.length;
+ }
+ final int[] concatOps = new int[totalLength];
+ int index = 0;
+ for (int[] opArray : opArrays) {
+ if (opArray == null || opArray.length == 0) continue;
+ System.arraycopy(opArray, 0, concatOps, index, opArray.length);
+ index += opArray.length;
+ }
+ return concatOps;
+ }
+
@Inject
public AppOpsControllerImpl(
Context context,
@@ -533,12 +574,17 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
}
private boolean isOpCamera(int op) {
- return op == AppOpsManager.OP_CAMERA || op == AppOpsManager.OP_PHONE_CALL_CAMERA;
+ for (int i = 0; i < OPS_CAMERA.length; i++) {
+ if (op == OPS_CAMERA[i]) return true;
+ }
+ return false;
}
private boolean isOpMicrophone(int op) {
- return op == AppOpsManager.OP_RECORD_AUDIO || op == AppOpsManager.OP_PHONE_CALL_MICROPHONE
- || op == AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
+ for (int i = 0; i < OPS_MIC.length; i++) {
+ if (op == OPS_MIC[i]) return true;
+ }
+ return false;
}
protected class H extends Handler {
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt b/packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt
index 88b8676ae1c0..fedbdec113f8 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt
@@ -53,11 +53,14 @@ class AppOpsPrivacyItemMonitor @Inject constructor(
@VisibleForTesting
companion object {
- val OPS_MIC_CAMERA = intArrayOf(AppOpsManager.OP_CAMERA,
- AppOpsManager.OP_PHONE_CALL_CAMERA, AppOpsManager.OP_RECORD_AUDIO,
+ val OPS_MIC_CAMERA = intArrayOf(
+ AppOpsManager.OP_CAMERA,
+ AppOpsManager.OP_PHONE_CALL_CAMERA,
+ AppOpsManager.OP_RECORD_AUDIO,
AppOpsManager.OP_PHONE_CALL_MICROPHONE,
AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
- AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO)
+ AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO,
+ AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO)
val OPS_LOCATION = intArrayOf(
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION)
@@ -212,6 +215,7 @@ class AppOpsPrivacyItemMonitor @Inject constructor(
AppOpsManager.OP_PHONE_CALL_MICROPHONE,
AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO,
+ AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO,
AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE
else -> return null
}
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 61a651234e0c..b23f7f2db01e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -19,6 +19,8 @@ package com.android.systemui.appops;
import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
+import static com.android.systemui.appops.AppOpsControllerImpl.OPS_MIC;
+
import static junit.framework.TestCase.assertFalse;
import static org.junit.Assert.assertEquals;
@@ -171,6 +173,28 @@ public class AppOpsControllerTest extends SysuiTestCase {
TEST_UID, TEST_PACKAGE_NAME, true);
}
+
+ // Only the app ops in the {@link com.android.systemui.appops.AppOpsControllerImpl.OPS} will be
+ // supported by the {@link AppOpsControllerImpl} to add callbacks. The state changes of active
+ // app ops will be notified by the callback.
+ @Test
+ public void addCallback_partialIncludedCode() {
+ mController.addCallback(new int[]{AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO,
+ AppOpsManager.OP_FINE_LOCATION}, mCallback);
+ mController.onOpActiveChanged(
+ AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+ mController.onOpActiveChanged(
+ AppOpsManager.OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO, TEST_UID, TEST_PACKAGE_NAME,
+ true);
+ assertEquals(2, mController.getActiveAppOps().size());
+
+ mTestableLooper.processAllMessages();
+ verify(mCallback).onActiveStateChanged(AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO,
+ TEST_UID, TEST_PACKAGE_NAME, true);
+ verify(mCallback, never()).onActiveStateChanged(AppOpsManager.OP_RECORD_AUDIO,
+ TEST_UID, TEST_PACKAGE_NAME, true);
+ }
+
@Test
public void addCallback_notIncludedCode() {
mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback);
@@ -504,41 +528,17 @@ public class AppOpsControllerTest extends SysuiTestCase {
}
@Test
- public void testUnpausedRecordingSentActive() {
- mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
- mTestableLooper.processAllMessages();
- mController.onOpActiveChanged(
- AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
-
- mTestableLooper.processAllMessages();
- mRecordingCallback.onRecordingConfigChanged(Collections.emptyList());
-
- mTestableLooper.processAllMessages();
-
- verify(mCallback).onActiveStateChanged(
- AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+ public void testUnPausedRecordingSentActive() {
+ for (int i = 0; i < OPS_MIC.length; i++) {
+ verifyUnPausedSentActive(OPS_MIC[i]);
+ }
}
@Test
public void testAudioPausedSentInactive() {
- mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
- mTestableLooper.processAllMessages();
- mController.onOpActiveChanged(
- AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
- mTestableLooper.processAllMessages();
-
- AudioRecordingConfiguration mockARC = mock(AudioRecordingConfiguration.class);
- when(mockARC.getClientUid()).thenReturn(TEST_UID_OTHER);
- when(mockARC.isClientSilenced()).thenReturn(true);
-
- mRecordingCallback.onRecordingConfigChanged(List.of(mockARC));
- mTestableLooper.processAllMessages();
-
- InOrder inOrder = inOrder(mCallback);
- inOrder.verify(mCallback).onActiveStateChanged(
- AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
- inOrder.verify(mCallback).onActiveStateChanged(
- AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, false);
+ for (int i = 0; i < OPS_MIC.length; i++) {
+ verifyAudioPausedSentInactive(OPS_MIC[i]);
+ }
}
@Test
@@ -673,6 +673,41 @@ public class AppOpsControllerTest extends SysuiTestCase {
assertEquals(AppOpsManager.OP_PHONE_CALL_CAMERA, list.get(cameraIdx).getCode());
}
+ private void verifyUnPausedSentActive(int micOpCode) {
+ mController.addCallback(new int[]{micOpCode}, mCallback);
+ mTestableLooper.processAllMessages();
+ mController.onOpActiveChanged(AppOpsManager.opToPublicName(micOpCode), TEST_UID,
+ TEST_PACKAGE_NAME, true);
+
+ mTestableLooper.processAllMessages();
+ mRecordingCallback.onRecordingConfigChanged(Collections.emptyList());
+
+ mTestableLooper.processAllMessages();
+
+ verify(mCallback).onActiveStateChanged(micOpCode, TEST_UID, TEST_PACKAGE_NAME, true);
+ }
+
+ private void verifyAudioPausedSentInactive(int micOpCode) {
+ mController.addCallback(new int[]{micOpCode}, mCallback);
+ mTestableLooper.processAllMessages();
+ mController.onOpActiveChanged(AppOpsManager.opToPublicName(micOpCode), TEST_UID_OTHER,
+ TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+
+ AudioRecordingConfiguration mockARC = mock(AudioRecordingConfiguration.class);
+ when(mockARC.getClientUid()).thenReturn(TEST_UID_OTHER);
+ when(mockARC.isClientSilenced()).thenReturn(true);
+
+ mRecordingCallback.onRecordingConfigChanged(List.of(mockARC));
+ mTestableLooper.processAllMessages();
+
+ InOrder inOrder = inOrder(mCallback);
+ inOrder.verify(mCallback).onActiveStateChanged(
+ micOpCode, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ inOrder.verify(mCallback).onActiveStateChanged(
+ micOpCode, TEST_UID_OTHER, TEST_PACKAGE_NAME, false);
+ }
+
private class TestHandler extends AppOpsControllerImpl.H {
TestHandler(Looper looper) {
mController.super(looper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt
index db96d5507ba1..14ecf93a134e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt
@@ -143,6 +143,16 @@ class AppOpsPrivacyItemMonitorTest : SysuiTestCase() {
}
@Test
+ fun testVoiceActivationPrivacyItems() {
+ doReturn(listOf(AppOpItem(AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO, TEST_UID,
+ TEST_PACKAGE_NAME, 0)))
+ .`when`(appOpsController).getActiveAppOps(anyBoolean())
+ val privacyItems = appOpsPrivacyItemMonitor.getActivePrivacyItems()
+ assertEquals(1, privacyItems.size)
+ assertEquals(PrivacyType.TYPE_MICROPHONE, privacyItems[0].privacyType)
+ }
+
+ @Test
fun testSimilarItemsDifferentTimeStamp() {
doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0),
AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 1)))