blob: 1c70db3a548e9095fbc0f9416aca13b6ba092427 [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;
Beverlya53fb0d2020-01-29 15:26:13 -050043import android.content.res.Resources;
Beverly Taid1e175c2020-03-10 16:37:04 +000044import android.hardware.display.AmbientDisplayConfiguration;
Beverlya53fb0d2020-01-29 15:26:13 -050045import android.hardware.face.FaceManager;
Beverly Taid1e175c2020-03-10 16:37:04 +000046import android.os.Handler;
47import android.os.PowerManager;
48import android.service.dreams.IDreamManager;
Mady Mellor76343012020-05-13 11:02:50 -070049import android.service.notification.NotificationListenerService;
Beverlya53fb0d2020-01-29 15:26:13 -050050import android.service.notification.ZenModeConfig;
51import android.testing.AndroidTestingRunner;
52import android.testing.TestableLooper;
53import android.view.WindowManager;
54
55import androidx.test.filters.SmallTest;
56
57import com.android.internal.colorextraction.ColorExtractor;
Mady Mellor458a6262020-06-07 21:09:19 -070058import com.android.internal.statusbar.IStatusBarService;
Beverlya53fb0d2020-01-29 15:26:13 -050059import com.android.systemui.SysuiTestCase;
60import com.android.systemui.colorextraction.SysuiColorExtractor;
Ned Burnsaaeb44b2020-02-12 23:48:26 -050061import com.android.systemui.dump.DumpManager;
Joshua Tsujibe60a582020-03-23 17:17:26 -040062import com.android.systemui.model.SysUiState;
Beverlya53fb0d2020-01-29 15:26:13 -050063import com.android.systemui.plugins.statusbar.StatusBarStateController;
64import com.android.systemui.statusbar.FeatureFlags;
65import com.android.systemui.statusbar.NotificationLockscreenUserManager;
Mady Mellor76343012020-05-13 11:02:50 -070066import com.android.systemui.statusbar.RankingBuilder;
Beverlya53fb0d2020-01-29 15:26:13 -050067import com.android.systemui.statusbar.SysuiStatusBarStateController;
68import com.android.systemui.statusbar.notification.NotificationEntryManager;
69import com.android.systemui.statusbar.notification.NotificationFilter;
Beverlya53fb0d2020-01-29 15:26:13 -050070import com.android.systemui.statusbar.notification.collection.NotifPipeline;
71import com.android.systemui.statusbar.notification.collection.NotificationEntry;
72import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
Beverlya53fb0d2020-01-29 15:26:13 -050073import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
74import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
75import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
76import com.android.systemui.statusbar.phone.DozeParameters;
77import com.android.systemui.statusbar.phone.KeyguardBypassController;
Dave Mankoffc0d9a7d2020-02-27 17:15:52 -050078import com.android.systemui.statusbar.phone.LockscreenLockIconController;
Beverlya53fb0d2020-01-29 15:26:13 -050079import com.android.systemui.statusbar.phone.NotificationGroupManager;
80import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
Fabian Kozynskib00c70b2020-04-03 12:41:31 -040081import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
Beverlya53fb0d2020-01-29 15:26:13 -050082import com.android.systemui.statusbar.phone.ShadeController;
83import com.android.systemui.statusbar.policy.BatteryController;
84import com.android.systemui.statusbar.policy.ConfigurationController;
85import com.android.systemui.statusbar.policy.HeadsUpManager;
86import com.android.systemui.statusbar.policy.ZenModeController;
Joshua Tsuji7155bf12020-02-13 16:14:29 -050087import com.android.systemui.util.FloatingContentCoordinator;
Beverlya53fb0d2020-01-29 15:26:13 -050088
89import org.junit.Before;
Josh Tsuji72e12cb2020-06-12 16:49:33 -040090import org.junit.Ignore;
Beverlya53fb0d2020-01-29 15:26:13 -050091import org.junit.Test;
92import org.junit.runner.RunWith;
93import org.mockito.ArgumentCaptor;
94import org.mockito.Captor;
95import org.mockito.Mock;
96import org.mockito.MockitoAnnotations;
97
98import java.util.List;
99
100/**
101 * Tests the NotifPipeline setup with BubbleController.
102 * The NotificationEntryManager setup with BubbleController is tested in
103 * {@link BubbleControllerTest}.
104 */
105@SmallTest
106@RunWith(AndroidTestingRunner.class)
107@TestableLooper.RunWithLooper(setAsMainLooper = true)
108public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
109 @Mock
110 private NotificationEntryManager mNotificationEntryManager;
111 @Mock
112 private NotificationGroupManager mNotificationGroupManager;
113 @Mock
114 private BubbleController.NotifCallback mNotifCallback;
115 @Mock
116 private WindowManager mWindowManager;
117 @Mock
118 private IActivityManager mActivityManager;
119 @Mock
120 private DozeParameters mDozeParameters;
121 @Mock
122 private ConfigurationController mConfigurationController;
123 @Mock
124 private ZenModeController mZenModeController;
125 @Mock
126 private ZenModeConfig mZenModeConfig;
127 @Mock
128 private FaceManager mFaceManager;
129 @Mock
130 private NotificationLockscreenUserManager mLockscreenUserManager;
131 @Mock
132 private SysuiStatusBarStateController mStatusBarStateController;
133 @Mock
134 private KeyguardBypassController mKeyguardBypassController;
Joshua Tsuji7155bf12020-02-13 16:14:29 -0500135 @Mock
136 private FloatingContentCoordinator mFloatingContentCoordinator;
Fabian Kozynskib00c70b2020-04-03 12:41:31 -0400137 @Mock
Pinyao Tingee191b12020-04-29 18:35:39 -0700138 private BubbleDataRepository mDataRepository;
139 @Mock
Fabian Kozynskib00c70b2020-04-03 12:41:31 -0400140 private NotificationShadeWindowView mNotificationShadeWindowView;
Joshua Tsujibe60a582020-03-23 17:17:26 -0400141
142 private SysUiState mSysUiState = new SysUiState();
143
Beverlya53fb0d2020-01-29 15:26:13 -0500144 @Captor
145 private ArgumentCaptor<NotifCollectionListener> mNotifListenerCaptor;
Beverlya53fb0d2020-01-29 15:26:13 -0500146 private TestableBubbleController mBubbleController;
147 private NotificationShadeWindowController mNotificationShadeWindowController;
148 private NotifCollectionListener mEntryListener;
Beverlya53fb0d2020-01-29 15:26:13 -0500149 private NotificationTestHelper mNotificationTestHelper;
150 private ExpandableNotificationRow mRow;
151 private ExpandableNotificationRow mRow2;
152 private ExpandableNotificationRow mNonBubbleNotifRow;
Beverlya53fb0d2020-01-29 15:26:13 -0500153 @Mock
Beverlya53fb0d2020-01-29 15:26:13 -0500154 private BubbleController.BubbleExpandListener mBubbleExpandListener;
155 @Mock
156 private PendingIntent mDeleteIntent;
157 @Mock
158 private SysuiColorExtractor mColorExtractor;
159 @Mock
160 ColorExtractor.GradientColors mGradientColors;
161 @Mock
162 private Resources mResources;
163 @Mock
164 private ShadeController mShadeController;
165 @Mock
166 private NotificationRowComponent mNotificationRowComponent;
167 @Mock
168 private NotifPipeline mNotifPipeline;
169 @Mock
170 private FeatureFlags mFeatureFlagsNewPipeline;
171 @Mock
Ned Burnsaaeb44b2020-02-12 23:48:26 -0500172 private DumpManager mDumpManager;
Dave Mankoffc0d9a7d2020-02-27 17:15:52 -0500173 @Mock
174 private LockscreenLockIconController mLockIconController;
Mady Mellor458a6262020-06-07 21:09:19 -0700175 @Mock
176 private IStatusBarService mStatusBarService;
Beverlya53fb0d2020-01-29 15:26:13 -0500177
Beverlya53fb0d2020-01-29 15:26:13 -0500178 private BubbleData mBubbleData;
179
180 private TestableLooper mTestableLooper;
181
182 @Before
183 public void setUp() throws Exception {
184 MockitoAnnotations.initMocks(this);
185
186 mTestableLooper = TestableLooper.get(this);
187
188 mContext.addMockSystemService(FaceManager.class, mFaceManager);
189 when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
190
Beverlya53fb0d2020-01-29 15:26:13 -0500191 // Bubbles get added to status bar window view
192 mNotificationShadeWindowController = new NotificationShadeWindowController(mContext,
193 mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
Lucas Dupind73410a2020-02-18 12:54:41 -0800194 mConfigurationController, mKeyguardBypassController, mColorExtractor,
Ned Burnsaaeb44b2020-02-12 23:48:26 -0500195 mDumpManager);
Fabian Kozynskib00c70b2020-04-03 12:41:31 -0400196 mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
Beverlya53fb0d2020-01-29 15:26:13 -0500197 mNotificationShadeWindowController.attach();
198
199 // Need notifications for bubbles
Kevin Hana7c21be2020-04-01 17:58:35 -0700200 mNotificationTestHelper = new NotificationTestHelper(
201 mContext,
202 mDependency,
203 TestableLooper.get(this));
Beverlya53fb0d2020-01-29 15:26:13 -0500204 mRow = mNotificationTestHelper.createBubble(mDeleteIntent);
205 mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
206 mNonBubbleNotifRow = mNotificationTestHelper.createRow();
207
208 mZenModeConfig.suppressedVisualEffects = 0;
209 when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
210
Beverly Taid1e175c2020-03-10 16:37:04 +0000211 TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
212 new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
213 mock(PowerManager.class),
214 mock(IDreamManager.class),
215 mock(AmbientDisplayConfiguration.class),
Beverlya53fb0d2020-01-29 15:26:13 -0500216 mock(NotificationFilter.class),
217 mock(StatusBarStateController.class),
Beverly Taid1e175c2020-03-10 16:37:04 +0000218 mock(BatteryController.class),
219 mock(HeadsUpManager.class),
220 mock(Handler.class)
221 );
Beverlya53fb0d2020-01-29 15:26:13 -0500222 mBubbleData = new BubbleData(mContext);
223 when(mFeatureFlagsNewPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
Ned Burnsaaeb44b2020-02-12 23:48:26 -0500224 mBubbleController = new TestableBubbleController(
225 mContext,
Beverlya53fb0d2020-01-29 15:26:13 -0500226 mNotificationShadeWindowController,
227 mStatusBarStateController,
228 mShadeController,
229 mBubbleData,
230 mConfigurationController,
231 interruptionStateProvider,
232 mZenModeController,
233 mLockscreenUserManager,
234 mNotificationGroupManager,
235 mNotificationEntryManager,
236 mNotifPipeline,
237 mFeatureFlagsNewPipeline,
Ned Burnsaaeb44b2020-02-12 23:48:26 -0500238 mDumpManager,
Joshua Tsujibe60a582020-03-23 17:17:26 -0400239 mFloatingContentCoordinator,
Pinyao Tingee191b12020-04-29 18:35:39 -0700240 mDataRepository,
Mady Mellor9adfe6a2020-03-30 17:23:26 -0700241 mSysUiState,
Mady Mellor59a7b982020-05-11 15:19:59 -0700242 mock(INotificationManager.class),
Mady Mellor458a6262020-06-07 21:09:19 -0700243 mStatusBarService,
Mady Mellor59a7b982020-05-11 15:19:59 -0700244 mWindowManager);
Beverlya53fb0d2020-01-29 15:26:13 -0500245 mBubbleController.addNotifCallback(mNotifCallback);
Beverlya53fb0d2020-01-29 15:26:13 -0500246 mBubbleController.setExpandListener(mBubbleExpandListener);
247
248 // Get a reference to the BubbleController's entry listener
249 verify(mNotifPipeline, atLeastOnce())
250 .addCollectionListener(mNotifListenerCaptor.capture());
251 mEntryListener = mNotifListenerCaptor.getValue();
252 }
253
254 @Test
255 public void testAddBubble() {
256 mBubbleController.updateBubble(mRow.getEntry());
257 assertTrue(mBubbleController.hasBubbles());
Beverlya53fb0d2020-01-29 15:26:13 -0500258 }
259
260 @Test
261 public void testHasBubbles() {
262 assertFalse(mBubbleController.hasBubbles());
263 mBubbleController.updateBubble(mRow.getEntry());
264 assertTrue(mBubbleController.hasBubbles());
265 }
266
267 @Test
268 public void testRemoveBubble() {
269 mBubbleController.updateBubble(mRow.getEntry());
Lyn Han2f6e89d2020-04-15 10:01:01 -0700270 assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500271 assertTrue(mBubbleController.hasBubbles());
272 verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
Beverlya53fb0d2020-01-29 15:26:13 -0500273
Pinyao Ting3c930612020-05-19 00:26:03 +0000274 mBubbleController.removeBubble(
275 mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
Lyn Han2f6e89d2020-04-15 10:01:01 -0700276 assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500277 verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
Beverlya53fb0d2020-01-29 15:26:13 -0500278 }
279
280 @Test
Lyn Han2f6e89d2020-04-15 10:01:01 -0700281 public void testRemoveBubble_withDismissedNotif_inOverflow() {
Beverlya53fb0d2020-01-29 15:26:13 -0500282 mEntryListener.onEntryAdded(mRow.getEntry());
283 mBubbleController.updateBubble(mRow.getEntry());
284
285 assertTrue(mBubbleController.hasBubbles());
286 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
287
288 // Make it look like dismissed notif
Lyn Han2f6e89d2020-04-15 10:01:01 -0700289 mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
Beverlya53fb0d2020-01-29 15:26:13 -0500290
291 // Now remove the bubble
Pinyao Ting3c930612020-05-19 00:26:03 +0000292 mBubbleController.removeBubble(
293 mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
Lyn Han2f6e89d2020-04-15 10:01:01 -0700294 assertTrue(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500295
Lyn Han2f6e89d2020-04-15 10:01:01 -0700296 // We don't remove the notification since the bubble is still in overflow.
297 verify(mNotifCallback, never()).removeNotification(eq(mRow.getEntry()), anyInt());
298 assertFalse(mBubbleController.hasBubbles());
299 }
300
301 @Test
302 public void testRemoveBubble_withDismissedNotif_notInOverflow() {
303 mEntryListener.onEntryAdded(mRow.getEntry());
304 mBubbleController.updateBubble(mRow.getEntry());
Pinyao Ting175a5b82020-06-15 23:41:14 +0000305 when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
306 .thenReturn(mRow.getEntry());
Lyn Han2f6e89d2020-04-15 10:01:01 -0700307
308 assertTrue(mBubbleController.hasBubbles());
309 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
310
311 // Make it look like dismissed notif
312 mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
313
314 // Now remove the bubble
Pinyao Ting3c930612020-05-19 00:26:03 +0000315 mBubbleController.removeBubble(
316 mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
Lyn Han2f6e89d2020-04-15 10:01:01 -0700317 assertFalse(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
318
319 // Since the notif is dismissed and not in overflow, once the bubble is removed,
320 // removeNotification gets called to really remove the notif
Beverlya53fb0d2020-01-29 15:26:13 -0500321 verify(mNotifCallback, times(1)).removeNotification(eq(mRow.getEntry()), anyInt());
322 assertFalse(mBubbleController.hasBubbles());
323 }
324
325 @Test
326 public void testDismissStack() {
327 mBubbleController.updateBubble(mRow.getEntry());
328 verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
Lyn Han2f6e89d2020-04-15 10:01:01 -0700329 assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500330 mBubbleController.updateBubble(mRow2.getEntry());
Lyn Han9f66c3b2020-03-05 23:59:29 -0800331 verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
Lyn Han2f6e89d2020-04-15 10:01:01 -0700332 assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500333 assertTrue(mBubbleController.hasBubbles());
334
Joshua Tsuji7dd88b02020-03-27 17:43:09 -0400335 mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
Beverlya53fb0d2020-01-29 15:26:13 -0500336 verify(mNotifCallback, times(3)).invalidateNotifications(anyString());
Lyn Han2f6e89d2020-04-15 10:01:01 -0700337 assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
338 assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500339 }
340
341 @Test
342 public void testExpandCollapseStack() {
343 assertFalse(mBubbleController.isStackExpanded());
344
345 // Mark it as a bubble and add it explicitly
346 mEntryListener.onEntryAdded(mRow.getEntry());
347 mBubbleController.updateBubble(mRow.getEntry());
348
349 // We should have bubbles & their notifs should not be suppressed
350 assertTrue(mBubbleController.hasBubbles());
351 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
352 mRow.getEntry()));
Beverlya53fb0d2020-01-29 15:26:13 -0500353
354 // Expand the stack
355 BubbleStackView stackView = mBubbleController.getStackView();
Joshua Tsuji7dd88b02020-03-27 17:43:09 -0400356 mBubbleData.setExpanded(true);
Beverlya53fb0d2020-01-29 15:26:13 -0500357 assertTrue(mBubbleController.isStackExpanded());
358 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500359
360 // Make sure the notif is suppressed
361 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
362
363 // Collapse
364 mBubbleController.collapseStack();
365 verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
366 assertFalse(mBubbleController.isStackExpanded());
Beverlya53fb0d2020-01-29 15:26:13 -0500367 }
368
369 @Test
Josh Tsuji72e12cb2020-06-12 16:49:33 -0400370 @Ignore("Currently broken.")
Beverlya53fb0d2020-01-29 15:26:13 -0500371 public void testCollapseAfterChangingExpandedBubble() {
372 // Mark it as a bubble and add it explicitly
373 mEntryListener.onEntryAdded(mRow.getEntry());
374 mEntryListener.onEntryAdded(mRow2.getEntry());
375 mBubbleController.updateBubble(mRow.getEntry());
376 mBubbleController.updateBubble(mRow2.getEntry());
377
378 // We should have bubbles & their notifs should not be suppressed
379 assertTrue(mBubbleController.hasBubbles());
380 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
381 mRow.getEntry()));
382 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
383 mRow2.getEntry()));
384
385 // Expand
386 BubbleStackView stackView = mBubbleController.getStackView();
Joshua Tsuji7dd88b02020-03-27 17:43:09 -0400387 mBubbleData.setExpanded(true);
Beverlya53fb0d2020-01-29 15:26:13 -0500388 assertTrue(mBubbleController.isStackExpanded());
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400389 verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
390 true, mRow.getEntry().getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500391
392 // Last added is the one that is expanded
Pinyao Ting175a5b82020-06-15 23:41:14 +0000393 assertEquals(mRow2.getEntry().getKey(), mBubbleData.getSelectedBubble().getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500394 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow2.getEntry()));
395
396 // Switch which bubble is expanded
Lyn Han2f6e89d2020-04-15 10:01:01 -0700397 mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500398 mBubbleData.setExpanded(true);
Pinyao Ting175a5b82020-06-15 23:41:14 +0000399 assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
400 stackView.getExpandedBubble().getKey()).getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500401 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
402 mRow.getEntry()));
403
404 // collapse for previous bubble
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400405 verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
406 false, mRow2.getEntry().getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500407 // expand for selected bubble
Joshua Tsuji06785ab2020-06-08 11:18:40 -0400408 verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
409 true, mRow.getEntry().getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500410
411 // Collapse
412 mBubbleController.collapseStack();
413 assertFalse(mBubbleController.isStackExpanded());
414 }
415
416 @Test
417 public void testExpansionRemovesShowInShadeAndDot() {
418 // Mark it as a bubble and add it explicitly
419 mEntryListener.onEntryAdded(mRow.getEntry());
420 mBubbleController.updateBubble(mRow.getEntry());
421
422 // We should have bubbles & their notifs should not be suppressed
423 assertTrue(mBubbleController.hasBubbles());
424 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
425
426 mTestableLooper.processAllMessages();
Lyn Han2f6e89d2020-04-15 10:01:01 -0700427 assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
Beverlya53fb0d2020-01-29 15:26:13 -0500428
429 // Expand
Joshua Tsuji7dd88b02020-03-27 17:43:09 -0400430 mBubbleData.setExpanded(true);
Beverlya53fb0d2020-01-29 15:26:13 -0500431 assertTrue(mBubbleController.isStackExpanded());
432 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
433
434 // Notif is suppressed after expansion
435 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
436 mRow.getEntry()));
437 // Notif shouldn't show dot after expansion
Lyn Han2f6e89d2020-04-15 10:01:01 -0700438 assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
Beverlya53fb0d2020-01-29 15:26:13 -0500439 }
440
441 @Test
442 public void testUpdateWhileExpanded_DoesntChangeShowInShadeAndDot() {
443 // Mark it as a bubble and add it explicitly
444 mEntryListener.onEntryAdded(mRow.getEntry());
445 mBubbleController.updateBubble(mRow.getEntry());
446
447 // We should have bubbles & their notifs should not be suppressed
448 assertTrue(mBubbleController.hasBubbles());
449 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
450 mRow.getEntry()));
451
452 mTestableLooper.processAllMessages();
Lyn Han2f6e89d2020-04-15 10:01:01 -0700453 assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
Beverlya53fb0d2020-01-29 15:26:13 -0500454
455 // Expand
Joshua Tsuji7dd88b02020-03-27 17:43:09 -0400456 mBubbleData.setExpanded(true);
Beverlya53fb0d2020-01-29 15:26:13 -0500457 assertTrue(mBubbleController.isStackExpanded());
458 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
459
460 // Notif is suppressed after expansion
461 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
462 mRow.getEntry()));
463 // Notif shouldn't show dot after expansion
Lyn Han2f6e89d2020-04-15 10:01:01 -0700464 assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
Beverlya53fb0d2020-01-29 15:26:13 -0500465
466 // Send update
467 mEntryListener.onEntryUpdated(mRow.getEntry());
468
469 // Nothing should have changed
470 // Notif is suppressed after expansion
471 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
472 mRow.getEntry()));
473 // Notif shouldn't show dot after expansion
Lyn Han2f6e89d2020-04-15 10:01:01 -0700474 assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
Beverlya53fb0d2020-01-29 15:26:13 -0500475 }
476
477 @Test
478 public void testRemoveLastExpandedCollapses() {
479 // Mark it as a bubble and add it explicitly
480 mEntryListener.onEntryAdded(mRow.getEntry());
481 mEntryListener.onEntryAdded(mRow2.getEntry());
482 mBubbleController.updateBubble(mRow.getEntry());
483 mBubbleController.updateBubble(mRow2.getEntry());
Beverlya53fb0d2020-01-29 15:26:13 -0500484
485 // Expand
486 BubbleStackView stackView = mBubbleController.getStackView();
Joshua Tsuji7dd88b02020-03-27 17:43:09 -0400487 mBubbleData.setExpanded(true);
Beverlya53fb0d2020-01-29 15:26:13 -0500488
489 assertTrue(mBubbleController.isStackExpanded());
490 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
491
492 // Last added is the one that is expanded
Pinyao Ting175a5b82020-06-15 23:41:14 +0000493 assertEquals(mRow2.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
494 stackView.getExpandedBubble().getKey()).getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500495 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
496 mRow2.getEntry()));
497
498 // Dismiss currently expanded
Lyn Han9f66c3b2020-03-05 23:59:29 -0800499 mBubbleController.removeBubble(
Pinyao Ting3c930612020-05-19 00:26:03 +0000500 mBubbleData.getBubbleInStackWithKey(
Pinyao Ting175a5b82020-06-15 23:41:14 +0000501 stackView.getExpandedBubble().getKey()).getKey(),
Beverlya53fb0d2020-01-29 15:26:13 -0500502 BubbleController.DISMISS_USER_GESTURE);
503 verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
504
505 // Make sure first bubble is selected
Pinyao Ting175a5b82020-06-15 23:41:14 +0000506 assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
507 stackView.getExpandedBubble().getKey()).getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500508 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
509
510 // Dismiss that one
Lyn Han9f66c3b2020-03-05 23:59:29 -0800511 mBubbleController.removeBubble(
Pinyao Ting3c930612020-05-19 00:26:03 +0000512 mBubbleData.getBubbleInStackWithKey(
Pinyao Ting175a5b82020-06-15 23:41:14 +0000513 stackView.getExpandedBubble().getKey()).getKey(),
Beverlya53fb0d2020-01-29 15:26:13 -0500514 BubbleController.DISMISS_USER_GESTURE);
515
516 // Make sure state changes and collapse happens
517 verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
Beverlya53fb0d2020-01-29 15:26:13 -0500518 assertFalse(mBubbleController.hasBubbles());
519 }
520
521 @Test
522 public void testAutoExpand_fails_noFlag() {
523 assertFalse(mBubbleController.isStackExpanded());
524 setMetadataFlags(mRow.getEntry(),
525 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */);
526
527 // Add the auto expand bubble
528 mEntryListener.onEntryAdded(mRow.getEntry());
529 mBubbleController.updateBubble(mRow.getEntry());
530
531 // Expansion shouldn't change
532 verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
533 mRow.getEntry().getKey());
534 assertFalse(mBubbleController.isStackExpanded());
Beverlya53fb0d2020-01-29 15:26:13 -0500535 }
536
537 @Test
538 public void testAutoExpand_succeeds_withFlag() {
539 setMetadataFlags(mRow.getEntry(),
540 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, true /* enableFlag */);
541
542 // Add the auto expand bubble
543 mEntryListener.onEntryAdded(mRow.getEntry());
544 mBubbleController.updateBubble(mRow.getEntry());
545
546 // Expansion should change
547 verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
548 mRow.getEntry().getKey());
549 assertTrue(mBubbleController.isStackExpanded());
Beverlya53fb0d2020-01-29 15:26:13 -0500550 }
551
552 @Test
553 public void testSuppressNotif_onInitialNotif() {
554 setMetadataFlags(mRow.getEntry(),
555 Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
556
557 // Add the suppress notif bubble
558 mEntryListener.onEntryAdded(mRow.getEntry());
559 mBubbleController.updateBubble(mRow.getEntry());
560
561 // Notif should be suppressed because we were foreground
562 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
563 mRow.getEntry()));
564 // Dot + flyout is hidden because notif is suppressed
Lyn Han2f6e89d2020-04-15 10:01:01 -0700565 assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
566 assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
Beverlya53fb0d2020-01-29 15:26:13 -0500567 }
568
569 @Test
570 public void testSuppressNotif_onUpdateNotif() {
571 mBubbleController.updateBubble(mRow.getEntry());
572
573 // Should not be suppressed
574 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
575 mRow.getEntry()));
576 // Should show dot
Lyn Han2f6e89d2020-04-15 10:01:01 -0700577 assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
Beverlya53fb0d2020-01-29 15:26:13 -0500578
579 // Update to suppress notif
580 setMetadataFlags(mRow.getEntry(),
581 Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
582 mBubbleController.updateBubble(mRow.getEntry());
583
584 // Notif should be suppressed
585 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
586 mRow.getEntry()));
587 // Dot + flyout is hidden because notif is suppressed
Lyn Han2f6e89d2020-04-15 10:01:01 -0700588 assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
589 assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
Beverlya53fb0d2020-01-29 15:26:13 -0500590 }
591
592 @Test
593 public void testMarkNewNotificationAsShowInShade() {
594 mEntryListener.onEntryAdded(mRow.getEntry());
595 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
596 mRow.getEntry()));
597
598 mTestableLooper.processAllMessages();
Lyn Han2f6e89d2020-04-15 10:01:01 -0700599 assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
Beverlya53fb0d2020-01-29 15:26:13 -0500600 }
601
602 @Test
603 public void testAddNotif_notBubble() {
604 mEntryListener.onEntryAdded(mNonBubbleNotifRow.getEntry());
605 mEntryListener.onEntryUpdated(mNonBubbleNotifRow.getEntry());
606
Beverlya53fb0d2020-01-29 15:26:13 -0500607 assertThat(mBubbleController.hasBubbles()).isFalse();
608 }
609
610 @Test
611 public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
612 mBubbleController.updateBubble(mRow.getEntry());
Pinyao Ting3c930612020-05-19 00:26:03 +0000613 mBubbleController.removeBubble(mRow.getEntry().getKey(), BubbleController.DISMISS_AGED);
Beverlya53fb0d2020-01-29 15:26:13 -0500614 verify(mDeleteIntent, never()).send();
615 }
616
617 @Test
618 public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
619 mBubbleController.updateBubble(mRow.getEntry());
620 mBubbleController.removeBubble(
Pinyao Ting3c930612020-05-19 00:26:03 +0000621 mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
Beverlya53fb0d2020-01-29 15:26:13 -0500622 verify(mDeleteIntent, times(1)).send();
623 }
624
625 @Test
626 public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException {
627 mBubbleController.updateBubble(mRow.getEntry());
628 mBubbleController.updateBubble(mRow2.getEntry());
Joshua Tsuji7dd88b02020-03-27 17:43:09 -0400629 mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
Beverlya53fb0d2020-01-29 15:26:13 -0500630 verify(mDeleteIntent, times(2)).send();
631 }
632
633 @Test
634 public void testRemoveBubble_noLongerBubbleAfterUpdate()
635 throws PendingIntent.CanceledException {
636 mBubbleController.updateBubble(mRow.getEntry());
637 assertTrue(mBubbleController.hasBubbles());
638
639 mRow.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
Mady Mellor76343012020-05-13 11:02:50 -0700640 NotificationListenerService.Ranking ranking = new RankingBuilder(
641 mRow.getEntry().getRanking()).setCanBubble(false).build();
642 mRow.getEntry().setRanking(ranking);
Beverlya53fb0d2020-01-29 15:26:13 -0500643 mEntryListener.onEntryUpdated(mRow.getEntry());
644
645 assertFalse(mBubbleController.hasBubbles());
646 verify(mDeleteIntent, never()).send();
647 }
648
649 @Test
650 public void testRemoveBubble_entryListenerRemove() {
651 mEntryListener.onEntryAdded(mRow.getEntry());
652 mBubbleController.updateBubble(mRow.getEntry());
653
654 assertTrue(mBubbleController.hasBubbles());
655
656 // Removes the notification
657 mEntryListener.onEntryRemoved(mRow.getEntry(), 0);
658 assertFalse(mBubbleController.hasBubbles());
659 }
660
661 @Test
Lyn Han9f66c3b2020-03-05 23:59:29 -0800662 public void removeBubble_intercepted() {
Beverlya53fb0d2020-01-29 15:26:13 -0500663 mEntryListener.onEntryAdded(mRow.getEntry());
664 mBubbleController.updateBubble(mRow.getEntry());
665
666 assertTrue(mBubbleController.hasBubbles());
667 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
668 mRow.getEntry()));
669
670 boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
671
672 // Intercept!
673 assertTrue(intercepted);
674 // Should update show in shade state
675 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow.getEntry()));
676 }
677
678 @Test
Lyn Han2f6e89d2020-04-15 10:01:01 -0700679 public void removeBubble_dismissIntoOverflow_intercepted() {
Beverlya53fb0d2020-01-29 15:26:13 -0500680 mEntryListener.onEntryAdded(mRow.getEntry());
681 mBubbleController.updateBubble(mRow.getEntry());
682
683 assertTrue(mBubbleController.hasBubbles());
684 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
685 mRow.getEntry()));
686
687 // Dismiss the bubble
688 mBubbleController.removeBubble(
Pinyao Ting3c930612020-05-19 00:26:03 +0000689 mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
Beverlya53fb0d2020-01-29 15:26:13 -0500690 assertFalse(mBubbleController.hasBubbles());
691
692 // Dismiss the notification
693 boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
694
Lyn Han2f6e89d2020-04-15 10:01:01 -0700695 // Intercept dismissal since bubble is going into overflow
696 assertTrue(intercepted);
697 }
698
699 @Test
700 public void removeBubble_notIntercepted() {
701 mEntryListener.onEntryAdded(mRow.getEntry());
702 mBubbleController.updateBubble(mRow.getEntry());
703
704 assertTrue(mBubbleController.hasBubbles());
705 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
706 mRow.getEntry()));
707
708 // Dismiss the bubble
709 mBubbleController.removeBubble(
Pinyao Ting3c930612020-05-19 00:26:03 +0000710 mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
Lyn Han2f6e89d2020-04-15 10:01:01 -0700711 assertFalse(mBubbleController.hasBubbles());
712
713 // Dismiss the notification
714 boolean intercepted = mBubbleController.handleDismissalInterception(mRow.getEntry());
715
716 // Not a bubble anymore so we don't intercept dismissal.
Beverlya53fb0d2020-01-29 15:26:13 -0500717 assertFalse(intercepted);
718 }
719
720 @Test
721 public void testNotifyShadeSuppressionChange_notificationDismiss() {
722 BubbleController.NotificationSuppressionChangedListener listener =
723 mock(BubbleController.NotificationSuppressionChangedListener.class);
724 mBubbleData.setSuppressionChangedListener(listener);
725
726 mEntryListener.onEntryAdded(mRow.getEntry());
727
728 assertTrue(mBubbleController.hasBubbles());
729 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
730 mRow.getEntry()));
731
732 mBubbleController.handleDismissalInterception(mRow.getEntry());
733
734 // Should update show in shade state
735 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
736 mRow.getEntry()));
737
738 // Should notify delegate that shade state changed
739 verify(listener).onBubbleNotificationSuppressionChange(
Lyn Han2f6e89d2020-04-15 10:01:01 -0700740 mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500741 }
742
743 @Test
744 public void testNotifyShadeSuppressionChange_bubbleExpanded() {
745 BubbleController.NotificationSuppressionChangedListener listener =
746 mock(BubbleController.NotificationSuppressionChangedListener.class);
747 mBubbleData.setSuppressionChangedListener(listener);
748
749 mEntryListener.onEntryAdded(mRow.getEntry());
750
751 assertTrue(mBubbleController.hasBubbles());
752 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
753 mRow.getEntry()));
754
755 mBubbleData.setExpanded(true);
756
757 // Once a bubble is expanded the notif is suppressed
758 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
759 mRow.getEntry()));
760
761 // Should notify delegate that shade state changed
762 verify(listener).onBubbleNotificationSuppressionChange(
Lyn Han2f6e89d2020-04-15 10:01:01 -0700763 mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500764 }
765
766 @Test
767 public void testBubbleSummaryDismissal_suppressesSummaryAndBubbleFromShade() throws Exception {
768 // GIVEN a group summary with a bubble child
769 ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
770 ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
771 mEntryListener.onEntryAdded(groupedBubble.getEntry());
Pinyao Ting175a5b82020-06-15 23:41:14 +0000772 when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
773 .thenReturn(groupedBubble.getEntry());
Beverlya53fb0d2020-01-29 15:26:13 -0500774 groupSummary.addChildNotification(groupedBubble);
Lyn Han2f6e89d2020-04-15 10:01:01 -0700775 assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500776
777 // WHEN the summary is dismissed
778 mBubbleController.handleDismissalInterception(groupSummary.getEntry());
779
780 // THEN the summary and bubbled child are suppressed from the shade
781 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
782 groupedBubble.getEntry()));
783 assertTrue(mBubbleData.isSummarySuppressed(groupSummary.getEntry().getSbn().getGroupKey()));
784 }
785
786 @Test
787 public void testAppRemovesSummary_removesAllBubbleChildren() throws Exception {
788 // GIVEN a group summary with a bubble child
789 ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(0);
790 ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
791 mEntryListener.onEntryAdded(groupedBubble.getEntry());
Pinyao Ting175a5b82020-06-15 23:41:14 +0000792 when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
793 .thenReturn(groupedBubble.getEntry());
Beverlya53fb0d2020-01-29 15:26:13 -0500794 groupSummary.addChildNotification(groupedBubble);
Lyn Han2f6e89d2020-04-15 10:01:01 -0700795 assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500796
797 // GIVEN the summary is dismissed
798 mBubbleController.handleDismissalInterception(groupSummary.getEntry());
799
800 // WHEN the summary is cancelled by the app
801 mEntryListener.onEntryRemoved(groupSummary.getEntry(), 0);
802
803 // THEN the summary and its children are removed from bubble data
Lyn Han2f6e89d2020-04-15 10:01:01 -0700804 assertFalse(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500805 assertFalse(mBubbleData.isSummarySuppressed(
806 groupSummary.getEntry().getSbn().getGroupKey()));
807 }
808
809 @Test
810 public void testSummaryDismissalMarksBubblesHiddenFromShadeAndDismissesNonBubbledChildren()
811 throws Exception {
812 // GIVEN a group summary with two (non-bubble) children and one bubble child
813 ExpandableNotificationRow groupSummary = mNotificationTestHelper.createGroup(2);
814 ExpandableNotificationRow groupedBubble = mNotificationTestHelper.createBubbleInGroup();
815 mEntryListener.onEntryAdded(groupedBubble.getEntry());
Pinyao Ting175a5b82020-06-15 23:41:14 +0000816 when(mNotificationEntryManager.getPendingOrActiveNotif(groupedBubble.getEntry().getKey()))
817 .thenReturn(groupedBubble.getEntry());
Beverlya53fb0d2020-01-29 15:26:13 -0500818 groupSummary.addChildNotification(groupedBubble);
819
820 // WHEN the summary is dismissed
821 mBubbleController.handleDismissalInterception(groupSummary.getEntry());
822
823 // THEN only the NON-bubble children are dismissed
Kevin Han43077f92020-02-28 12:51:53 -0800824 List<ExpandableNotificationRow> childrenRows = groupSummary.getAttachedChildren();
Beverlya53fb0d2020-01-29 15:26:13 -0500825 verify(mNotifCallback, times(1)).removeNotification(
826 childrenRows.get(0).getEntry(), REASON_GROUP_SUMMARY_CANCELED);
827 verify(mNotifCallback, times(1)).removeNotification(
828 childrenRows.get(1).getEntry(), REASON_GROUP_SUMMARY_CANCELED);
829 verify(mNotifCallback, never()).removeNotification(eq(groupedBubble.getEntry()), anyInt());
830
831 // THEN the bubble child still exists as a bubble and is suppressed from the shade
Lyn Han2f6e89d2020-04-15 10:01:01 -0700832 assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
Beverlya53fb0d2020-01-29 15:26:13 -0500833 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
834 groupedBubble.getEntry()));
835
836 // THEN the summary is also suppressed from the shade
837 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
838 groupSummary.getEntry()));
839 }
840
Beverlya53fb0d2020-01-29 15:26:13 -0500841 /**
842 * Sets the bubble metadata flags for this entry. These flags are normally set by
843 * NotificationManagerService when the notification is sent, however, these tests do not
844 * go through that path so we set them explicitly when testing.
845 */
846 private void setMetadataFlags(NotificationEntry entry, int flag, boolean enableFlag) {
847 Notification.BubbleMetadata bubbleMetadata =
848 entry.getSbn().getNotification().getBubbleMetadata();
849 int flags = bubbleMetadata.getFlags();
850 if (enableFlag) {
851 flags |= flag;
852 } else {
853 flags &= ~flag;
854 }
855 bubbleMetadata.setFlags(flags);
856 }
857}