Loading services/core/java/com/android/server/notification/NotificationManagerService.java +43 −6 Original line number Diff line number Diff line Loading @@ -631,6 +631,8 @@ public class NotificationManagerService extends SystemService { // Minium number of sparse groups for a package before autogrouping them private static final int AUTOGROUP_SPARSE_GROUPS_AT_COUNT = 3; private static final Duration ZEN_BROADCAST_DELAY = Duration.ofMillis(250); private IActivityManager mAm; private ActivityTaskManagerInternal mAtm; private ActivityManager mActivityManager; Loading Loading @@ -3169,6 +3171,24 @@ public class NotificationManagerService extends SystemService { sendRegisteredOnlyBroadcast(new Intent(action)); } /** * Schedules a broadcast to be sent to runtime receivers and DND-policy-access packages. The * broadcast will be sent after {@link #ZEN_BROADCAST_DELAY}, unless a new broadcast is * scheduled in the interim, in which case the previous one is dropped and the waiting period * is <em>restarted</em>. * * <p>Note that this uses <em>equality of the {@link Intent#getAction}</em> as the criteria for * deduplicating pending broadcasts, ignoring the extras and anything else. This is intentional * so that e.g. rapidly changing some value A -> B -> C will only produce a broadcast for C * (instead of every time because the extras are different). */ private void sendZenBroadcastWithDelay(Intent intent) { String token = "zen_broadcast:" + intent.getAction(); mHandler.removeCallbacksAndEqualMessages(token); mHandler.postDelayed(() -> sendRegisteredOnlyBroadcast(intent), token, ZEN_BROADCAST_DELAY.toMillis()); } private void sendRegisteredOnlyBroadcast(Intent baseIntent) { int[] userIds = mUmInternal.getProfileIds(mAmi.getCurrentUserId(), true); if (Flags.nmBinderPerfReduceZenBroadcasts()) { Loading Loading @@ -3362,15 +3382,26 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mNotificationLock") private void updateEffectsSuppressorLocked() { final long oldSuppressedEffects = mZenModeHelper.getSuppressedEffects(); final long updatedSuppressedEffects = calculateSuppressedEffects(); if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return; if (updatedSuppressedEffects == oldSuppressedEffects) return; final List<ComponentName> suppressors = getSuppressors(); ZenLog.traceEffectsSuppressorChanged( mEffectsSuppressors, suppressors, updatedSuppressedEffects); mEffectsSuppressors = suppressors; mEffectsSuppressors, suppressors, oldSuppressedEffects, updatedSuppressedEffects); mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects); if (Flags.nmBinderPerfThrottleEffectsSuppressorBroadcast()) { if (!suppressors.equals(mEffectsSuppressors)) { mEffectsSuppressors = suppressors; sendZenBroadcastWithDelay( new Intent(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED)); } } else { mEffectsSuppressors = suppressors; sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); } } private void exitIdle() { if (mDeviceIdleManager != null) { Loading Loading @@ -3491,13 +3522,19 @@ public class NotificationManagerService extends SystemService { } private ArrayList<ComponentName> getSuppressors() { ArrayList<ComponentName> names = new ArrayList<ComponentName>(); ArrayList<ComponentName> names = new ArrayList<>(); for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i); for (ComponentName info : serviceInfoList) { if (Flags.nmBinderPerfThrottleEffectsSuppressorBroadcast()) { if (!names.contains(info)) { names.add(info); } } else { names.add(info); } } } return names; Loading services/core/java/com/android/server/notification/ZenLog.java +3 −2 Original line number Diff line number Diff line Loading @@ -140,8 +140,9 @@ public class ZenLog { } public static void traceEffectsSuppressorChanged(List<ComponentName> oldSuppressors, List<ComponentName> newSuppressors, long suppressedEffects) { append(TYPE_SUPPRESSOR_CHANGED, "suppressed effects:" + suppressedEffects + "," List<ComponentName> newSuppressors, long oldSuppressedEffects, long suppressedEffects) { append(TYPE_SUPPRESSOR_CHANGED, "suppressed effects:" + oldSuppressedEffects + "->" + suppressedEffects + "," + componentListToString(oldSuppressors) + "->" + componentListToString(newSuppressors)); } Loading services/core/java/com/android/server/notification/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -181,6 +181,16 @@ flag { } } flag { name: "nm_binder_perf_throttle_effects_suppressor_broadcast" namespace: "systemui" description: "Delay sending the ACTION_EFFECTS_SUPPRESSOR_CHANGED broadcast if it changes too often" bug: "371776935" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "fix_calling_uid_from_cps" namespace: "systemui" Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +74 −5 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import static android.app.NotificationChannel.RECS_ID; import static android.app.NotificationChannel.SOCIAL_MEDIA_ID; import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE; import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED; import static android.app.NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED; import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED; import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ACTIVATED; import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; Loading Loading @@ -123,7 +124,9 @@ import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICAT import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS; import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; import static android.service.notification.NotificationListenerService.REASON_CANCEL; import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN; Loading Loading @@ -163,6 +166,7 @@ import static junit.framework.Assert.fail; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyLong; Loading Loading @@ -360,7 +364,6 @@ import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.ArgumentMatchers; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mockito; Loading @@ -368,6 +371,9 @@ import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import platform.test.runner.parameterized.ParameterizedAndroidJunit4; import platform.test.runner.parameterized.Parameters; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; Loading @@ -383,9 +389,6 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; import platform.test.runner.parameterized.ParameterizedAndroidJunit4; import platform.test.runner.parameterized.Parameters; @SmallTest @RunWith(ParameterizedAndroidJunit4.class) @RunWithLooper Loading Loading @@ -11413,8 +11416,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mContext).sendBroadcastAsUser(eqIntent(expected), eq(UserHandle.of(mUserId))); } private static Intent isIntentWithAction(String wantedAction) { return argThat( intent -> intent != null && wantedAction.equals(intent.getAction()) ); } private static Intent eqIntent(Intent wanted) { return ArgumentMatchers.argThat( return argThat( new ArgumentMatcher<Intent>() { @Override public boolean matches(Intent argument) { Loading Loading @@ -17490,6 +17499,66 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component); } @Test @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_EFFECTS_SUPPRESSOR_BROADCAST, Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS}) public void requestHintsFromListener_changingEffectsButNotSuppressor_noBroadcast() throws Exception { // Note that NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS is not strictly necessary; however each // path will do slightly different calls so we force one of them to simplify the test. when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); INotificationListener token = mock(INotificationListener.class); mService.isSystemUid = true; mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_CALL_EFFECTS); mTestableLooper.moveTimeForward(500); // more than ZEN_BROADCAST_DELAY waitForIdle(); verify(mContext, times(1)).sendBroadcastMultiplePermissions( isIntentWithAction(ACTION_EFFECTS_SUPPRESSOR_CHANGED), any(), any(), any()); // Same suppressor suppresses something else. mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); mTestableLooper.moveTimeForward(500); // more than ZEN_BROADCAST_DELAY waitForIdle(); // Still 1 total calls (the previous one). verify(mContext, times(1)).sendBroadcastMultiplePermissions( isIntentWithAction(ACTION_EFFECTS_SUPPRESSOR_CHANGED), any(), any(), any()); } @Test @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_EFFECTS_SUPPRESSOR_BROADCAST, Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS}) public void requestHintsFromListener_changingSuppressor_throttlesBroadcast() throws Exception { // Note that NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS is not strictly necessary; however each // path will do slightly different calls so we force one of them to simplify the test. when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); INotificationListener token = mock(INotificationListener.class); mService.isSystemUid = true; // Several updates in quick succession. mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_CALL_EFFECTS); mBinderService.clearRequestedListenerHints(token); mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); mBinderService.clearRequestedListenerHints(token); mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_CALL_EFFECTS); mBinderService.clearRequestedListenerHints(token); mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); // No broadcasts yet! verify(mContext, never()).sendBroadcastMultiplePermissions(any(), any(), any(), any()); mTestableLooper.moveTimeForward(500); // more than ZEN_BROADCAST_DELAY waitForIdle(); // Only one broadcast after idle time. verify(mContext, times(1)).sendBroadcastMultiplePermissions( isIntentWithAction(ACTION_EFFECTS_SUPPRESSOR_CHANGED), any(), any(), any()); } @Test @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) public void testApplyAdjustment_keyType_validType() throws Exception { Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +43 −6 Original line number Diff line number Diff line Loading @@ -631,6 +631,8 @@ public class NotificationManagerService extends SystemService { // Minium number of sparse groups for a package before autogrouping them private static final int AUTOGROUP_SPARSE_GROUPS_AT_COUNT = 3; private static final Duration ZEN_BROADCAST_DELAY = Duration.ofMillis(250); private IActivityManager mAm; private ActivityTaskManagerInternal mAtm; private ActivityManager mActivityManager; Loading Loading @@ -3169,6 +3171,24 @@ public class NotificationManagerService extends SystemService { sendRegisteredOnlyBroadcast(new Intent(action)); } /** * Schedules a broadcast to be sent to runtime receivers and DND-policy-access packages. The * broadcast will be sent after {@link #ZEN_BROADCAST_DELAY}, unless a new broadcast is * scheduled in the interim, in which case the previous one is dropped and the waiting period * is <em>restarted</em>. * * <p>Note that this uses <em>equality of the {@link Intent#getAction}</em> as the criteria for * deduplicating pending broadcasts, ignoring the extras and anything else. This is intentional * so that e.g. rapidly changing some value A -> B -> C will only produce a broadcast for C * (instead of every time because the extras are different). */ private void sendZenBroadcastWithDelay(Intent intent) { String token = "zen_broadcast:" + intent.getAction(); mHandler.removeCallbacksAndEqualMessages(token); mHandler.postDelayed(() -> sendRegisteredOnlyBroadcast(intent), token, ZEN_BROADCAST_DELAY.toMillis()); } private void sendRegisteredOnlyBroadcast(Intent baseIntent) { int[] userIds = mUmInternal.getProfileIds(mAmi.getCurrentUserId(), true); if (Flags.nmBinderPerfReduceZenBroadcasts()) { Loading Loading @@ -3362,15 +3382,26 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mNotificationLock") private void updateEffectsSuppressorLocked() { final long oldSuppressedEffects = mZenModeHelper.getSuppressedEffects(); final long updatedSuppressedEffects = calculateSuppressedEffects(); if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return; if (updatedSuppressedEffects == oldSuppressedEffects) return; final List<ComponentName> suppressors = getSuppressors(); ZenLog.traceEffectsSuppressorChanged( mEffectsSuppressors, suppressors, updatedSuppressedEffects); mEffectsSuppressors = suppressors; mEffectsSuppressors, suppressors, oldSuppressedEffects, updatedSuppressedEffects); mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects); if (Flags.nmBinderPerfThrottleEffectsSuppressorBroadcast()) { if (!suppressors.equals(mEffectsSuppressors)) { mEffectsSuppressors = suppressors; sendZenBroadcastWithDelay( new Intent(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED)); } } else { mEffectsSuppressors = suppressors; sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); } } private void exitIdle() { if (mDeviceIdleManager != null) { Loading Loading @@ -3491,13 +3522,19 @@ public class NotificationManagerService extends SystemService { } private ArrayList<ComponentName> getSuppressors() { ArrayList<ComponentName> names = new ArrayList<ComponentName>(); ArrayList<ComponentName> names = new ArrayList<>(); for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i); for (ComponentName info : serviceInfoList) { if (Flags.nmBinderPerfThrottleEffectsSuppressorBroadcast()) { if (!names.contains(info)) { names.add(info); } } else { names.add(info); } } } return names; Loading
services/core/java/com/android/server/notification/ZenLog.java +3 −2 Original line number Diff line number Diff line Loading @@ -140,8 +140,9 @@ public class ZenLog { } public static void traceEffectsSuppressorChanged(List<ComponentName> oldSuppressors, List<ComponentName> newSuppressors, long suppressedEffects) { append(TYPE_SUPPRESSOR_CHANGED, "suppressed effects:" + suppressedEffects + "," List<ComponentName> newSuppressors, long oldSuppressedEffects, long suppressedEffects) { append(TYPE_SUPPRESSOR_CHANGED, "suppressed effects:" + oldSuppressedEffects + "->" + suppressedEffects + "," + componentListToString(oldSuppressors) + "->" + componentListToString(newSuppressors)); } Loading
services/core/java/com/android/server/notification/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -181,6 +181,16 @@ flag { } } flag { name: "nm_binder_perf_throttle_effects_suppressor_broadcast" namespace: "systemui" description: "Delay sending the ACTION_EFFECTS_SUPPRESSOR_CHANGED broadcast if it changes too often" bug: "371776935" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "fix_calling_uid_from_cps" namespace: "systemui" Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +74 −5 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import static android.app.NotificationChannel.RECS_ID; import static android.app.NotificationChannel.SOCIAL_MEDIA_ID; import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE; import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED; import static android.app.NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED; import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED; import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ACTIVATED; import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; Loading Loading @@ -123,7 +124,9 @@ import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICAT import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS; import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; import static android.service.notification.NotificationListenerService.REASON_CANCEL; import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN; Loading Loading @@ -163,6 +166,7 @@ import static junit.framework.Assert.fail; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyLong; Loading Loading @@ -360,7 +364,6 @@ import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.ArgumentMatchers; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mockito; Loading @@ -368,6 +371,9 @@ import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import platform.test.runner.parameterized.ParameterizedAndroidJunit4; import platform.test.runner.parameterized.Parameters; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; Loading @@ -383,9 +389,6 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; import platform.test.runner.parameterized.ParameterizedAndroidJunit4; import platform.test.runner.parameterized.Parameters; @SmallTest @RunWith(ParameterizedAndroidJunit4.class) @RunWithLooper Loading Loading @@ -11413,8 +11416,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mContext).sendBroadcastAsUser(eqIntent(expected), eq(UserHandle.of(mUserId))); } private static Intent isIntentWithAction(String wantedAction) { return argThat( intent -> intent != null && wantedAction.equals(intent.getAction()) ); } private static Intent eqIntent(Intent wanted) { return ArgumentMatchers.argThat( return argThat( new ArgumentMatcher<Intent>() { @Override public boolean matches(Intent argument) { Loading Loading @@ -17490,6 +17499,66 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component); } @Test @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_EFFECTS_SUPPRESSOR_BROADCAST, Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS}) public void requestHintsFromListener_changingEffectsButNotSuppressor_noBroadcast() throws Exception { // Note that NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS is not strictly necessary; however each // path will do slightly different calls so we force one of them to simplify the test. when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); INotificationListener token = mock(INotificationListener.class); mService.isSystemUid = true; mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_CALL_EFFECTS); mTestableLooper.moveTimeForward(500); // more than ZEN_BROADCAST_DELAY waitForIdle(); verify(mContext, times(1)).sendBroadcastMultiplePermissions( isIntentWithAction(ACTION_EFFECTS_SUPPRESSOR_CHANGED), any(), any(), any()); // Same suppressor suppresses something else. mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); mTestableLooper.moveTimeForward(500); // more than ZEN_BROADCAST_DELAY waitForIdle(); // Still 1 total calls (the previous one). verify(mContext, times(1)).sendBroadcastMultiplePermissions( isIntentWithAction(ACTION_EFFECTS_SUPPRESSOR_CHANGED), any(), any(), any()); } @Test @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_EFFECTS_SUPPRESSOR_BROADCAST, Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS}) public void requestHintsFromListener_changingSuppressor_throttlesBroadcast() throws Exception { // Note that NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS is not strictly necessary; however each // path will do slightly different calls so we force one of them to simplify the test. when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); INotificationListener token = mock(INotificationListener.class); mService.isSystemUid = true; // Several updates in quick succession. mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_CALL_EFFECTS); mBinderService.clearRequestedListenerHints(token); mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); mBinderService.clearRequestedListenerHints(token); mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_CALL_EFFECTS); mBinderService.clearRequestedListenerHints(token); mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); // No broadcasts yet! verify(mContext, never()).sendBroadcastMultiplePermissions(any(), any(), any(), any()); mTestableLooper.moveTimeForward(500); // more than ZEN_BROADCAST_DELAY waitForIdle(); // Only one broadcast after idle time. verify(mContext, times(1)).sendBroadcastMultiplePermissions( isIntentWithAction(ACTION_EFFECTS_SUPPRESSOR_CHANGED), any(), any(), any()); } @Test @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) public void testApplyAdjustment_keyType_validType() throws Exception {