blob: 52c64cc40e79c29cc14610de4c3ea608c2fc6f4f [file] [log] [blame]
Beverlya53fb0d2020-01-29 15:26:13 -05001/*
2 * Copyright (C) 2020 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
17package com.android.systemui.bubbles;
18
19import static android.app.Notification.FLAG_BUBBLE;
20import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
21
22import static com.google.common.truth.Truth.assertThat;
23
24import static org.junit.Assert.assertEquals;
25import static org.junit.Assert.assertFalse;
26import static org.junit.Assert.assertNotNull;
27import static org.junit.Assert.assertNull;
28import static org.junit.Assert.assertTrue;
Beverlya53fb0d2020-01-29 15:26:13 -050029import static org.mockito.ArgumentMatchers.anyInt;
30import static org.mockito.ArgumentMatchers.anyString;
31import static org.mockito.ArgumentMatchers.eq;
32import static org.mockito.Mockito.atLeastOnce;
33import static org.mockito.Mockito.mock;
34import static org.mockito.Mockito.never;
35import static org.mockito.Mockito.times;
36import static org.mockito.Mockito.verify;
37import static org.mockito.Mockito.when;
38
39import android.app.IActivityManager;
Mady Mellor9adfe6a2020-03-30 17:23:26 -070040import android.app.INotificationManager;
Beverlya53fb0d2020-01-29 15:26:13 -050041import android.app.Notification;
42import android.app.PendingIntent;
Joshua Tsuji33477392020-06-19 18:35:35 -040043import android.content.pm.LauncherApps;
Beverlya53fb0d2020-01-29 15:26:13 -050044import android.content.res.Resources;
Beverly Taid1e175c2020-03-10 16:37:04 +000045import android.hardware.display.AmbientDisplayConfiguration;
Beverlya53fb0d2020-01-29 15:26:13 -050046import android.hardware.face.FaceManager;
Beverly Taid1e175c2020-03-10 16:37:04 +000047import android.os.Handler;
48import android.os.PowerManager;
49import android.service.dreams.IDreamManager;
Mady Mellor76343012020-05-13 11:02:50 -070050import android.service.notification.NotificationListenerService;
Beverlya53fb0d2020-01-29 15:26:13 -050051import android.service.notification.ZenModeConfig;
52import android.testing.AndroidTestingRunner;
53import android.testing.TestableLooper;
54import android.view.WindowManager;
55
56import androidx.test.filters.SmallTest;
57
58import com.android.internal.colorextraction.ColorExtractor;
Mady Mellor458a6262020-06-07 21:09:19 -070059import com.android.internal.statusbar.IStatusBarService;
Beverlya53fb0d2020-01-29 15:26:13 -050060import com.android.systemui.SysuiTestCase;
61import com.android.systemui.colorextraction.SysuiColorExtractor;
Ned Burnsaaeb44b2020-02-12 23:48:26 -050062import com.android.systemui.dump.DumpManager;
Joshua Tsujibe60a582020-03-23 17:17:26 -040063import com.android.systemui.model.SysUiState;
Beverlya53fb0d2020-01-29 15:26:13 -050064import com.android.systemui.plugins.statusbar.StatusBarStateController;
65import com.android.systemui.statusbar.FeatureFlags;
66import com.android.systemui.statusbar.NotificationLockscreenUserManager;
Mady Mellor76343012020-05-13 11:02:50 -070067import com.android.systemui.statusbar.RankingBuilder;
Beverlya53fb0d2020-01-29 15:26:13 -050068import com.android.systemui.statusbar.SysuiStatusBarStateController;
69import com.android.systemui.statusbar.notification.NotificationEntryManager;
70import com.android.systemui.statusbar.notification.NotificationFilter;
Beverlya53fb0d2020-01-29 15:26:13 -050071import com.android.systemui.statusbar.notification.collection.NotifPipeline;
72import com.android.systemui.statusbar.notification.collection.NotificationEntry;
73import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
Beverlya53fb0d2020-01-29 15:26:13 -050074import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
75import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
76import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
77import com.android.systemui.statusbar.phone.DozeParameters;
78import com.android.systemui.statusbar.phone.KeyguardBypassController;
Dave Mankoffc0d9a7d2020-02-27 17:15:52 -050079import com.android.systemui.statusbar.phone.LockscreenLockIconController;
Beverlya53fb0d2020-01-29 15:26:13 -050080import com.android.systemui.statusbar.phone.NotificationGroupManager;
81import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
Fabian Kozynskib00c70b2020-04-03 12:41:31 -040082import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
Beverlya53fb0d2020-01-29 15:26:13 -050083import com.android.systemui.statusbar.phone.ShadeController;
84import com.android.systemui.statusbar.policy.BatteryController;
85import com.android.systemui.statusbar.policy.ConfigurationController;
86import com.android.systemui.statusbar.policy.HeadsUpManager;
87import com.android.systemui.statusbar.policy.ZenModeController;
Joshua Tsuji7155bf12020-02-13 16:14:29 -050088import com.android.systemui.util.FloatingContentCoordinator;
Beverlya53fb0d2020-01-29 15:26:13 -050089
90import org.junit.Before;
Josh Tsuji72e12cb2020-06-12 16:49:33 -040091import org.junit.Ignore;
Beverlya53fb0d2020-01-29 15:26:13 -050092import org.junit.Test;
93import org.junit.runner.RunWith;
94import org.mockito.ArgumentCaptor;
95import org.mockito.Captor;
96import org.mockito.Mock;
97import org.mockito.MockitoAnnotations;
98
99import java.util.List;
100
101/**
102 * Tests the NotifPipeline setup with BubbleController.
103 * The NotificationEntryManager setup with BubbleController is tested in
104 * {@link BubbleControllerTest}.
105 */
106@SmallTest
107@RunWith(AndroidTestingRunner.class)
108@TestableLooper.RunWithLooper(setAsMainLooper = true)
109public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
110 @Mock
111 private NotificationEntryManager mNotificationEntryManager;
112 @Mock
113 private NotificationGroupManager mNotificationGroupManager;
114 @Mock
115 private BubbleController.NotifCallback mNotifCallback;
116 @Mock
117 private WindowManager mWindowManager;
118 @Mock
119 private IActivityManager mActivityManager;
120 @Mock
121 private DozeParameters mDozeParameters;
122 @Mock
123 private ConfigurationController mConfigurationController;
124 @Mock
125 private ZenModeController mZenModeController;
126 @Mock
127 private ZenModeConfig mZenModeConfig;
128 @Mock
129 private FaceManager mFaceManager;
130 @Mock
131 private NotificationLockscreenUserManager mLockscreenUserManager;
132 @Mock
133 private SysuiStatusBarStateController mStatusBarStateController;
134 @Mock
135 private KeyguardBypassController mKeyguardBypassController;
Joshua Tsuji7155bf12020-02-13 16:14:29 -0500136 @Mock
137 private FloatingContentCoordinator mFloatingContentCoordinator;
Fabian Kozynskib00c70b2020-04-03 12:41:31 -0400138 @Mock
Pinyao Tingee191b12020-04-29 18:35:39 -0700139 private BubbleDataRepository mDataRepository;
140 @Mock
Fabian Kozynskib00c70b2020-04-03 12:41:31 -0400141 private NotificationShadeWindowView mNotificationShadeWindowView;
Joshua Tsujibe60a582020-03-23 17:17:26 -0400142
143 private SysUiState mSysUiState = new SysUiState();
144
Beverlya53fb0d2020-01-29 15:26:13 -0500145 @Captor
146 private ArgumentCaptor<NotifCollectionListener> mNotifListenerCaptor;
Beverlya53fb0d2020-01-29 15:26:13 -0500147 private TestableBubbleController mBubbleController;
148 private NotificationShadeWindowController mNotificationShadeWindowController;
149 private NotifCollectionListener mEntryListener;
Beverlya53fb0d2020-01-29 15:26:13 -0500150 private NotificationTestHelper mNotificationTestHelper;
151 private ExpandableNotificationRow mRow;
152 private ExpandableNotificationRow mRow2;
153 private ExpandableNotificationRow mNonBubbleNotifRow;
Beverlya53fb0d2020-01-29 15:26:13 -0500154 @Mock
Beverlya53fb0d2020-01-29 15:26:13 -0500155 private BubbleController.BubbleExpandListener mBubbleExpandListener;
156 @Mock
157 private PendingIntent mDeleteIntent;
158 @Mock
159 private SysuiColorExtractor mColorExtractor;
160 @Mock
161 ColorExtractor.GradientColors mGradientColors;
162 @Mock
163 private Resources mResources;
164 @Mock
165 private ShadeController mShadeController;
166 @Mock
167 private NotificationRowComponent mNotificationRowComponent;
168 @Mock
169 private NotifPipeline mNotifPipeline;
170 @Mock
171 private FeatureFlags mFeatureFlagsNewPipeline;
172 @Mock
Ned Burnsaaeb44b2020-02-12 23:48:26 -0500173 private DumpManager mDumpManager;
Dave Mankoffc0d9a7d2020-02-27 17:15:52 -0500174 @Mock
175 private LockscreenLockIconController mLockIconController;
Mady Mellor458a6262020-06-07 21:09:19 -0700176 @Mock
177 private IStatusBarService mStatusBarService;
Joshua Tsuji33477392020-06-19 18:35:35 -0400178 @Mock
179 private LauncherApps mLauncherApps;
Beverlya53fb0d2020-01-29 15:26:13 -0500180
Beverlya53fb0d2020-01-29 15:26:13 -0500181 private BubbleData mBubbleData;
182
183 private TestableLooper mTestableLooper;
184
185 @Before
186 public void setUp() throws Exception {
187 MockitoAnnotations.initMocks(this);
188
189 mTestableLooper = TestableLooper.get(this);
190
191 mContext.addMockSystemService(FaceManager.class, mFaceManager);
192 when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
193
Beverlya53fb0d2020-01-29 15:26:13 -0500194 // Bubbles get added to status bar window view
195 mNotificationShadeWindowController = new NotificationShadeWindowController(mContext,
196 mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
Lucas Dupind73410a2020-02-18 12:54:41 -0800197 mConfigurationController, mKeyguardBypassController, mColorExtractor,
Ned Burnsaaeb44b2020-02-12 23:48:26 -0500198 mDumpManager);
Fabian Kozynskib00c70b2020-04-03 12:41:31 -0400199 mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
Beverlya53fb0d2020-01-29 15:26:13 -0500200 mNotificationShadeWindowController.attach();
201
202 // Need notifications for bubbles
Kevin Hana7c21be2020-04-01 17:58:35 -0700203 mNotificationTestHelper = new NotificationTestHelper(
204 mContext,
205 mDependency,
206 TestableLooper.get(this));
Beverlya53fb0d2020-01-29 15:26:13 -0500207 mRow = mNotificationTestHelper.createBubble(mDeleteIntent);
208 mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
209 mNonBubbleNotifRow = mNotificationTestHelper.createRow();
210
211 mZenModeConfig.suppressedVisualEffects = 0;
212 when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
213
Beverly Taid1e175c2020-03-10 16:37:04 +0000214 TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
215 new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
216 mock(PowerManager.class),
217 mock(IDreamManager.class),
218 mock(AmbientDisplayConfiguration.class),
Beverlya53fb0d2020-01-29 15:26:13 -0500219 mock(NotificationFilter.class),
220 mock(StatusBarStateController.class),
Beverly Taid1e175c2020-03-10 16:37:04 +0000221 mock(BatteryController.class),
222 mock(HeadsUpManager.class),
223 mock(Handler.class)
224 );
Beverlya53fb0d2020-01-29 15:26:13 -0500225 mBubbleData = new BubbleData(mContext);
226 when(mFeatureFlagsNewPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
Ned Burnsaaeb44b2020-02-12 23:48:26 -0500227 mBubbleController = new TestableBubbleController(
228 mContext,
Beverlya53fb0d2020-01-29 15:26:13 -0500229 mNotificationShadeWindowController,
230 mStatusBarStateController,
231 mShadeController,
232 mBubbleData,
233 mConfigurationController,
234 interruptionStateProvider,
235 mZenModeController,
236 mLockscreenUserManager,
237 mNotificationGroupManager,
238 mNotificationEntryManager,
239 mNotifPipeline,
240 mFeatureFlagsNewPipeline,
Ned Burnsaaeb44b2020-02-12 23:48:26 -0500241 mDumpManager,
Joshua Tsujibe60a582020-03-23 17:17:26 -0400242 mFloatingContentCoordinator,
Pinyao Tingee191b12020-04-29 18:35:39 -0700243 mDataRepository,
Mady Mellor9adfe6a2020-03-30 17:23:26 -0700244 mSysUiState,
Mady Mellor59a7b982020-05-11 15:19:59 -0700245 mock(INotificationManager.class),
Mady Mellor458a6262020-06-07 21:09:19 -0700246 mStatusBarService,
Joshua Tsuji33477392020-06-19 18:35:35 -0400247 mWindowManager,
248 mLauncherApps);
Beverlya53fb0d2020-01-29 15:26:13 -0500249 mBubbleController.addNotifCallback(mNotifCallback);
Beverlya53fb0d2020-01-29 15:26:13 -0500250 mBubbleController.setExpandListener(mBubbleExpandListener);
251
252 // Get a reference to the BubbleController's entry listener
253 verify(mNotifPipeline, atLeastOnce())
254 .addCollectionListener(mNotifListenerCaptor.capture());
255 mEntryListener = mNotifListenerCaptor.getValue();
256 }
257
258 @Test
259 public void testAddBubble() {
260 mBubbleController.updateBubble(mRow.getEntry());
261 assertTrue(mBubbleController.hasBubbles());
Beverlya53fb0d2020-01-29 15:26:13 -0500262 }
263
264 @Test
265 public void testHasBubbles() {
266 assertFalse(mBubbleController.hasBubbles());
267 mBubbleController.updateBubble(mRow.getEntry());
268 assertTrue(mBubbleController.hasBubbles());
269 }
270
271 @Test
272 public void testRemoveBubble() {
273 mBubbleController.updateBubble(mRow.getEntry());
Lyn Han2f6e89d2020-04-15 10:01:01 -0700274 assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500275 assertTrue(mBubbleController.hasBubbles());
276 verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
Beverlya53fb0d2020-01-29 15:26:13 -0500277
Pinyao Ting3c930612020-05-19 00:26:03 +0000278 mBubbleController.removeBubble(
279 mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
Lyn Han2f6e89d2020-04-15 10:01:01 -0700280 assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500281 verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
Beverlya53fb0d2020-01-29 15:26:13 -0500282 }
283
284 @Test
Lyn Han2f6e89d2020-04-15 10:01:01 -0700285 public void testRemoveBubble_withDismissedNotif_inOverflow() {
Beverlya53fb0d2020-01-29 15:26:13 -0500286 mEntryListener.onEntryAdded(mRow.getEntry());
287 mBubbleController.updateBubble(mRow.getEntry());
288
289 assertTrue(mBubbleController.hasBubbles());
290 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
291
292 // Make it look like dismissed notif
Lyn Han2f6e89d2020-04-15 10:01:01 -0700293 mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
Beverlya53fb0d2020-01-29 15:26:13 -0500294
295 // Now remove the bubble
Pinyao Ting3c930612020-05-19 00:26:03 +0000296 mBubbleController.removeBubble(
297 mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
Lyn Han2f6e89d2020-04-15 10:01:01 -0700298 assertTrue(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500299
Lyn Han2f6e89d2020-04-15 10:01:01 -0700300 // We don't remove the notification since the bubble is still in overflow.
301 verify(mNotifCallback, never()).removeNotification(eq(mRow.getEntry()), anyInt());
302 assertFalse(mBubbleController.hasBubbles());
303 }
304
305 @Test
306 public void testRemoveBubble_withDismissedNotif_notInOverflow() {
307 mEntryListener.onEntryAdded(mRow.getEntry());
308 mBubbleController.updateBubble(mRow.getEntry());
Pinyao Ting175a5b82020-06-15 23:41:14 +0000309 when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
310 .thenReturn(mRow.getEntry());
Lyn Han2f6e89d2020-04-15 10:01:01 -0700311
312 assertTrue(mBubbleController.hasBubbles());
313 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
314
315 // Make it look like dismissed notif
316 mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
317
318 // Now remove the bubble
Pinyao Ting3c930612020-05-19 00:26:03 +0000319 mBubbleController.removeBubble(
320 mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
Lyn Han2f6e89d2020-04-15 10:01:01 -0700321 assertFalse(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
322
323 // Since the notif is dismissed and not in overflow, once the bubble is removed,
324 // removeNotification gets called to really remove the notif
Beverlya53fb0d2020-01-29 15:26:13 -0500325 verify(mNotifCallback, times(1)).removeNotification(eq(mRow.getEntry()), anyInt());
326 assertFalse(mBubbleController.hasBubbles());
327 }
328
329 @Test
330 public void testDismissStack() {
331 mBubbleController.updateBubble(mRow.getEntry());
332 verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
Lyn Han2f6e89d2020-04-15 10:01:01 -0700333 assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500334 mBubbleController.updateBubble(mRow2.getEntry());
Lyn Han9f66c3b2020-03-05 23:59:29 -0800335 verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
Lyn Han2f6e89d2020-04-15 10:01:01 -0700336 assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500337 assertTrue(mBubbleController.hasBubbles());
338
Joshua Tsuji7dd88b02020-03-27 17:43:09 -0400339 mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
Beverlya53fb0d2020-01-29 15:26:13 -0500340 verify(mNotifCallback, times(3)).invalidateNotifications(anyString());
Lyn Han2f6e89d2020-04-15 10:01:01 -0700341 assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
342 assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500343 }
344
345 @Test
346 public void testExpandCollapseStack() {
347 assertFalse(mBubbleController.isStackExpanded());
348
349 // Mark it as a bubble and add it explicitly
350 mEntryListener.onEntryAdded(mRow.getEntry());
351 mBubbleController.updateBubble(mRow.getEntry());
352
353 // We should have bubbles & their notifs should not be suppressed
354 assertTrue(mBubbleController.hasBubbles());
355 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
356 mRow.getEntry()));
Beverlya53fb0d2020-01-29 15:26:13 -0500357
358 // Expand the stack
359 BubbleStackView stackView = mBubbleController.getStackView();
Joshua Tsuji7dd88b02020-03-27 17:43:09 -0400360 mBubbleData.setExpanded(true);
Beverlya53fb0d2020-01-29 15:26:13 -0500361 assertTrue(mBubbleController.isStackExpanded());
362 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500363
364 // Make sure the notif is suppressed
365 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
366
367 // Collapse
368 mBubbleController.collapseStack();
369 verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
370 assertFalse(mBubbleController.isStackExpanded());
Beverlya53fb0d2020-01-29 15:26:13 -0500371 }
372
373 @Test
Josh Tsuji72e12cb2020-06-12 16:49:33 -0400374 @Ignore("Currently broken.")
Beverlya53fb0d2020-01-29 15:26:13 -0500375 public void testCollapseAfterChangingExpandedBubble() {
376 // Mark it as a bubble and add it explicitly
377 mEntryListener.onEntryAdded(mRow.getEntry());
378 mEntryListener.onEntryAdded(mRow2.getEntry());
379 mBubbleController.updateBubble(mRow.getEntry());
380 mBubbleController.updateBubble(mRow2.getEntry());
381
382 // We should have bubbles & their notifs should not be suppressed
383 assertTrue(mBubbleController.hasBubbles());
384 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
385 mRow.getEntry()));
386 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
387 mRow2.getEntry()));
388
389 // Expand
390 BubbleStackView stackView = mBubbleController.getStackView();
Joshua Tsuji7dd88b02020-03-27 17:43:09 -0400391 mBubbleData.setExpanded(true);
Beverlya53fb0d2020-01-29 15:26:13 -0500392 assertTrue(mBubbleController.isStackExpanded());
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400393 verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
394 true, mRow.getEntry().getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500395
396 // Last added is the one that is expanded
Pinyao Ting175a5b82020-06-15 23:41:14 +0000397 assertEquals(mRow2.getEntry().getKey(), mBubbleData.getSelectedBubble().getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500398 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow2.getEntry()));
399
400 // Switch which bubble is expanded
Lyn Han2f6e89d2020-04-15 10:01:01 -0700401 mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500402 mBubbleData.setExpanded(true);
Pinyao Ting175a5b82020-06-15 23:41:14 +0000403 assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
404 stackView.getExpandedBubble().getKey()).getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500405 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
406 mRow.getEntry()));
407
408 // collapse for previous bubble
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400409 verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
410 false, mRow2.getEntry().getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500411 // expand for selected bubble
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400412 verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
413 true, mRow.getEntry().getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500414
415 // Collapse
416 mBubbleController.collapseStack();
417 assertFalse(mBubbleController.isStackExpanded());
418 }
419
420 @Test
421 public void testExpansionRemovesShowInShadeAndDot() {
422 // Mark it as a bubble and add it explicitly
423 mEntryListener.onEntryAdded(mRow.getEntry());
424 mBubbleController.updateBubble(mRow.getEntry());
425
426 // We should have bubbles & their notifs should not be suppressed
427 assertTrue(mBubbleController.hasBubbles());
428 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
429
430 mTestableLooper.processAllMessages();
Lyn Han2f6e89d2020-04-15 10:01:01 -0700431 assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
Beverlya53fb0d2020-01-29 15:26:13 -0500432
433 // Expand
Joshua Tsuji7dd88b02020-03-27 17:43:09 -0400434 mBubbleData.setExpanded(true);
Beverlya53fb0d2020-01-29 15:26:13 -0500435 assertTrue(mBubbleController.isStackExpanded());
436 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
437
438 // Notif is suppressed after expansion
439 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
440 mRow.getEntry()));
441 // Notif shouldn't show dot after expansion
Lyn Han2f6e89d2020-04-15 10:01:01 -0700442 assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
Beverlya53fb0d2020-01-29 15:26:13 -0500443 }
444
445 @Test
446 public void testUpdateWhileExpanded_DoesntChangeShowInShadeAndDot() {
447 // Mark it as a bubble and add it explicitly
448 mEntryListener.onEntryAdded(mRow.getEntry());
449 mBubbleController.updateBubble(mRow.getEntry());
450
451 // We should have bubbles & their notifs should not be suppressed
452 assertTrue(mBubbleController.hasBubbles());
453 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
454 mRow.getEntry()));
455
456 mTestableLooper.processAllMessages();
Lyn Han2f6e89d2020-04-15 10:01:01 -0700457 assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
Beverlya53fb0d2020-01-29 15:26:13 -0500458
459 // Expand
Joshua Tsuji7dd88b02020-03-27 17:43:09 -0400460 mBubbleData.setExpanded(true);
Beverlya53fb0d2020-01-29 15:26:13 -0500461 assertTrue(mBubbleController.isStackExpanded());
462 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
463
464 // Notif is suppressed after expansion
465 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
466 mRow.getEntry()));
467 // Notif shouldn't show dot after expansion
Lyn Han2f6e89d2020-04-15 10:01:01 -0700468 assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
Beverlya53fb0d2020-01-29 15:26:13 -0500469
470 // Send update
471 mEntryListener.onEntryUpdated(mRow.getEntry());
472
473 // Nothing should have changed
474 // Notif is suppressed after expansion
475 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
476 mRow.getEntry()));
477 // Notif shouldn't show dot after expansion
Lyn Han2f6e89d2020-04-15 10:01:01 -0700478 assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
Beverlya53fb0d2020-01-29 15:26:13 -0500479 }
480
481 @Test
482 public void testRemoveLastExpandedCollapses() {
483 // Mark it as a bubble and add it explicitly
484 mEntryListener.onEntryAdded(mRow.getEntry());
485 mEntryListener.onEntryAdded(mRow2.getEntry());
486 mBubbleController.updateBubble(mRow.getEntry());
487 mBubbleController.updateBubble(mRow2.getEntry());
Beverlya53fb0d2020-01-29 15:26:13 -0500488
489 // Expand
490 BubbleStackView stackView = mBubbleController.getStackView();
Joshua Tsuji7dd88b02020-03-27 17:43:09 -0400491 mBubbleData.setExpanded(true);
Beverlya53fb0d2020-01-29 15:26:13 -0500492
493 assertTrue(mBubbleController.isStackExpanded());
494 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
495
496 // Last added is the one that is expanded
Pinyao Ting175a5b82020-06-15 23:41:14 +0000497 assertEquals(mRow2.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
498 stackView.getExpandedBubble().getKey()).getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500499 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
500 mRow2.getEntry()));
501
502 // Dismiss currently expanded
Lyn Han9f66c3b2020-03-05 23:59:29 -0800503 mBubbleController.removeBubble(
Pinyao Ting3c930612020-05-19 00:26:03 +0000504 mBubbleData.getBubbleInStackWithKey(
Pinyao Ting175a5b82020-06-15 23:41:14 +0000505 stackView.getExpandedBubble().getKey()).getKey(),
Beverlya53fb0d2020-01-29 15:26:13 -0500506 BubbleController.DISMISS_USER_GESTURE);
507 verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
508
509 // Make sure first bubble is selected
Pinyao Ting175a5b82020-06-15 23:41:14 +0000510 assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
511 stackView.getExpandedBubble().getKey()).getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500512 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
513
514 // Dismiss that one
Lyn Han9f66c3b2020-03-05 23:59:29 -0800515 mBubbleController.removeBubble(
Pinyao Ting3c930612020-05-19 00:26:03 +0000516 mBubbleData.getBubbleInStackWithKey(
Pinyao Ting175a5b82020-06-15 23:41:14 +0000517 stackView.getExpandedBubble().getKey()).getKey(),
Beverlya53fb0d2020-01-29 15:26:13 -0500518 BubbleController.DISMISS_USER_GESTURE);
519
520 // Make sure state changes and collapse happens
521 verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500522 assertFalse(mBubbleController.hasBubbles());
523 }
524
525 @Test
526 public void testAutoExpand_fails_noFlag() {
527 assertFalse(mBubbleController.isStackExpanded());
528 setMetadataFlags(mRow.getEntry(),
529 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */);
530
531 // Add the auto expand bubble
532 mEntryListener.onEntryAdded(mRow.getEntry());
533 mBubbleController.updateBubble(mRow.getEntry());
534
535 // Expansion shouldn't change
536 verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
537 mRow.getEntry().getKey());
538 assertFalse(mBubbleController.isStackExpanded());
Beverlya53fb0d2020-01-29 15:26:13 -0500539 }
540
541 @Test
542 public void testAutoExpand_succeeds_withFlag() {
543 setMetadataFlags(mRow.getEntry(),
544 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, true /* enableFlag */);
545
546 // Add the auto expand bubble
547 mEntryListener.onEntryAdded(mRow.getEntry());
548 mBubbleController.updateBubble(mRow.getEntry());
549
550 // Expansion should change
551 verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
552 mRow.getEntry().getKey());
553 assertTrue(mBubbleController.isStackExpanded());
Beverlya53fb0d2020-01-29 15:26:13 -0500554 }
555
556 @Test
557 public void testSuppressNotif_onInitialNotif() {
558 setMetadataFlags(mRow.getEntry(),
559 Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
560
561 // Add the suppress notif bubble
562 mEntryListener.onEntryAdded(mRow.getEntry());
563 mBubbleController.updateBubble(mRow.getEntry());
564
565 // Notif should be suppressed because we were foreground
566 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
567 mRow.getEntry()));
568 // Dot + flyout is hidden because notif is suppressed
Lyn Han2f6e89d2020-04-15 10:01:01 -0700569 assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
570 assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
Beverlya53fb0d2020-01-29 15:26:13 -0500571 }
572
573 @Test
574 public void testSuppressNotif_onUpdateNotif() {
575 mBubbleController.updateBubble(mRow.getEntry());
576
577 // Should not be suppressed
578 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
579 mRow.getEntry()));
580 // Should show dot
Lyn Han2f6e89d2020-04-15 10:01:01 -0700581 assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
Beverlya53fb0d2020-01-29 15:26:13 -0500582
583 // Update to suppress notif
584 setMetadataFlags(mRow.getEntry(),
585 Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
586 mBubbleController.updateBubble(mRow.getEntry());
587
588 // Notif should be suppressed
589 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
590 mRow.getEntry()));
591 // Dot + flyout is hidden because notif is suppressed
Lyn Han2f6e89d2020-04-15 10:01:01 -0700592 assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
593 assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
Beverlya53fb0d2020-01-29 15:26:13 -0500594 }
595
596 @Test
597 public void testMarkNewNotificationAsShowInShade() {
598 mEntryListener.onEntryAdded(mRow.getEntry());
599 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
600 mRow.getEntry()));
601
602 mTestableLooper.processAllMessages();
Lyn Han2f6e89d2020-04-15 10:01:01 -0700603 assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
Beverlya53fb0d2020-01-29 15:26:13 -0500604 }
605
606 @Test
607 public void testAddNotif_notBubble() {
608 mEntryListener.onEntryAdded(mNonBubbleNotifRow.getEntry());
609 mEntryListener.onEntryUpdated(mNonBubbleNotifRow.getEntry());
610
Beverlya53fb0d2020-01-29 15:26:13 -0500611 assertThat(mBubbleController.hasBubbles()).isFalse();
612 }
613
614 @Test
615 public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
616 mBubbleController.updateBubble(mRow.getEntry());
Pinyao Ting3c930612020-05-19 00:26:03 +0000617 mBubbleController.removeBubble(mRow.getEntry().getKey(), BubbleController.DISMISS_AGED);
Beverlya53fb0d2020-01-29 15:26:13 -0500618 verify(mDeleteIntent, never()).send();
619 }
620
621 @Test
622 public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
623 mBubbleController.updateBubble(mRow.getEntry());
624 mBubbleController.removeBubble(
Pinyao Ting3c930612020-05-19 00:26:03 +0000625 mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
Beverlya53fb0d2020-01-29 15:26:13 -0500626 verify(mDeleteIntent, times(1)).send();
627 }
628
629 @Test
630 public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException {
631 mBubbleController.updateBubble(mRow.getEntry());
632 mBubbleController.updateBubble(mRow2.getEntry());
Joshua Tsuji7dd88b02020-03-27 17:43:09 -0400633 mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
Beverlya53fb0d2020-01-29 15:26:13 -0500634 verify(mDeleteIntent, times(2)).send();
635 }
636
637 @Test
638 public void testRemoveBubble_noLongerBubbleAfterUpdate()
639 throws PendingIntent.CanceledException {
640 mBubbleController.updateBubble(mRow.getEntry());
641 assertTrue(mBubbleController.hasBubbles());
642
643 mRow.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
Mady Mellor76343012020-05-13 11:02:50 -0700644 NotificationListenerService.Ranking ranking = new RankingBuilder(
645 mRow.getEntry().getRanking()).setCanBubble(false).build();
646 mRow.getEntry().setRanking(ranking);
Beverlya53fb0d2020-01-29 15:26:13 -0500647 mEntryListener.onEntryUpdated(mRow.getEntry());
648
649 assertFalse(mBubbleController.hasBubbles());
650 verify(mDeleteIntent, never()).send();
651 }
652
653 @Test
654 public void testRemoveBubble_entryListenerRemove() {
655 mEntryListener.onEntryAdded(mRow.getEntry());
656 mBubbleController.updateBubble(mRow.getEntry());
657
658 assertTrue(mBubbleController.hasBubbles());
659
660 // Removes the notification
661 mEntryListener.onEntryRemoved(mRow.getEntry(), 0);
662 assertFalse(mBubbleController.hasBubbles());
663 }
664
665 @Test
Lyn Han9f66c3b2020-03-05 23:59:29 -0800666 public void removeBubble_intercepted() {
Beverlya53fb0d2020-01-29 15:26:13 -0500667 mEntryListener.onEntryAdded(mRow.getEntry());
668 mBubbleController.updateBubble(mRow.getEntry());
669
670 assertTrue(mBubbleController.hasBubbles());
671 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
672 mRow.getEntry()));
673
674 boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
675
676 // Intercept!
677 assertTrue(intercepted);
678 // Should update show in shade state
679 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
680 }
681
682 @Test
Lyn Han2f6e89d2020-04-15 10:01:01 -0700683 public void removeBubble_dismissIntoOverflow_intercepted() {
Beverlya53fb0d2020-01-29 15:26:13 -0500684 mEntryListener.onEntryAdded(mRow.getEntry());
685 mBubbleController.updateBubble(mRow.getEntry());
686
687 assertTrue(mBubbleController.hasBubbles());
688 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
689 mRow.getEntry()));
690
691 // Dismiss the bubble
692 mBubbleController.removeBubble(
Pinyao Ting3c930612020-05-19 00:26:03 +0000693 mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
Beverlya53fb0d2020-01-29 15:26:13 -0500694 assertFalse(mBubbleController.hasBubbles());
695
696 // Dismiss the notification
697 boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
698
Lyn Han2f6e89d2020-04-15 10:01:01 -0700699 // Intercept dismissal since bubble is going into overflow
700 assertTrue(intercepted);
701 }
702
703 @Test
704 public void removeBubble_notIntercepted() {
705 mEntryListener.onEntryAdded(mRow.getEntry());
706 mBubbleController.updateBubble(mRow.getEntry());
707
708 assertTrue(mBubbleController.hasBubbles());
709 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
710 mRow.getEntry()));
711
712 // Dismiss the bubble
713 mBubbleController.removeBubble(
Pinyao Ting3c930612020-05-19 00:26:03 +0000714 mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
Lyn Han2f6e89d2020-04-15 10:01:01 -0700715 assertFalse(mBubbleController.hasBubbles());
716
717 // Dismiss the notification
718 boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
719
720 // Not a bubble anymore so we don't intercept dismissal.
Beverlya53fb0d2020-01-29 15:26:13 -0500721 assertFalse(intercepted);
722 }
723
724 @Test
725 public void testNotifyShadeSuppressionChange_notificationDismiss() {
726 BubbleController.NotificationSuppressionChangedListener listener =
727 mock(BubbleController.NotificationSuppressionChangedListener.class);
728 mBubbleData.setSuppressionChangedListener(listener);
729
730 mEntryListener.onEntryAdded(mRow.getEntry());
731
732 assertTrue(mBubbleController.hasBubbles());
733 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
734 mRow.getEntry()));
735
736 mBubbleController.handleDismissalInterception(mRow.getEntry());
737
738 // Should update show in shade state
739 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
740 mRow.getEntry()));
741
742 // Should notify delegate that shade state changed
743 verify(listener).onBubbleNotificationSuppressionChange(
Lyn Han2f6e89d2020-04-15 10:01:01 -0700744 mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500745 }
746
747 @Test
748 public void testNotifyShadeSuppressionChange_bubbleExpanded() {
749 BubbleController.NotificationSuppressionChangedListener listener =
750 mock(BubbleController.NotificationSuppressionChangedListener.class);
751 mBubbleData.setSuppressionChangedListener(listener);
752
753 mEntryListener.onEntryAdded(mRow.getEntry());
754
755 assertTrue(mBubbleController.hasBubbles());
756 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
757 mRow.getEntry()));
758
759 mBubbleData.setExpanded(true);
760
761 // Once a bubble is expanded the notif is suppressed
762 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
763 mRow.getEntry()));
764
765 // Should notify delegate that shade state changed
766 verify(listener).onBubbleNotificationSuppressionChange(
Lyn Han2f6e89d2020-04-15 10:01:01 -0700767 mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500768 }
769
770 @Test
771 public void testBubbleSummaryDismissal_suppressesSummaryAndBubbleFromShade() throws Exception {
772 // GIVEN a group summary with a bubble child
773 ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
774 ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
775 mEntryListener.onEntryAdded(groupedBubble.getEntry());
Pinyao Ting175a5b82020-06-15 23:41:14 +0000776 when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
777 .thenReturn(groupedBubble.getEntry());
Beverlya53fb0d2020-01-29 15:26:13 -0500778 groupSummary.addChildNotification(groupedBubble);
Lyn Han2f6e89d2020-04-15 10:01:01 -0700779 assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500780
781 // WHEN the summary is dismissed
782 mBubbleController.handleDismissalInterception(groupSummary.getEntry());
783
784 // THEN the summary and bubbled child are suppressed from the shade
785 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
786 groupedBubble.getEntry()));
787 assertTrue(mBubbleData.isSummarySuppressed(groupSummary.getEntry().getSbn().getGroupKey()));
788 }
789
790 @Test
791 public void testAppRemovesSummary_removesAllBubbleChildren() throws Exception {
792 // GIVEN a group summary with a bubble child
793 ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
794 ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
795 mEntryListener.onEntryAdded(groupedBubble.getEntry());
Pinyao Ting175a5b82020-06-15 23:41:14 +0000796 when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
797 .thenReturn(groupedBubble.getEntry());
Beverlya53fb0d2020-01-29 15:26:13 -0500798 groupSummary.addChildNotification(groupedBubble);
Lyn Han2f6e89d2020-04-15 10:01:01 -0700799 assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500800
801 // GIVEN the summary is dismissed
802 mBubbleController.handleDismissalInterception(groupSummary.getEntry());
803
804 // WHEN the summary is cancelled by the app
805 mEntryListener.onEntryRemoved(groupSummary.getEntry(), 0);
806
807 // THEN the summary and its children are removed from bubble data
Lyn Han2f6e89d2020-04-15 10:01:01 -0700808 assertFalse(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500809 assertFalse(mBubbleData.isSummarySuppressed(
810 groupSummary.getEntry().getSbn().getGroupKey()));
811 }
812
813 @Test
814 public void testSummaryDismissalMarksBubblesHiddenFromShadeAndDismissesNonBubbledChildren()
815 throws Exception {
816 // GIVEN a group summary with two (non-bubble) children and one bubble child
817 ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(2);
818 ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
819 mEntryListener.onEntryAdded(groupedBubble.getEntry());
Pinyao Ting175a5b82020-06-15 23:41:14 +0000820 when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
821 .thenReturn(groupedBubble.getEntry());
Beverlya53fb0d2020-01-29 15:26:13 -0500822 groupSummary.addChildNotification(groupedBubble);
823
824 // WHEN the summary is dismissed
825 mBubbleController.handleDismissalInterception(groupSummary.getEntry());
826
827 // THEN only the NON-bubble children are dismissed
Kevin Han43077f92020-02-28 12:51:53 -0800828 List<ExpandableNotificationRow> childrenRows = groupSummary.getAttachedChildren();
Beverlya53fb0d2020-01-29 15:26:13 -0500829 verify(mNotifCallback, times(1)).removeNotification(
830 childrenRows.get(0).getEntry(), REASON_GROUP_SUMMARY_CANCELED);
831 verify(mNotifCallback, times(1)).removeNotification(
832 childrenRows.get(1).getEntry(), REASON_GROUP_SUMMARY_CANCELED);
833 verify(mNotifCallback, never()).removeNotification(eq(groupedBubble.getEntry()), anyInt());
834
835 // THEN the bubble child still exists as a bubble and is suppressed from the shade
Lyn Han2f6e89d2020-04-15 10:01:01 -0700836 assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500837 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
838 groupedBubble.getEntry()));
839
840 // THEN the summary is also suppressed from the shade
841 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
842 groupSummary.getEntry()));
843 }
844
Beverlya53fb0d2020-01-29 15:26:13 -0500845 /**
846 * Sets the bubble metadata flags for this entry. These flags are normally set by
847 * NotificationManagerService when the notification is sent, however, these tests do not
848 * go through that path so we set them explicitly when testing.
849 */
850 private void setMetadataFlags(NotificationEntry entry, int flag, boolean enableFlag) {
851 Notification.BubbleMetadata bubbleMetadata =
852 entry.getSbn().getNotification().getBubbleMetadata();
853 int flags = bubbleMetadata.getFlags();
854 if (enableFlag) {
855 flags |= flag;
856 } else {
857 flags &= ~flag;
858 }
859 bubbleMetadata.setFlags(flags);
860 }
861}