1 /* 2 * Copyright (C) 2018 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.phone; 18 19 import static org.junit.Assert.assertFalse; 20 import static org.junit.Assert.assertTrue; 21 import static org.mockito.Mockito.doReturn; 22 import static org.mockito.Mockito.spy; 23 import static org.mockito.Mockito.times; 24 import static org.mockito.Mockito.verify; 25 import static org.mockito.Mockito.when; 26 27 import android.app.Notification; 28 import android.service.notification.StatusBarNotification; 29 import android.testing.AndroidTestingRunner; 30 import android.testing.TestableLooper; 31 32 import androidx.test.filters.SmallTest; 33 34 import com.android.systemui.SysuiTestCase; 35 import com.android.systemui.statusbar.AmbientPulseManager; 36 import com.android.systemui.statusbar.notification.NotificationEntryListener; 37 import com.android.systemui.statusbar.notification.NotificationEntryManager; 38 import com.android.systemui.statusbar.notification.collection.NotificationEntry; 39 import com.android.systemui.statusbar.policy.HeadsUpManager; 40 41 import org.junit.Before; 42 import org.junit.Rule; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 import org.mockito.ArgumentCaptor; 46 import org.mockito.Captor; 47 import org.mockito.Mock; 48 import org.mockito.junit.MockitoJUnit; 49 import org.mockito.junit.MockitoRule; 50 51 import java.util.HashMap; 52 53 @SmallTest 54 @RunWith(AndroidTestingRunner.class) 55 @TestableLooper.RunWithLooper 56 public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { 57 @Rule public MockitoRule rule = MockitoJUnit.rule(); 58 59 private NotificationGroupAlertTransferHelper mGroupAlertTransferHelper; 60 private NotificationGroupManager mGroupManager; 61 private AmbientPulseManager mAmbientPulseManager; 62 private HeadsUpManager mHeadsUpManager; 63 @Mock private NotificationEntryManager mNotificationEntryManager; 64 @Captor 65 private ArgumentCaptor<NotificationEntryListener> mListenerCaptor; 66 private NotificationEntryListener mNotificationEntryListener; 67 private final HashMap<String, NotificationEntry> mPendingEntries = new HashMap<>(); 68 private final NotificationGroupTestHelper mGroupTestHelper = 69 new NotificationGroupTestHelper(mContext); 70 71 72 @Before setup()73 public void setup() { 74 mAmbientPulseManager = new AmbientPulseManager(mContext); 75 mDependency.injectTestDependency(AmbientPulseManager.class, mAmbientPulseManager); 76 mHeadsUpManager = new HeadsUpManager(mContext) {}; 77 78 when(mNotificationEntryManager.getPendingNotificationsIterator()) 79 .thenReturn(mPendingEntries.values()); 80 81 mGroupManager = new NotificationGroupManager(); 82 mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager); 83 mGroupManager.setHeadsUpManager(mHeadsUpManager); 84 85 mGroupAlertTransferHelper = new NotificationGroupAlertTransferHelper(); 86 mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager); 87 88 mGroupAlertTransferHelper.bind(mNotificationEntryManager, mGroupManager); 89 verify(mNotificationEntryManager).addNotificationEntryListener(mListenerCaptor.capture()); 90 mNotificationEntryListener = mListenerCaptor.getValue(); 91 mHeadsUpManager.addListener(mGroupAlertTransferHelper); 92 mAmbientPulseManager.addListener(mGroupAlertTransferHelper); 93 } 94 95 @Test testSuppressedSummaryHeadsUpTransfersToChild()96 public void testSuppressedSummaryHeadsUpTransfersToChild() { 97 NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); 98 mHeadsUpManager.showNotification(summaryEntry); 99 NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); 100 101 // Summary will be suppressed because there is only one child. 102 mGroupManager.onEntryAdded(summaryEntry); 103 mGroupManager.onEntryAdded(childEntry); 104 105 // A suppressed summary should transfer its alert state to the child. 106 assertFalse(mHeadsUpManager.isAlerting(summaryEntry.key)); 107 assertTrue(mHeadsUpManager.isAlerting(childEntry.key)); 108 } 109 110 @Test testSuppressedSummaryHeadsUpTransfersToChildButBackAgain()111 public void testSuppressedSummaryHeadsUpTransfersToChildButBackAgain() { 112 NotificationEntry summaryEntry = 113 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); 114 NotificationEntry childEntry = 115 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); 116 NotificationEntry childEntry2 = 117 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); 118 mHeadsUpManager.showNotification(summaryEntry); 119 // Trigger a transfer of alert state from summary to child. 120 mGroupManager.onEntryAdded(summaryEntry); 121 mGroupManager.onEntryAdded(childEntry); 122 123 // Add second child notification so that summary is no longer suppressed. 124 mPendingEntries.put(childEntry2.key, childEntry2); 125 mNotificationEntryListener.onPendingEntryAdded(childEntry2); 126 mGroupManager.onEntryAdded(childEntry2); 127 128 // The alert state should transfer back to the summary as there is now more than one 129 // child and the summary should no longer be suppressed. 130 assertTrue(mHeadsUpManager.isAlerting(summaryEntry.key)); 131 assertFalse(mHeadsUpManager.isAlerting(childEntry.key)); 132 } 133 134 @Test testSuppressedSummaryHeadsUpDoesntTransferBackOnDozingChanged()135 public void testSuppressedSummaryHeadsUpDoesntTransferBackOnDozingChanged() { 136 NotificationEntry summaryEntry = 137 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); 138 NotificationEntry childEntry = 139 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); 140 NotificationEntry childEntry2 = 141 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); 142 mHeadsUpManager.showNotification(summaryEntry); 143 // Trigger a transfer of alert state from summary to child. 144 mGroupManager.onEntryAdded(summaryEntry); 145 mGroupManager.onEntryAdded(childEntry); 146 147 // Set dozing to true. 148 mGroupAlertTransferHelper.onDozingChanged(true); 149 150 // Add second child notification so that summary is no longer suppressed. 151 mPendingEntries.put(childEntry2.key, childEntry2); 152 mNotificationEntryListener.onPendingEntryAdded(childEntry2); 153 mGroupManager.onEntryAdded(childEntry2); 154 155 // Dozing changed so no reason to re-alert summary. 156 assertFalse(mHeadsUpManager.isAlerting(summaryEntry.key)); 157 } 158 159 @Test testSuppressedSummaryHeadsUpTransferDoesNotAlertChildIfUninflated()160 public void testSuppressedSummaryHeadsUpTransferDoesNotAlertChildIfUninflated() { 161 NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); 162 mHeadsUpManager.showNotification(summaryEntry); 163 NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); 164 when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) 165 .thenReturn(false); 166 167 mGroupManager.onEntryAdded(summaryEntry); 168 mGroupManager.onEntryAdded(childEntry); 169 170 // Alert is immediately removed from summary, but we do not show child yet either as its 171 // content is not inflated. 172 assertFalse(mHeadsUpManager.isAlerting(summaryEntry.key)); 173 assertFalse(mHeadsUpManager.isAlerting(childEntry.key)); 174 assertTrue(mGroupAlertTransferHelper.isAlertTransferPending(childEntry)); 175 } 176 177 @Test testSuppressedSummaryHeadsUpTransferAlertsChildOnInflation()178 public void testSuppressedSummaryHeadsUpTransferAlertsChildOnInflation() { 179 NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); 180 mHeadsUpManager.showNotification(summaryEntry); 181 NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); 182 when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) 183 .thenReturn(false); 184 185 mGroupManager.onEntryAdded(summaryEntry); 186 mGroupManager.onEntryAdded(childEntry); 187 188 when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) 189 .thenReturn(true); 190 mNotificationEntryListener.onEntryReinflated(childEntry); 191 192 // Alert is immediately removed from summary, and we show child as its content is inflated. 193 assertFalse(mHeadsUpManager.isAlerting(summaryEntry.key)); 194 assertTrue(mHeadsUpManager.isAlerting(childEntry.key)); 195 } 196 197 @Test testSuppressedSummaryHeadsUpTransferBackAbortsChildInflation()198 public void testSuppressedSummaryHeadsUpTransferBackAbortsChildInflation() { 199 NotificationEntry summaryEntry = 200 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); 201 NotificationEntry childEntry = 202 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); 203 when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) 204 .thenReturn(false); 205 NotificationEntry childEntry2 = 206 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); 207 mHeadsUpManager.showNotification(summaryEntry); 208 // Trigger a transfer of alert state from summary to child. 209 mGroupManager.onEntryAdded(summaryEntry); 210 mGroupManager.onEntryAdded(childEntry); 211 212 // Add second child notification so that summary is no longer suppressed. 213 mPendingEntries.put(childEntry2.key, childEntry2); 214 mNotificationEntryListener.onPendingEntryAdded(childEntry2); 215 mGroupManager.onEntryAdded(childEntry2); 216 217 // Child entry finishes its inflation. 218 when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) 219 .thenReturn(true); 220 mNotificationEntryListener.onEntryReinflated(childEntry); 221 222 verify(childEntry.getRow(), times(1)).freeContentViewWhenSafe(mHeadsUpManager 223 .getContentFlag()); 224 assertFalse(mHeadsUpManager.isAlerting(childEntry.key)); 225 } 226 227 @Test testCleanUpPendingAlertInfo()228 public void testCleanUpPendingAlertInfo() { 229 NotificationEntry summaryEntry = 230 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); 231 NotificationEntry childEntry = 232 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); 233 when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) 234 .thenReturn(false); 235 mHeadsUpManager.showNotification(summaryEntry); 236 // Trigger a transfer of alert state from summary to child. 237 mGroupManager.onEntryAdded(summaryEntry); 238 mGroupManager.onEntryAdded(childEntry); 239 240 mNotificationEntryListener.onEntryRemoved(childEntry, null, false); 241 242 assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry)); 243 } 244 245 @Test testUpdateGroupChangeDoesNotTransfer()246 public void testUpdateGroupChangeDoesNotTransfer() { 247 NotificationEntry summaryEntry = 248 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); 249 NotificationEntry childEntry = 250 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); 251 when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) 252 .thenReturn(false); 253 mHeadsUpManager.showNotification(summaryEntry); 254 // Trigger a transfer of alert state from summary to child. 255 mGroupManager.onEntryAdded(summaryEntry); 256 mGroupManager.onEntryAdded(childEntry); 257 258 // Notify that entry changed groups. 259 StatusBarNotification oldNotification = childEntry.notification; 260 StatusBarNotification newSbn = spy(childEntry.notification.clone()); 261 doReturn("other_group").when(newSbn).getGroupKey(); 262 childEntry.notification = newSbn; 263 mGroupManager.onEntryUpdated(childEntry, oldNotification); 264 265 assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry)); 266 } 267 268 @Test testUpdateChildToSummaryDoesNotTransfer()269 public void testUpdateChildToSummaryDoesNotTransfer() { 270 NotificationEntry summaryEntry = 271 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); 272 NotificationEntry childEntry = 273 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); 274 when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) 275 .thenReturn(false); 276 mHeadsUpManager.showNotification(summaryEntry); 277 // Trigger a transfer of alert state from summary to child. 278 mGroupManager.onEntryAdded(summaryEntry); 279 mGroupManager.onEntryAdded(childEntry); 280 281 // Update that child to a summary. 282 StatusBarNotification oldNotification = childEntry.notification; 283 childEntry.notification = mGroupTestHelper.createSummaryNotification( 284 Notification.GROUP_ALERT_SUMMARY).notification; 285 mGroupManager.onEntryUpdated(childEntry, oldNotification); 286 287 assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry)); 288 } 289 } 290