Loading packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +28 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import com.android.systemui.util.time.SystemClock; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import javax.inject.Inject; Loading Loading @@ -145,6 +146,10 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon protected void setListening(boolean listening) { mListening = listening; if (listening) { // System UI could be restarted while ops are active, so fetch the currently active ops // once System UI starts listening again. fetchCurrentActiveOps(); mAppOps.startWatchingActive(OPS, this); mAppOps.startWatchingNoted(OPS, this); mAudioManager.registerAudioRecordingCallback(mAudioRecordingCallback, mBGHandler); Loading Loading @@ -177,6 +182,29 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon } } private void fetchCurrentActiveOps() { List<AppOpsManager.PackageOps> packageOps = mAppOps.getPackagesForOps(OPS); for (AppOpsManager.PackageOps op : packageOps) { for (AppOpsManager.OpEntry entry : op.getOps()) { for (Map.Entry<String, AppOpsManager.AttributedOpEntry> attributedOpEntry : entry.getAttributedOpEntries().entrySet()) { if (attributedOpEntry.getValue().isRunning()) { onOpActiveChanged( entry.getOpStr(), op.getUid(), op.getPackageName(), /* attributionTag= */ attributedOpEntry.getKey(), /* active= */ true, // AppOpsManager doesn't have a way to fetch attribution flags or // chain ID given an op entry, so default them to none. AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE); } } } } } /** * Adds a callback that will get notifified when an AppOp of the type the controller tracks * changes Loading packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt +3 −2 Original line number Diff line number Diff line Loading @@ -132,8 +132,9 @@ constructor( override fun onStatusEvent(event: StatusEvent) { Assert.isMainThread() // Ignore any updates until the system is up and running if (isTooEarly() || !isImmersiveIndicatorEnabled()) { // Ignore any updates until the system is up and running. However, for important events that // request to be force visible (like privacy), ignore whether it's too early. if ((isTooEarly() && !event.forceVisible) || !isImmersiveIndicatorEnabled()) { return } Loading packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt +3 −2 Original line number Diff line number Diff line Loading @@ -93,8 +93,9 @@ constructor( @SystemAnimationState override fun getAnimationState() = animationState override fun onStatusEvent(event: StatusEvent) { // Ignore any updates until the system is up and running if (isTooEarly() || !isImmersiveIndicatorEnabled()) { // Ignore any updates until the system is up and running. However, for important events that // request to be force visible (like privacy), ignore whether it's too early. if ((isTooEarly() && !event.forceVisible) || !isImmersiveIndicatorEnabled()) { return } Loading packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +217 −0 Original line number Diff line number Diff line Loading @@ -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.google.common.truth.Truth.assertThat; import static junit.framework.TestCase.assertFalse; import static org.junit.Assert.assertEquals; Loading Loading @@ -66,6 +68,7 @@ import org.mockito.MockitoAnnotations; import java.util.Collections; import java.util.List; import java.util.Map; @SmallTest @RunWith(AndroidTestingRunner.class) Loading Loading @@ -157,6 +160,204 @@ public class AppOpsControllerTest extends SysuiTestCase { verify(mSensorPrivacyController, times(1)).removeCallback(mController); } @Test public void startListening_fetchesCurrentActive_none() { when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) .thenReturn(List.of()); mController.setListening(true); assertThat(mController.getActiveAppOps()).isEmpty(); } /** Regression test for b/294104969. */ @Test public void startListening_fetchesCurrentActive_oneActive() { AppOpsManager.PackageOps packageOps = createPackageOp( "package.test", /* packageUid= */ 2, AppOpsManager.OPSTR_FINE_LOCATION, /* isRunning= */ true); when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) .thenReturn(List.of(packageOps)); // WHEN we start listening mController.setListening(true); // THEN the active list has the op List<AppOpItem> list = mController.getActiveAppOps(); assertEquals(1, list.size()); AppOpItem first = list.get(0); assertThat(first.getPackageName()).isEqualTo("package.test"); assertThat(first.getUid()).isEqualTo(2); assertThat(first.getCode()).isEqualTo(AppOpsManager.OP_FINE_LOCATION); } @Test public void startListening_fetchesCurrentActive_multiplePackages() { AppOpsManager.PackageOps packageOps1 = createPackageOp( "package.one", /* packageUid= */ 1, AppOpsManager.OPSTR_FINE_LOCATION, /* isRunning= */ true); AppOpsManager.PackageOps packageOps2 = createPackageOp( "package.two", /* packageUid= */ 2, AppOpsManager.OPSTR_FINE_LOCATION, /* isRunning= */ false); AppOpsManager.PackageOps packageOps3 = createPackageOp( "package.three", /* packageUid= */ 3, AppOpsManager.OPSTR_FINE_LOCATION, /* isRunning= */ true); when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) .thenReturn(List.of(packageOps1, packageOps2, packageOps3)); // WHEN we start listening mController.setListening(true); // THEN the active list has the ops List<AppOpItem> list = mController.getActiveAppOps(); assertEquals(2, list.size()); AppOpItem item0 = list.get(0); assertThat(item0.getPackageName()).isEqualTo("package.one"); assertThat(item0.getUid()).isEqualTo(1); assertThat(item0.getCode()).isEqualTo(AppOpsManager.OP_FINE_LOCATION); AppOpItem item1 = list.get(1); assertThat(item1.getPackageName()).isEqualTo("package.three"); assertThat(item1.getUid()).isEqualTo(3); assertThat(item1.getCode()).isEqualTo(AppOpsManager.OP_FINE_LOCATION); } @Test public void startListening_fetchesCurrentActive_multipleEntries() { AppOpsManager.PackageOps packageOps = mock(AppOpsManager.PackageOps.class); when(packageOps.getUid()).thenReturn(1); when(packageOps.getPackageName()).thenReturn("package.one"); // Entry 1 AppOpsManager.OpEntry entry1 = mock(AppOpsManager.OpEntry.class); when(entry1.getOpStr()).thenReturn(AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE); AppOpsManager.AttributedOpEntry attributed1 = mock(AppOpsManager.AttributedOpEntry.class); when(attributed1.isRunning()).thenReturn(true); when(entry1.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed1)); // Entry 2 AppOpsManager.OpEntry entry2 = mock(AppOpsManager.OpEntry.class); when(entry2.getOpStr()).thenReturn(AppOpsManager.OPSTR_CAMERA); AppOpsManager.AttributedOpEntry attributed2 = mock(AppOpsManager.AttributedOpEntry.class); when(attributed2.isRunning()).thenReturn(true); when(entry2.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed2)); // Entry 3 AppOpsManager.OpEntry entry3 = mock(AppOpsManager.OpEntry.class); when(entry3.getOpStr()).thenReturn(AppOpsManager.OPSTR_FINE_LOCATION); AppOpsManager.AttributedOpEntry attributed3 = mock(AppOpsManager.AttributedOpEntry.class); when(attributed3.isRunning()).thenReturn(false); when(entry3.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed3)); when(packageOps.getOps()).thenReturn(List.of(entry1, entry2, entry3)); when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) .thenReturn(List.of(packageOps)); // WHEN we start listening mController.setListening(true); // THEN the active list has the ops List<AppOpItem> list = mController.getActiveAppOps(); assertEquals(2, list.size()); AppOpItem first = list.get(0); assertThat(first.getPackageName()).isEqualTo("package.one"); assertThat(first.getUid()).isEqualTo(1); assertThat(first.getCode()).isEqualTo(AppOpsManager.OP_PHONE_CALL_MICROPHONE); AppOpItem second = list.get(1); assertThat(second.getPackageName()).isEqualTo("package.one"); assertThat(second.getUid()).isEqualTo(1); assertThat(second.getCode()).isEqualTo(AppOpsManager.OP_CAMERA); } @Test public void startListening_fetchesCurrentActive_multipleAttributes() { AppOpsManager.PackageOps packageOps = mock(AppOpsManager.PackageOps.class); when(packageOps.getUid()).thenReturn(1); when(packageOps.getPackageName()).thenReturn("package.one"); AppOpsManager.OpEntry entry = mock(AppOpsManager.OpEntry.class); when(entry.getOpStr()).thenReturn(AppOpsManager.OPSTR_RECORD_AUDIO); AppOpsManager.AttributedOpEntry attributed1 = mock(AppOpsManager.AttributedOpEntry.class); when(attributed1.isRunning()).thenReturn(false); AppOpsManager.AttributedOpEntry attributed2 = mock(AppOpsManager.AttributedOpEntry.class); when(attributed2.isRunning()).thenReturn(true); AppOpsManager.AttributedOpEntry attributed3 = mock(AppOpsManager.AttributedOpEntry.class); when(attributed3.isRunning()).thenReturn(true); when(entry.getAttributedOpEntries()).thenReturn( Map.of("attr1", attributed1, "attr2", attributed2, "attr3", attributed3)); when(packageOps.getOps()).thenReturn(List.of(entry)); when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) .thenReturn(List.of(packageOps)); // WHEN we start listening mController.setListening(true); // THEN the active list has the ops List<AppOpItem> list = mController.getActiveAppOps(); // Multiple attributes get merged into one entry in the active ops assertEquals(1, list.size()); AppOpItem first = list.get(0); assertThat(first.getPackageName()).isEqualTo("package.one"); assertThat(first.getUid()).isEqualTo(1); assertThat(first.getCode()).isEqualTo(AppOpsManager.OP_RECORD_AUDIO); } /** Regression test for b/294104969. */ @Test public void addCallback_existingCallbacksNotifiedOfCurrentActive() { AppOpsManager.PackageOps packageOps1 = createPackageOp( "package.one", /* packageUid= */ 1, AppOpsManager.OPSTR_FINE_LOCATION, /* isRunning= */ true); AppOpsManager.PackageOps packageOps2 = createPackageOp( "package.two", /* packageUid= */ 2, AppOpsManager.OPSTR_RECORD_AUDIO, /* isRunning= */ true); AppOpsManager.PackageOps packageOps3 = createPackageOp( "package.three", /* packageUid= */ 3, AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE, /* isRunning= */ true); when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) .thenReturn(List.of(packageOps1, packageOps2, packageOps3)); // WHEN we start listening mController.addCallback( new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_FINE_LOCATION}, mCallback); mTestableLooper.processAllMessages(); // THEN the callback is notified of the current active ops it cares about verify(mCallback).onActiveStateChanged( AppOpsManager.OP_FINE_LOCATION, /* uid= */ 1, "package.one", true); verify(mCallback).onActiveStateChanged( AppOpsManager.OP_RECORD_AUDIO, /* uid= */ 2, "package.two", true); verify(mCallback, never()).onActiveStateChanged( AppOpsManager.OP_PHONE_CALL_MICROPHONE, /* uid= */ 3, "package.three", true); } @Test public void addCallback_includedCode() { mController.addCallback( Loading Loading @@ -673,6 +874,22 @@ public class AppOpsControllerTest extends SysuiTestCase { assertEquals(AppOpsManager.OP_PHONE_CALL_CAMERA, list.get(cameraIdx).getCode()); } private AppOpsManager.PackageOps createPackageOp( String packageName, int packageUid, String opStr, boolean isRunning) { AppOpsManager.PackageOps packageOps = mock(AppOpsManager.PackageOps.class); when(packageOps.getPackageName()).thenReturn(packageName); when(packageOps.getUid()).thenReturn(packageUid); AppOpsManager.OpEntry entry = mock(AppOpsManager.OpEntry.class); when(entry.getOpStr()).thenReturn(opStr); AppOpsManager.AttributedOpEntry attributed = mock(AppOpsManager.AttributedOpEntry.class); when(attributed.isRunning()).thenReturn(isRunning); when(packageOps.getOps()).thenReturn(Collections.singletonList(entry)); when(entry.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed)); return packageOps; } private class TestHandler extends AppOpsControllerImpl.H { TestHandler(Looper looper) { mController.super(looper); Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt +24 −4 Original line number Diff line number Diff line Loading @@ -93,9 +93,6 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() { fakeFeatureFlags ) // ensure that isTooEarly() check in SystemStatusAnimationScheduler does not return true systemClock.advanceTime(Process.getStartUptimeMillis() + MIN_UPTIME) // StatusBarContentInsetProvider is mocked. Ensure that it returns some mocked values. whenever(statusBarContentInsetProvider.getStatusBarContentInsetsForCurrentRotation()) .thenReturn(android.util.Pair(10, 10)) Loading Loading @@ -156,6 +153,21 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() { assertEquals(0f, batteryChip.view.alpha) } /** Regression test for b/294104969. */ @Test fun testPrivacyStatusEvent_beforeSystemUptime_stillDisplayed() = runTest { initializeSystemStatusAnimationScheduler(testScope = this, advancePastMinUptime = false) // WHEN the uptime hasn't quite passed the minimum required uptime... systemClock.setUptimeMillis(Process.getStartUptimeMillis() + MIN_UPTIME / 2) // BUT the event is a privacy event createAndScheduleFakePrivacyEvent() // THEN the privacy event still happens assertEquals(ANIMATION_QUEUED, systemStatusAnimationScheduler.getAnimationState()) } @Test fun testPrivacyStatusEvent_standardAnimationLifecycle() = runTest { // Instantiate class under test with TestScope from runTest Loading Loading @@ -568,7 +580,10 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() { return batteryChip } private fun initializeSystemStatusAnimationScheduler(testScope: TestScope) { private fun initializeSystemStatusAnimationScheduler( testScope: TestScope, advancePastMinUptime: Boolean = true, ) { systemStatusAnimationScheduler = SystemStatusAnimationSchedulerImpl( systemEventCoordinator, Loading @@ -581,5 +596,10 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() { ) // add a mock listener systemStatusAnimationScheduler.addCallback(listener) if (advancePastMinUptime) { // ensure that isTooEarly() check in SystemStatusAnimationScheduler does not return true systemClock.advanceTime(Process.getStartUptimeMillis() + MIN_UPTIME) } } } Loading
packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +28 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import com.android.systemui.util.time.SystemClock; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import javax.inject.Inject; Loading Loading @@ -145,6 +146,10 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon protected void setListening(boolean listening) { mListening = listening; if (listening) { // System UI could be restarted while ops are active, so fetch the currently active ops // once System UI starts listening again. fetchCurrentActiveOps(); mAppOps.startWatchingActive(OPS, this); mAppOps.startWatchingNoted(OPS, this); mAudioManager.registerAudioRecordingCallback(mAudioRecordingCallback, mBGHandler); Loading Loading @@ -177,6 +182,29 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon } } private void fetchCurrentActiveOps() { List<AppOpsManager.PackageOps> packageOps = mAppOps.getPackagesForOps(OPS); for (AppOpsManager.PackageOps op : packageOps) { for (AppOpsManager.OpEntry entry : op.getOps()) { for (Map.Entry<String, AppOpsManager.AttributedOpEntry> attributedOpEntry : entry.getAttributedOpEntries().entrySet()) { if (attributedOpEntry.getValue().isRunning()) { onOpActiveChanged( entry.getOpStr(), op.getUid(), op.getPackageName(), /* attributionTag= */ attributedOpEntry.getKey(), /* active= */ true, // AppOpsManager doesn't have a way to fetch attribution flags or // chain ID given an op entry, so default them to none. AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE); } } } } } /** * Adds a callback that will get notifified when an AppOp of the type the controller tracks * changes Loading
packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt +3 −2 Original line number Diff line number Diff line Loading @@ -132,8 +132,9 @@ constructor( override fun onStatusEvent(event: StatusEvent) { Assert.isMainThread() // Ignore any updates until the system is up and running if (isTooEarly() || !isImmersiveIndicatorEnabled()) { // Ignore any updates until the system is up and running. However, for important events that // request to be force visible (like privacy), ignore whether it's too early. if ((isTooEarly() && !event.forceVisible) || !isImmersiveIndicatorEnabled()) { return } Loading
packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt +3 −2 Original line number Diff line number Diff line Loading @@ -93,8 +93,9 @@ constructor( @SystemAnimationState override fun getAnimationState() = animationState override fun onStatusEvent(event: StatusEvent) { // Ignore any updates until the system is up and running if (isTooEarly() || !isImmersiveIndicatorEnabled()) { // Ignore any updates until the system is up and running. However, for important events that // request to be force visible (like privacy), ignore whether it's too early. if ((isTooEarly() && !event.forceVisible) || !isImmersiveIndicatorEnabled()) { return } Loading
packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +217 −0 Original line number Diff line number Diff line Loading @@ -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.google.common.truth.Truth.assertThat; import static junit.framework.TestCase.assertFalse; import static org.junit.Assert.assertEquals; Loading Loading @@ -66,6 +68,7 @@ import org.mockito.MockitoAnnotations; import java.util.Collections; import java.util.List; import java.util.Map; @SmallTest @RunWith(AndroidTestingRunner.class) Loading Loading @@ -157,6 +160,204 @@ public class AppOpsControllerTest extends SysuiTestCase { verify(mSensorPrivacyController, times(1)).removeCallback(mController); } @Test public void startListening_fetchesCurrentActive_none() { when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) .thenReturn(List.of()); mController.setListening(true); assertThat(mController.getActiveAppOps()).isEmpty(); } /** Regression test for b/294104969. */ @Test public void startListening_fetchesCurrentActive_oneActive() { AppOpsManager.PackageOps packageOps = createPackageOp( "package.test", /* packageUid= */ 2, AppOpsManager.OPSTR_FINE_LOCATION, /* isRunning= */ true); when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) .thenReturn(List.of(packageOps)); // WHEN we start listening mController.setListening(true); // THEN the active list has the op List<AppOpItem> list = mController.getActiveAppOps(); assertEquals(1, list.size()); AppOpItem first = list.get(0); assertThat(first.getPackageName()).isEqualTo("package.test"); assertThat(first.getUid()).isEqualTo(2); assertThat(first.getCode()).isEqualTo(AppOpsManager.OP_FINE_LOCATION); } @Test public void startListening_fetchesCurrentActive_multiplePackages() { AppOpsManager.PackageOps packageOps1 = createPackageOp( "package.one", /* packageUid= */ 1, AppOpsManager.OPSTR_FINE_LOCATION, /* isRunning= */ true); AppOpsManager.PackageOps packageOps2 = createPackageOp( "package.two", /* packageUid= */ 2, AppOpsManager.OPSTR_FINE_LOCATION, /* isRunning= */ false); AppOpsManager.PackageOps packageOps3 = createPackageOp( "package.three", /* packageUid= */ 3, AppOpsManager.OPSTR_FINE_LOCATION, /* isRunning= */ true); when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) .thenReturn(List.of(packageOps1, packageOps2, packageOps3)); // WHEN we start listening mController.setListening(true); // THEN the active list has the ops List<AppOpItem> list = mController.getActiveAppOps(); assertEquals(2, list.size()); AppOpItem item0 = list.get(0); assertThat(item0.getPackageName()).isEqualTo("package.one"); assertThat(item0.getUid()).isEqualTo(1); assertThat(item0.getCode()).isEqualTo(AppOpsManager.OP_FINE_LOCATION); AppOpItem item1 = list.get(1); assertThat(item1.getPackageName()).isEqualTo("package.three"); assertThat(item1.getUid()).isEqualTo(3); assertThat(item1.getCode()).isEqualTo(AppOpsManager.OP_FINE_LOCATION); } @Test public void startListening_fetchesCurrentActive_multipleEntries() { AppOpsManager.PackageOps packageOps = mock(AppOpsManager.PackageOps.class); when(packageOps.getUid()).thenReturn(1); when(packageOps.getPackageName()).thenReturn("package.one"); // Entry 1 AppOpsManager.OpEntry entry1 = mock(AppOpsManager.OpEntry.class); when(entry1.getOpStr()).thenReturn(AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE); AppOpsManager.AttributedOpEntry attributed1 = mock(AppOpsManager.AttributedOpEntry.class); when(attributed1.isRunning()).thenReturn(true); when(entry1.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed1)); // Entry 2 AppOpsManager.OpEntry entry2 = mock(AppOpsManager.OpEntry.class); when(entry2.getOpStr()).thenReturn(AppOpsManager.OPSTR_CAMERA); AppOpsManager.AttributedOpEntry attributed2 = mock(AppOpsManager.AttributedOpEntry.class); when(attributed2.isRunning()).thenReturn(true); when(entry2.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed2)); // Entry 3 AppOpsManager.OpEntry entry3 = mock(AppOpsManager.OpEntry.class); when(entry3.getOpStr()).thenReturn(AppOpsManager.OPSTR_FINE_LOCATION); AppOpsManager.AttributedOpEntry attributed3 = mock(AppOpsManager.AttributedOpEntry.class); when(attributed3.isRunning()).thenReturn(false); when(entry3.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed3)); when(packageOps.getOps()).thenReturn(List.of(entry1, entry2, entry3)); when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) .thenReturn(List.of(packageOps)); // WHEN we start listening mController.setListening(true); // THEN the active list has the ops List<AppOpItem> list = mController.getActiveAppOps(); assertEquals(2, list.size()); AppOpItem first = list.get(0); assertThat(first.getPackageName()).isEqualTo("package.one"); assertThat(first.getUid()).isEqualTo(1); assertThat(first.getCode()).isEqualTo(AppOpsManager.OP_PHONE_CALL_MICROPHONE); AppOpItem second = list.get(1); assertThat(second.getPackageName()).isEqualTo("package.one"); assertThat(second.getUid()).isEqualTo(1); assertThat(second.getCode()).isEqualTo(AppOpsManager.OP_CAMERA); } @Test public void startListening_fetchesCurrentActive_multipleAttributes() { AppOpsManager.PackageOps packageOps = mock(AppOpsManager.PackageOps.class); when(packageOps.getUid()).thenReturn(1); when(packageOps.getPackageName()).thenReturn("package.one"); AppOpsManager.OpEntry entry = mock(AppOpsManager.OpEntry.class); when(entry.getOpStr()).thenReturn(AppOpsManager.OPSTR_RECORD_AUDIO); AppOpsManager.AttributedOpEntry attributed1 = mock(AppOpsManager.AttributedOpEntry.class); when(attributed1.isRunning()).thenReturn(false); AppOpsManager.AttributedOpEntry attributed2 = mock(AppOpsManager.AttributedOpEntry.class); when(attributed2.isRunning()).thenReturn(true); AppOpsManager.AttributedOpEntry attributed3 = mock(AppOpsManager.AttributedOpEntry.class); when(attributed3.isRunning()).thenReturn(true); when(entry.getAttributedOpEntries()).thenReturn( Map.of("attr1", attributed1, "attr2", attributed2, "attr3", attributed3)); when(packageOps.getOps()).thenReturn(List.of(entry)); when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) .thenReturn(List.of(packageOps)); // WHEN we start listening mController.setListening(true); // THEN the active list has the ops List<AppOpItem> list = mController.getActiveAppOps(); // Multiple attributes get merged into one entry in the active ops assertEquals(1, list.size()); AppOpItem first = list.get(0); assertThat(first.getPackageName()).isEqualTo("package.one"); assertThat(first.getUid()).isEqualTo(1); assertThat(first.getCode()).isEqualTo(AppOpsManager.OP_RECORD_AUDIO); } /** Regression test for b/294104969. */ @Test public void addCallback_existingCallbacksNotifiedOfCurrentActive() { AppOpsManager.PackageOps packageOps1 = createPackageOp( "package.one", /* packageUid= */ 1, AppOpsManager.OPSTR_FINE_LOCATION, /* isRunning= */ true); AppOpsManager.PackageOps packageOps2 = createPackageOp( "package.two", /* packageUid= */ 2, AppOpsManager.OPSTR_RECORD_AUDIO, /* isRunning= */ true); AppOpsManager.PackageOps packageOps3 = createPackageOp( "package.three", /* packageUid= */ 3, AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE, /* isRunning= */ true); when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS)) .thenReturn(List.of(packageOps1, packageOps2, packageOps3)); // WHEN we start listening mController.addCallback( new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_FINE_LOCATION}, mCallback); mTestableLooper.processAllMessages(); // THEN the callback is notified of the current active ops it cares about verify(mCallback).onActiveStateChanged( AppOpsManager.OP_FINE_LOCATION, /* uid= */ 1, "package.one", true); verify(mCallback).onActiveStateChanged( AppOpsManager.OP_RECORD_AUDIO, /* uid= */ 2, "package.two", true); verify(mCallback, never()).onActiveStateChanged( AppOpsManager.OP_PHONE_CALL_MICROPHONE, /* uid= */ 3, "package.three", true); } @Test public void addCallback_includedCode() { mController.addCallback( Loading Loading @@ -673,6 +874,22 @@ public class AppOpsControllerTest extends SysuiTestCase { assertEquals(AppOpsManager.OP_PHONE_CALL_CAMERA, list.get(cameraIdx).getCode()); } private AppOpsManager.PackageOps createPackageOp( String packageName, int packageUid, String opStr, boolean isRunning) { AppOpsManager.PackageOps packageOps = mock(AppOpsManager.PackageOps.class); when(packageOps.getPackageName()).thenReturn(packageName); when(packageOps.getUid()).thenReturn(packageUid); AppOpsManager.OpEntry entry = mock(AppOpsManager.OpEntry.class); when(entry.getOpStr()).thenReturn(opStr); AppOpsManager.AttributedOpEntry attributed = mock(AppOpsManager.AttributedOpEntry.class); when(attributed.isRunning()).thenReturn(isRunning); when(packageOps.getOps()).thenReturn(Collections.singletonList(entry)); when(entry.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed)); return packageOps; } private class TestHandler extends AppOpsControllerImpl.H { TestHandler(Looper looper) { mController.super(looper); Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt +24 −4 Original line number Diff line number Diff line Loading @@ -93,9 +93,6 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() { fakeFeatureFlags ) // ensure that isTooEarly() check in SystemStatusAnimationScheduler does not return true systemClock.advanceTime(Process.getStartUptimeMillis() + MIN_UPTIME) // StatusBarContentInsetProvider is mocked. Ensure that it returns some mocked values. whenever(statusBarContentInsetProvider.getStatusBarContentInsetsForCurrentRotation()) .thenReturn(android.util.Pair(10, 10)) Loading Loading @@ -156,6 +153,21 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() { assertEquals(0f, batteryChip.view.alpha) } /** Regression test for b/294104969. */ @Test fun testPrivacyStatusEvent_beforeSystemUptime_stillDisplayed() = runTest { initializeSystemStatusAnimationScheduler(testScope = this, advancePastMinUptime = false) // WHEN the uptime hasn't quite passed the minimum required uptime... systemClock.setUptimeMillis(Process.getStartUptimeMillis() + MIN_UPTIME / 2) // BUT the event is a privacy event createAndScheduleFakePrivacyEvent() // THEN the privacy event still happens assertEquals(ANIMATION_QUEUED, systemStatusAnimationScheduler.getAnimationState()) } @Test fun testPrivacyStatusEvent_standardAnimationLifecycle() = runTest { // Instantiate class under test with TestScope from runTest Loading Loading @@ -568,7 +580,10 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() { return batteryChip } private fun initializeSystemStatusAnimationScheduler(testScope: TestScope) { private fun initializeSystemStatusAnimationScheduler( testScope: TestScope, advancePastMinUptime: Boolean = true, ) { systemStatusAnimationScheduler = SystemStatusAnimationSchedulerImpl( systemEventCoordinator, Loading @@ -581,5 +596,10 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() { ) // add a mock listener systemStatusAnimationScheduler.addCallback(listener) if (advancePastMinUptime) { // ensure that isTooEarly() check in SystemStatusAnimationScheduler does not return true systemClock.advanceTime(Process.getStartUptimeMillis() + MIN_UPTIME) } } }