Loading packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +8 −5 Original line number Diff line number Diff line Loading @@ -319,7 +319,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon if (item == null && active) { item = new AppOpItem(code, uid, packageName, mClock.elapsedRealtime()); if (isOpMicrophone(code)) { item.setDisabled(isAnyRecordingPausedLocked(uid)); item.setDisabled(isAllRecordingPausedLocked(uid)); } else if (isOpCamera(code)) { item.setDisabled(mCameraDisabled); } Loading Loading @@ -521,18 +521,21 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon } private boolean isAnyRecordingPausedLocked(int uid) { // TODO(b/365843152) remove AudioRecordingConfiguration listening private boolean isAllRecordingPausedLocked(int uid) { if (mMicMuted) { return true; } List<AudioRecordingConfiguration> configs = mRecordingsByUid.get(uid); if (configs == null) return false; // If we are aware of AudioRecordConfigs, suppress the indicator if all of them are known // to be silenced. int configsNum = configs.size(); for (int i = 0; i < configsNum; i++) { AudioRecordingConfiguration config = configs.get(i); if (config.isClientSilenced()) return true; if (!config.isClientSilenced()) return false; } return false; return true; } private void updateSensorDisabledStatus() { Loading @@ -543,7 +546,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon boolean paused = false; if (isOpMicrophone(item.getCode())) { paused = isAnyRecordingPausedLocked(item.getUid()); paused = isAllRecordingPausedLocked(item.getUid()); } else if (isOpCamera(item.getCode())) { paused = mCameraDisabled; } Loading packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +23 −7 Original line number Diff line number Diff line Loading @@ -103,11 +103,10 @@ public class AppOpsControllerTest extends SysuiTestCase { @Mock() private BroadcastDispatcher mDispatcher; @Mock(stubOnly = true) private AudioManager.AudioRecordingCallback mRecordingCallback; @Mock(stubOnly = true) private AudioRecordingConfiguration mPausedMockRecording; private AppOpsControllerImpl mController; private AudioManager.AudioRecordingCallback mRecordingCallback; private TestableLooper mTestableLooper; private final FakeExecutor mBgExecutor = new FakeExecutor(new FakeSystemClock()); Loading Loading @@ -975,6 +974,7 @@ public class AppOpsControllerTest extends SysuiTestCase { } private void verifyUnPausedSentActive(int micOpCode) { // Setup stubs the initial active recording list with a single silenced client mController.addCallback(new int[]{micOpCode}, mCallback); mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); Loading @@ -982,11 +982,20 @@ public class AppOpsControllerTest extends SysuiTestCase { TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); mRecordingCallback.onRecordingConfigChanged(Collections.emptyList()); // Update with multiple recording configs, of which one is unsilenced var mockARCUnsilenced = mock(AudioRecordingConfiguration.class); when(mockARCUnsilenced.getClientUid()).thenReturn(TEST_UID); when(mockARCUnsilenced.isClientSilenced()).thenReturn(false); mRecordingCallback.onRecordingConfigChanged(List.of( mockARCUnsilenced, mPausedMockRecording)); mTestableLooper.processAllMessages(); verify(mCallback).onActiveStateChanged(micOpCode, TEST_UID, TEST_PACKAGE_NAME, true); // For consistency since this runs in a loop mController.removeCallback(new int[]{micOpCode}, mCallback); } private void verifyAudioPausedSentInactive(int micOpCode) { Loading @@ -997,11 +1006,16 @@ public class AppOpsControllerTest extends SysuiTestCase { TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); AudioRecordingConfiguration mockARC = mock(AudioRecordingConfiguration.class); when(mockARC.getClientUid()).thenReturn(TEST_UID_OTHER); when(mockARC.isClientSilenced()).thenReturn(true); // Multiple recording configs, which are all silenced AudioRecordingConfiguration mockARCOne = mock(AudioRecordingConfiguration.class); when(mockARCOne.getClientUid()).thenReturn(TEST_UID_OTHER); when(mockARCOne.isClientSilenced()).thenReturn(true); AudioRecordingConfiguration mockARCTwo = mock(AudioRecordingConfiguration.class); when(mockARCTwo.getClientUid()).thenReturn(TEST_UID_OTHER); when(mockARCTwo.isClientSilenced()).thenReturn(true); mRecordingCallback.onRecordingConfigChanged(List.of(mockARC)); mRecordingCallback.onRecordingConfigChanged(List.of(mockARCOne, mockARCTwo)); mTestableLooper.processAllMessages(); InOrder inOrder = inOrder(mCallback); Loading @@ -1009,6 +1023,8 @@ public class AppOpsControllerTest extends SysuiTestCase { micOpCode, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); inOrder.verify(mCallback).onActiveStateChanged( micOpCode, TEST_UID_OTHER, TEST_PACKAGE_NAME, false); // For consistency since this runs in a loop mController.removeCallback(new int[]{micOpCode}, mCallback); } private void verifySingleActiveOps(int op) { Loading Loading
packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +8 −5 Original line number Diff line number Diff line Loading @@ -319,7 +319,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon if (item == null && active) { item = new AppOpItem(code, uid, packageName, mClock.elapsedRealtime()); if (isOpMicrophone(code)) { item.setDisabled(isAnyRecordingPausedLocked(uid)); item.setDisabled(isAllRecordingPausedLocked(uid)); } else if (isOpCamera(code)) { item.setDisabled(mCameraDisabled); } Loading Loading @@ -521,18 +521,21 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon } private boolean isAnyRecordingPausedLocked(int uid) { // TODO(b/365843152) remove AudioRecordingConfiguration listening private boolean isAllRecordingPausedLocked(int uid) { if (mMicMuted) { return true; } List<AudioRecordingConfiguration> configs = mRecordingsByUid.get(uid); if (configs == null) return false; // If we are aware of AudioRecordConfigs, suppress the indicator if all of them are known // to be silenced. int configsNum = configs.size(); for (int i = 0; i < configsNum; i++) { AudioRecordingConfiguration config = configs.get(i); if (config.isClientSilenced()) return true; if (!config.isClientSilenced()) return false; } return false; return true; } private void updateSensorDisabledStatus() { Loading @@ -543,7 +546,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon boolean paused = false; if (isOpMicrophone(item.getCode())) { paused = isAnyRecordingPausedLocked(item.getUid()); paused = isAllRecordingPausedLocked(item.getUid()); } else if (isOpCamera(item.getCode())) { paused = mCameraDisabled; } Loading
packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +23 −7 Original line number Diff line number Diff line Loading @@ -103,11 +103,10 @@ public class AppOpsControllerTest extends SysuiTestCase { @Mock() private BroadcastDispatcher mDispatcher; @Mock(stubOnly = true) private AudioManager.AudioRecordingCallback mRecordingCallback; @Mock(stubOnly = true) private AudioRecordingConfiguration mPausedMockRecording; private AppOpsControllerImpl mController; private AudioManager.AudioRecordingCallback mRecordingCallback; private TestableLooper mTestableLooper; private final FakeExecutor mBgExecutor = new FakeExecutor(new FakeSystemClock()); Loading Loading @@ -975,6 +974,7 @@ public class AppOpsControllerTest extends SysuiTestCase { } private void verifyUnPausedSentActive(int micOpCode) { // Setup stubs the initial active recording list with a single silenced client mController.addCallback(new int[]{micOpCode}, mCallback); mBgExecutor.runAllReady(); mTestableLooper.processAllMessages(); Loading @@ -982,11 +982,20 @@ public class AppOpsControllerTest extends SysuiTestCase { TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); mRecordingCallback.onRecordingConfigChanged(Collections.emptyList()); // Update with multiple recording configs, of which one is unsilenced var mockARCUnsilenced = mock(AudioRecordingConfiguration.class); when(mockARCUnsilenced.getClientUid()).thenReturn(TEST_UID); when(mockARCUnsilenced.isClientSilenced()).thenReturn(false); mRecordingCallback.onRecordingConfigChanged(List.of( mockARCUnsilenced, mPausedMockRecording)); mTestableLooper.processAllMessages(); verify(mCallback).onActiveStateChanged(micOpCode, TEST_UID, TEST_PACKAGE_NAME, true); // For consistency since this runs in a loop mController.removeCallback(new int[]{micOpCode}, mCallback); } private void verifyAudioPausedSentInactive(int micOpCode) { Loading @@ -997,11 +1006,16 @@ public class AppOpsControllerTest extends SysuiTestCase { TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); AudioRecordingConfiguration mockARC = mock(AudioRecordingConfiguration.class); when(mockARC.getClientUid()).thenReturn(TEST_UID_OTHER); when(mockARC.isClientSilenced()).thenReturn(true); // Multiple recording configs, which are all silenced AudioRecordingConfiguration mockARCOne = mock(AudioRecordingConfiguration.class); when(mockARCOne.getClientUid()).thenReturn(TEST_UID_OTHER); when(mockARCOne.isClientSilenced()).thenReturn(true); AudioRecordingConfiguration mockARCTwo = mock(AudioRecordingConfiguration.class); when(mockARCTwo.getClientUid()).thenReturn(TEST_UID_OTHER); when(mockARCTwo.isClientSilenced()).thenReturn(true); mRecordingCallback.onRecordingConfigChanged(List.of(mockARC)); mRecordingCallback.onRecordingConfigChanged(List.of(mockARCOne, mockARCTwo)); mTestableLooper.processAllMessages(); InOrder inOrder = inOrder(mCallback); Loading @@ -1009,6 +1023,8 @@ public class AppOpsControllerTest extends SysuiTestCase { micOpCode, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); inOrder.verify(mCallback).onActiveStateChanged( micOpCode, TEST_UID_OTHER, TEST_PACKAGE_NAME, false); // For consistency since this runs in a loop mController.removeCallback(new int[]{micOpCode}, mCallback); } private void verifySingleActiveOps(int op) { Loading