diff options
3 files changed, 106 insertions, 41 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java index c28a9ebb98e9..1aa1c59e9443 100644 --- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java @@ -34,7 +34,6 @@ 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; @@ -122,8 +121,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO }; - - protected static final int[] OPS = concatOps(OPS_MIC, OPS_CAMERA, OPS_LOC, OPS_OTHERS); + protected static final int[] OPS = concatOps(OPS_MIC, OPS_CAMERA, OPS_LOC, OPS_OTHERS); /** * @param opArrays the given op arrays. 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 b23f7f2db01e..b100336b602f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java @@ -21,6 +21,8 @@ import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE; import static com.android.systemui.appops.AppOpsControllerImpl.OPS_MIC; +import static com.google.common.truth.Truth.assertThat; + import static junit.framework.TestCase.assertFalse; import static org.junit.Assert.assertEquals; @@ -66,6 +68,7 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -543,69 +546,114 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void testAudioFilteredWhenMicDisabled() { - mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_CAMERA}, - mCallback); + int micOp = AppOpsManager.OP_RECORD_AUDIO; + int nonMicOp = AppOpsManager.OP_CAMERA; + + // Add callbacks for the micOp and nonMicOp, called for the micOp active state change, + // verify the micOp is the only active op returned. + mController.addCallback(new int[]{micOp, nonMicOp}, mCallback); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( - AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); + AppOpsManager.opToPublicName(micOp), TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); - List<AppOpItem> list = mController.getActiveAppOps(); - assertEquals(1, list.size()); - assertEquals(AppOpsManager.OP_RECORD_AUDIO, list.get(0).getCode()); - assertFalse(list.get(0).isDisabled()); + verifySingleActiveOps(micOp); - // Add a camera op, and disable the microphone. The camera op should be the only op returned + // Add a non-mic op, and disable the microphone. The camera op should be the only active op + // returned. mController.onSensorBlockedChanged(MICROPHONE, true); - mController.onOpActiveChanged( - AppOpsManager.OPSTR_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); + mController.onOpActiveChanged(AppOpsManager.opToPublicName(nonMicOp), TEST_UID_OTHER, + TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); - list = mController.getActiveAppOps(); - assertEquals(1, list.size()); - assertEquals(AppOpsManager.OP_CAMERA, list.get(0).getCode()); + verifySingleActiveOps(nonMicOp); - - // Re enable the microphone, and verify the op returns + // Re-enable the microphone, and verify the active op returns. mController.onSensorBlockedChanged(MICROPHONE, false); mTestableLooper.processAllMessages(); - - list = mController.getActiveAppOps(); - assertEquals(2, list.size()); - int micIdx = list.get(0).getCode() == AppOpsManager.OP_CAMERA ? 1 : 0; - assertEquals(AppOpsManager.OP_RECORD_AUDIO, list.get(micIdx).getCode()); + verifyActiveOps(micOp, nonMicOp); } @Test public void testPhoneCallMicrophoneFilteredWhenMicDisabled() { - mController.addCallback( - new int[]{AppOpsManager.OP_PHONE_CALL_MICROPHONE, AppOpsManager.OP_CAMERA}, - mCallback); + int micOp = AppOpsManager.OP_PHONE_CALL_MICROPHONE; + int nonMicOp = AppOpsManager.OP_CAMERA; + + // Add callbacks for the micOp and nonMicOp, called for the micOp active state change, + // verify the micOp is the only active op returned. + mController.addCallback(new int[]{micOp, nonMicOp}, mCallback); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( - AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); + AppOpsManager.opToPublicName(micOp), TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); - List<AppOpItem> list = mController.getActiveAppOps(); - assertEquals(1, list.size()); - assertEquals(AppOpsManager.OP_PHONE_CALL_MICROPHONE, list.get(0).getCode()); - assertFalse(list.get(0).isDisabled()); + verifySingleActiveOps(micOp); - // Add a camera op, and disable the microphone. The camera op should be the only op returned + // Add a non-mic op, and disable the microphone. The camera op should be the only active op + // returned. mController.onSensorBlockedChanged(MICROPHONE, true); + mController.onOpActiveChanged(AppOpsManager.opToPublicName(nonMicOp), TEST_UID_OTHER, + TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); + verifySingleActiveOps(nonMicOp); + + // Re-enable the microphone, and verify the active op returns. + mController.onSensorBlockedChanged(MICROPHONE, false); + mTestableLooper.processAllMessages(); + verifyActiveOps(micOp, nonMicOp); + } + + @Test + public void testAmbientTriggerMicrophoneFilteredWhenMicDisabled() { + int micOp = AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO; + int nonMicOp = AppOpsManager.OP_CAMERA; + + // Add callbacks for the micOp and nonMicOp, called for the micOp active state change, + // verify the micOp is the only active op returned. + mController.addCallback(new int[]{micOp, nonMicOp}, mCallback); + mTestableLooper.processAllMessages(); mController.onOpActiveChanged( - AppOpsManager.OPSTR_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); + AppOpsManager.opToPublicName(micOp), TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); - list = mController.getActiveAppOps(); - assertEquals(1, list.size()); - assertEquals(AppOpsManager.OP_CAMERA, list.get(0).getCode()); + verifySingleActiveOps(micOp); + // Add a non-mic op, and disable the microphone. The camera op should be the only active op + // returned. + mController.onSensorBlockedChanged(MICROPHONE, true); + mController.onOpActiveChanged(AppOpsManager.opToPublicName(nonMicOp), TEST_UID_OTHER, + TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); + verifySingleActiveOps(nonMicOp); - // Re enable the microphone, and verify the op returns + // Re-enable the microphone, and verify the active op returns. mController.onSensorBlockedChanged(MICROPHONE, false); mTestableLooper.processAllMessages(); + verifyActiveOps(micOp, nonMicOp); + } - list = mController.getActiveAppOps(); - assertEquals(2, list.size()); - int micIdx = list.get(0).getCode() == AppOpsManager.OP_CAMERA ? 1 : 0; - assertEquals(AppOpsManager.OP_PHONE_CALL_MICROPHONE, list.get(micIdx).getCode()); + @Test + public void testSandboxTriggerMicrophoneFilteredWhenMicDisabled() { + int micOp = AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO; + int nonMicOp = AppOpsManager.OP_CAMERA; + + // Add callbacks for the micOp and nonMicOp, called for the micOp active state change, + // verify the micOp is the only active op returned. + mController.addCallback(new int[]{micOp, nonMicOp}, mCallback); + mTestableLooper.processAllMessages(); + mController.onOpActiveChanged( + AppOpsManager.opToPublicName(micOp), TEST_UID_OTHER, TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); + verifySingleActiveOps(micOp); + + // Add a non-mic op, and disable the microphone. The camera op should be the only active op + // returned. + mController.onSensorBlockedChanged(MICROPHONE, true); + mController.onOpActiveChanged(AppOpsManager.opToPublicName(nonMicOp), TEST_UID_OTHER, + TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); + verifySingleActiveOps(nonMicOp); + + // Re-enable the microphone, and verify the active op returns. + mController.onSensorBlockedChanged(MICROPHONE, false); + mTestableLooper.processAllMessages(); + verifyActiveOps(micOp, nonMicOp); } @Test @@ -708,6 +756,22 @@ public class AppOpsControllerTest extends SysuiTestCase { micOpCode, TEST_UID_OTHER, TEST_PACKAGE_NAME, false); } + private void verifySingleActiveOps(int op) { + List<AppOpItem> list = mController.getActiveAppOps(); + assertEquals(1, list.size()); + assertEquals(op, list.get(0).getCode()); + assertFalse(list.get(0).isDisabled()); + } + + private void verifyActiveOps(int micOp, int nonMicOp) { + List<AppOpItem> list = mController.getActiveAppOps(); + assertEquals(2, list.size()); + List<Integer> codes = Arrays.asList(list.get(0).getCode(), list.get(1).getCode()); + assertThat(codes).containsExactly(micOp, nonMicOp); + assertFalse(list.get(0).isDisabled()); + assertFalse(list.get(1).isDisabled()); + } + private class TestHandler extends AppOpsControllerImpl.H { TestHandler(Looper looper) { mController.super(looper); diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java index 76126df14bfd..87809916bcaf 100644 --- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java +++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java @@ -27,6 +27,7 @@ import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA; import static android.app.AppOpsManager.OP_PHONE_CALL_MICROPHONE; import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO; import static android.app.AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO; +import static android.app.AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO; import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.content.Intent.EXTRA_PACKAGE_NAME; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; @@ -1125,6 +1126,8 @@ public final class SensorPrivacyService extends SystemService { case MICROPHONE: mAppOpsManagerInternal.setGlobalRestriction(OP_RECORD_AUDIO, enabled, mAppOpsRestrictionToken); + mAppOpsManagerInternal.setGlobalRestriction( + OP_RECEIVE_SANDBOX_TRIGGER_AUDIO, enabled, mAppOpsRestrictionToken); mAppOpsManagerInternal.setGlobalRestriction(OP_PHONE_CALL_MICROPHONE, enabled, mAppOpsRestrictionToken); // We don't show the dialog for RECEIVE_SOUNDTRIGGER_AUDIO, but still want to |