1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.notification.collection.coordinator; 18 19 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; 20 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; 21 22 import static org.junit.Assert.assertFalse; 23 import static org.junit.Assert.assertTrue; 24 import static org.mockito.ArgumentMatchers.eq; 25 import static org.mockito.Mockito.times; 26 import static org.mockito.Mockito.verify; 27 import static org.mockito.Mockito.when; 28 29 import android.app.Notification; 30 import android.service.notification.StatusBarNotification; 31 import android.testing.AndroidTestingRunner; 32 33 import androidx.annotation.Nullable; 34 import androidx.test.filters.SmallTest; 35 36 import com.android.systemui.SysuiTestCase; 37 import com.android.systemui.plugins.statusbar.StatusBarStateController; 38 import com.android.systemui.statusbar.RankingBuilder; 39 import com.android.systemui.statusbar.notification.collection.ListEntry; 40 import com.android.systemui.statusbar.notification.collection.NotifPipeline; 41 import com.android.systemui.statusbar.notification.collection.NotificationEntry; 42 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; 43 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; 44 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner; 45 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; 46 import com.android.systemui.statusbar.notification.collection.render.NodeController; 47 import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController; 48 49 import org.junit.Before; 50 import org.junit.Test; 51 import org.junit.runner.RunWith; 52 import org.mockito.ArgumentCaptor; 53 import org.mockito.Captor; 54 import org.mockito.Mock; 55 import org.mockito.Mockito; 56 import org.mockito.MockitoAnnotations; 57 58 import java.util.Arrays; 59 60 @SmallTest 61 @RunWith(AndroidTestingRunner.class) 62 public class RankingCoordinatorTest extends SysuiTestCase { 63 64 @Mock private StatusBarStateController mStatusBarStateController; 65 @Mock private HighPriorityProvider mHighPriorityProvider; 66 @Mock private NotifPipeline mNotifPipeline; 67 @Mock private NodeController mAlertingHeaderController; 68 @Mock private NodeController mSilentNodeController; 69 @Mock private SectionHeaderController mSilentHeaderController; 70 71 @Captor private ArgumentCaptor<NotifFilter> mNotifFilterCaptor; 72 73 private NotificationEntry mEntry; 74 private NotifFilter mCapturedSuspendedFilter; 75 private NotifFilter mCapturedDozingFilter; 76 77 private NotifSectioner mAlertingSectioner; 78 private NotifSectioner mSilentSectioner; 79 80 @Before setup()81 public void setup() { 82 MockitoAnnotations.initMocks(this); 83 RankingCoordinator rankingCoordinator = new RankingCoordinator( 84 mStatusBarStateController, mHighPriorityProvider, mAlertingHeaderController, 85 mSilentHeaderController, mSilentNodeController); 86 mEntry = new NotificationEntryBuilder().build(); 87 88 rankingCoordinator.attach(mNotifPipeline); 89 verify(mNotifPipeline, times(2)).addPreGroupFilter(mNotifFilterCaptor.capture()); 90 mCapturedSuspendedFilter = mNotifFilterCaptor.getAllValues().get(0); 91 mCapturedDozingFilter = mNotifFilterCaptor.getAllValues().get(1); 92 93 mAlertingSectioner = rankingCoordinator.getAlertingSectioner(); 94 mSilentSectioner = rankingCoordinator.getSilentSectioner(); 95 } 96 97 @Test testSilentHeaderClearableChildrenUpdate()98 public void testSilentHeaderClearableChildrenUpdate() { 99 StatusBarNotification sbn = Mockito.mock(StatusBarNotification.class); 100 Mockito.doReturn("key").when(sbn).getKey(); 101 Mockito.doReturn(Mockito.mock(Notification.class)).when(sbn).getNotification(); 102 NotificationEntry entry = new NotificationEntryBuilder().setSbn(sbn).build(); 103 ListEntry listEntry = new ListEntry("key", 0L) { 104 @Nullable 105 @Override 106 public NotificationEntry getRepresentativeEntry() { 107 return entry; 108 } 109 }; 110 Mockito.doReturn(true).when(sbn).isClearable(); 111 mSilentSectioner.onEntriesUpdated(Arrays.asList(listEntry)); 112 verify(mSilentHeaderController).setClearSectionEnabled(eq(true)); 113 114 Mockito.doReturn(false).when(sbn).isClearable(); 115 mSilentSectioner.onEntriesUpdated(Arrays.asList(listEntry)); 116 verify(mSilentHeaderController).setClearSectionEnabled(eq(false)); 117 } 118 119 @Test testUnfilteredState()120 public void testUnfilteredState() { 121 // GIVEN no suppressed visual effects + app not suspended 122 mEntry.setRanking(getRankingForUnfilteredNotif().build()); 123 124 // THEN don't filter out the notification 125 assertFalse(mCapturedSuspendedFilter.shouldFilterOut(mEntry, 0)); 126 } 127 128 @Test filterSuspended()129 public void filterSuspended() { 130 // GIVEN the notification's app is suspended 131 mEntry.setRanking(getRankingForUnfilteredNotif() 132 .setSuspended(true) 133 .build()); 134 135 // THEN filter out the notification 136 assertTrue(mCapturedSuspendedFilter.shouldFilterOut(mEntry, 0)); 137 } 138 139 @Test filterDozingSuppressAmbient()140 public void filterDozingSuppressAmbient() { 141 // GIVEN should suppress ambient 142 mEntry.setRanking(getRankingForUnfilteredNotif() 143 .setSuppressedVisualEffects(SUPPRESSED_EFFECT_AMBIENT) 144 .build()); 145 146 // WHEN it's dozing (on ambient display) 147 when(mStatusBarStateController.isDozing()).thenReturn(true); 148 149 // THEN filter out the notification 150 assertTrue(mCapturedDozingFilter.shouldFilterOut(mEntry, 0)); 151 152 // WHEN it's not dozing (showing the notification list) 153 when(mStatusBarStateController.isDozing()).thenReturn(false); 154 155 // THEN don't filter out the notification 156 assertFalse(mCapturedDozingFilter.shouldFilterOut(mEntry, 0)); 157 } 158 159 @Test filterDozingSuppressNotificationList()160 public void filterDozingSuppressNotificationList() { 161 // GIVEN should suppress from the notification list 162 mEntry.setRanking(getRankingForUnfilteredNotif() 163 .setSuppressedVisualEffects(SUPPRESSED_EFFECT_NOTIFICATION_LIST) 164 .build()); 165 166 // WHEN it's dozing (on ambient display) 167 when(mStatusBarStateController.isDozing()).thenReturn(true); 168 169 // THEN don't filter out the notification 170 assertFalse(mCapturedDozingFilter.shouldFilterOut(mEntry, 0)); 171 172 // WHEN it's not dozing (showing the notification list) 173 when(mStatusBarStateController.isDozing()).thenReturn(false); 174 175 // THEN filter out the notification 176 assertTrue(mCapturedDozingFilter.shouldFilterOut(mEntry, 0)); 177 } 178 179 @Test testIncludeInSectionAlerting()180 public void testIncludeInSectionAlerting() { 181 // GIVEN the entry is high priority 182 when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true); 183 184 // THEN entry is in the alerting section 185 assertTrue(mAlertingSectioner.isInSection(mEntry)); 186 assertFalse(mSilentSectioner.isInSection(mEntry)); 187 } 188 189 @Test testIncludeInSectionSilent()190 public void testIncludeInSectionSilent() { 191 // GIVEN the entry isn't high priority 192 when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false); 193 194 // THEN entry is in the silent section 195 assertFalse(mAlertingSectioner.isInSection(mEntry)); 196 assertTrue(mSilentSectioner.isInSection(mEntry)); 197 } 198 getRankingForUnfilteredNotif()199 private RankingBuilder getRankingForUnfilteredNotif() { 200 return new RankingBuilder() 201 .setKey(mEntry.getKey()) 202 .setSuppressedVisualEffects(0) 203 .setSuspended(false); 204 } 205 } 206