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