blob: 5cfb4b39b16bc241d86c6bca06c6012c7fcee427 [file] [log] [blame]
Mady Mellorebdbbb92018-11-15 14:36:48 -08001/*
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
17package com.android.systemui.bubbles;
18
Mady Melloraa8fef22019-04-11 13:36:40 -070019import static android.app.Notification.FLAG_BUBBLE;
Mady Mellorc2ff0112019-03-28 14:18:06 -070020import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
21import static android.service.notification.NotificationListenerService.REASON_CANCEL;
22import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
Mady Mellore80930e2019-03-21 16:00:45 -070023
Mady Mellor1a4e86f2019-05-03 16:07:23 -070024import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
25
Mady Mellorfc02cc32019-04-01 14:47:55 -070026import static com.google.common.truth.Truth.assertThat;
27
Mady Melloredd4ee12019-01-18 10:45:11 -080028import static org.junit.Assert.assertEquals;
Mady Mellorebdbbb92018-11-15 14:36:48 -080029import static org.junit.Assert.assertFalse;
Mady Mellored99c272019-06-13 15:58:30 -070030import static org.junit.Assert.assertNotNull;
31import static org.junit.Assert.assertNull;
Mady Mellorebdbbb92018-11-15 14:36:48 -080032import static org.junit.Assert.assertTrue;
Mady Mellorc2ff0112019-03-28 14:18:06 -070033import static org.mockito.ArgumentMatchers.any;
Mady Mellorfc02cc32019-04-01 14:47:55 -070034import static org.mockito.ArgumentMatchers.anyBoolean;
Mady Mellorc2ff0112019-03-28 14:18:06 -070035import static org.mockito.ArgumentMatchers.anyInt;
Beverly85d4c192019-09-30 11:40:39 -040036import static org.mockito.ArgumentMatchers.anyString;
Ned Burns01e38212019-01-03 16:32:52 -050037import static org.mockito.Mockito.atLeastOnce;
Mady Melloraa8fef22019-04-11 13:36:40 -070038import static org.mockito.Mockito.mock;
Mark Renouf08bc42a2019-03-07 13:01:59 -050039import static org.mockito.Mockito.never;
40import static org.mockito.Mockito.times;
Ned Burns01e38212019-01-03 16:32:52 -050041import static org.mockito.Mockito.verify;
42import static org.mockito.Mockito.when;
Mady Mellorebdbbb92018-11-15 14:36:48 -080043
44import android.app.IActivityManager;
Mady Mellore80930e2019-03-21 16:00:45 -070045import android.app.Notification;
Mark Renouf08bc42a2019-03-07 13:01:59 -050046import android.app.PendingIntent;
Mady Mellorebdbbb92018-11-15 14:36:48 -080047import android.content.Context;
Heemin Seogafb3dbc2019-11-04 16:05:19 -080048import android.content.res.Resources;
Mady Mellor80c25b22019-06-17 14:40:37 -070049import android.hardware.face.FaceManager;
Joshua Tsujidd4d9f92019-05-13 13:57:38 -040050import android.service.notification.ZenModeConfig;
Mady Mellorebdbbb92018-11-15 14:36:48 -080051import android.testing.AndroidTestingRunner;
52import android.testing.TestableLooper;
53import android.view.WindowManager;
Mady Mellorebdbbb92018-11-15 14:36:48 -080054
Brett Chabot84151d92019-02-27 15:37:59 -080055import androidx.test.filters.SmallTest;
56
Dave Mankoff2aff6c32019-10-14 17:40:37 -040057import com.android.internal.colorextraction.ColorExtractor;
Heemin Seogafb3dbc2019-11-04 16:05:19 -080058import com.android.systemui.SystemUIFactory;
Mady Mellorebdbbb92018-11-15 14:36:48 -080059import com.android.systemui.SysuiTestCase;
Dave Mankoff2aff6c32019-10-14 17:40:37 -040060import com.android.systemui.colorextraction.SysuiColorExtractor;
Mady Mellorc55b4122019-06-07 18:14:02 -070061import com.android.systemui.plugins.statusbar.StatusBarStateController;
Mark Renoufc19b4732019-06-26 12:08:33 -040062import com.android.systemui.statusbar.NotificationLockscreenUserManager;
Mady Melloraa8fef22019-04-11 13:36:40 -070063import com.android.systemui.statusbar.NotificationPresenter;
Mady Mellorc2ff0112019-03-28 14:18:06 -070064import com.android.systemui.statusbar.NotificationRemoveInterceptor;
Mady Mellorebdbbb92018-11-15 14:36:48 -080065import com.android.systemui.statusbar.NotificationTestHelper;
Heemin Seogafb3dbc2019-11-04 16:05:19 -080066import com.android.systemui.statusbar.SuperStatusBarViewFactory;
Lucas Dupine25c4872019-07-29 13:51:35 -070067import com.android.systemui.statusbar.SysuiStatusBarStateController;
Ned Burns01e38212019-01-03 16:32:52 -050068import com.android.systemui.statusbar.notification.NotificationEntryListener;
69import com.android.systemui.statusbar.notification.NotificationEntryManager;
Mady Mellorc55b4122019-06-07 18:14:02 -070070import com.android.systemui.statusbar.notification.NotificationFilter;
Mady Melloraa8fef22019-04-11 13:36:40 -070071import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
Mady Mellor8d25b202019-06-25 13:59:28 -070072import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Dave Mankoff56fe9e42020-01-08 15:42:06 -050073import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
Mady Mellorebdbbb92018-11-15 14:36:48 -080074import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Dave Mankoff56fe9e42020-01-08 15:42:06 -050075import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
Mady Mellorebdbbb92018-11-15 14:36:48 -080076import com.android.systemui.statusbar.phone.DozeParameters;
Lucas Dupine25c4872019-07-29 13:51:35 -070077import com.android.systemui.statusbar.phone.KeyguardBypassController;
Ned Burns296aec162019-09-04 17:30:59 -040078import com.android.systemui.statusbar.phone.NotificationGroupManager;
wilsonshihe8321942019-10-18 18:39:46 +080079import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
Mady Mellor7f234902019-10-20 12:06:29 -070080import com.android.systemui.statusbar.phone.ShadeController;
Lucas Dupinbd7366d2019-09-25 13:39:21 -070081import com.android.systemui.statusbar.policy.BatteryController;
Lyn Hanf1c9b8b2019-03-14 16:49:48 -070082import com.android.systemui.statusbar.policy.ConfigurationController;
Mady Melloraa8fef22019-04-11 13:36:40 -070083import com.android.systemui.statusbar.policy.HeadsUpManager;
Aran Inkaa4dfa72019-11-18 16:49:07 -050084import com.android.systemui.statusbar.policy.RemoteInputUriController;
Joshua Tsujidd4d9f92019-05-13 13:57:38 -040085import com.android.systemui.statusbar.policy.ZenModeController;
Heemin Seogafb3dbc2019-11-04 16:05:19 -080086import com.android.systemui.util.InjectionInflationController;
Mady Mellorebdbbb92018-11-15 14:36:48 -080087
88import org.junit.Before;
89import org.junit.Test;
90import org.junit.runner.RunWith;
Ned Burns01e38212019-01-03 16:32:52 -050091import org.mockito.ArgumentCaptor;
92import org.mockito.Captor;
Mady Mellorebdbbb92018-11-15 14:36:48 -080093import org.mockito.Mock;
94import org.mockito.MockitoAnnotations;
95
96@SmallTest
97@RunWith(AndroidTestingRunner.class)
98@TestableLooper.RunWithLooper(setAsMainLooper = true)
99public class BubbleControllerTest extends SysuiTestCase {
Mady Mellorebdbbb92018-11-15 14:36:48 -0800100 @Mock
Ned Burns01e38212019-01-03 16:32:52 -0500101 private NotificationEntryManager mNotificationEntryManager;
102 @Mock
Mady Mellor22f2f072019-04-18 13:26:18 -0700103 private NotificationGroupManager mNotificationGroupManager;
104 @Mock
Mady Mellorebdbbb92018-11-15 14:36:48 -0800105 private WindowManager mWindowManager;
106 @Mock
107 private IActivityManager mActivityManager;
108 @Mock
109 private DozeParameters mDozeParameters;
Lyn Hanf1c9b8b2019-03-14 16:49:48 -0700110 @Mock
111 private ConfigurationController mConfigurationController;
Joshua Tsujidd4d9f92019-05-13 13:57:38 -0400112 @Mock
113 private ZenModeController mZenModeController;
114 @Mock
115 private ZenModeConfig mZenModeConfig;
Mady Mellor80c25b22019-06-17 14:40:37 -0700116 @Mock
117 private FaceManager mFaceManager;
Mark Renoufc19b4732019-06-26 12:08:33 -0400118 @Mock
119 private NotificationLockscreenUserManager mLockscreenUserManager;
Mady Mellorf474e0d2019-08-01 11:08:40 -0700120 @Mock
Lucas Dupine25c4872019-07-29 13:51:35 -0700121 private SysuiStatusBarStateController mStatusBarStateController;
122 @Mock
123 private KeyguardBypassController mKeyguardBypassController;
Lyn Hanf1c9b8b2019-03-14 16:49:48 -0700124
Ned Burns01e38212019-01-03 16:32:52 -0500125 @Captor
126 private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
Mady Mellorc2ff0112019-03-28 14:18:06 -0700127 @Captor
128 private ArgumentCaptor<NotificationRemoveInterceptor> mRemoveInterceptorCaptor;
Mady Mellorebdbbb92018-11-15 14:36:48 -0800129
130 private TestableBubbleController mBubbleController;
wilsonshihe8321942019-10-18 18:39:46 +0800131 private NotificationShadeWindowController mNotificationShadeWindowController;
Ned Burns01e38212019-01-03 16:32:52 -0500132 private NotificationEntryListener mEntryListener;
Mady Mellorc2ff0112019-03-28 14:18:06 -0700133 private NotificationRemoveInterceptor mRemoveInterceptor;
Mady Mellorebdbbb92018-11-15 14:36:48 -0800134
135 private NotificationTestHelper mNotificationTestHelper;
136 private ExpandableNotificationRow mRow;
137 private ExpandableNotificationRow mRow2;
Mady Mellorfc02cc32019-04-01 14:47:55 -0700138 private ExpandableNotificationRow mNonBubbleNotifRow;
Mady Mellorebdbbb92018-11-15 14:36:48 -0800139
Mady Mellorb4991e62019-01-10 15:14:51 -0800140 @Mock
Mady Melloracb12152019-01-29 15:24:48 -0800141 private BubbleController.BubbleStateChangeListener mBubbleStateChangeListener;
142 @Mock
143 private BubbleController.BubbleExpandListener mBubbleExpandListener;
Mark Renouf6b2331c2019-03-21 13:40:08 -0400144 @Mock
Mark Renouf08bc42a2019-03-07 13:01:59 -0500145 private PendingIntent mDeleteIntent;
Dave Mankoff2aff6c32019-10-14 17:40:37 -0400146 @Mock
147 private SysuiColorExtractor mColorExtractor;
148 @Mock
149 ColorExtractor.GradientColors mGradientColors;
Heemin Seogafb3dbc2019-11-04 16:05:19 -0800150 @Mock
151 private Resources mResources;
Mady Mellor7f234902019-10-20 12:06:29 -0700152 @Mock
Heemin Seogba6337f2019-12-10 15:34:37 -0800153 private ShadeController mShadeController;
Aran Inkaa4dfa72019-11-18 16:49:07 -0500154 @Mock
155 private RemoteInputUriController mRemoteInputUriController;
Dave Mankoff56fe9e42020-01-08 15:42:06 -0500156 @Mock
157 private NotificationRowComponent mNotificationRowComponent;
Mark Renouf08bc42a2019-03-07 13:01:59 -0500158
Heemin Seogafb3dbc2019-11-04 16:05:19 -0800159 private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
Mady Mellorcfd06c12019-02-13 14:32:12 -0800160 private BubbleData mBubbleData;
161
Mady Mellorb8aaf972019-11-26 10:28:00 -0800162 private TestableLooper mTestableLooper;
163
Mady Mellorebdbbb92018-11-15 14:36:48 -0800164 @Before
165 public void setUp() throws Exception {
166 MockitoAnnotations.initMocks(this);
Mady Mellorb8aaf972019-11-26 10:28:00 -0800167
168 mTestableLooper = TestableLooper.get(this);
169
Mady Mellor80c25b22019-06-17 14:40:37 -0700170 mContext.addMockSystemService(FaceManager.class, mFaceManager);
Dave Mankoff2aff6c32019-10-14 17:40:37 -0400171 when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800172
Heemin Seogafb3dbc2019-11-04 16:05:19 -0800173 mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext,
Dave Mankoff56fe9e42020-01-08 15:42:06 -0500174 new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()),
175 new NotificationRowComponent.Builder() {
176 @Override
177 public NotificationRowComponent.Builder activatableNotificationView(
178 ActivatableNotificationView view) {
179 return this;
180 }
181
182 @Override
183 public NotificationRowComponent build() {
184 return mNotificationRowComponent;
185 }
186 });
Heemin Seogafb3dbc2019-11-04 16:05:19 -0800187
Mady Mellorebdbbb92018-11-15 14:36:48 -0800188 // Bubbles get added to status bar window view
wilsonshihe8321942019-10-18 18:39:46 +0800189 mNotificationShadeWindowController = new NotificationShadeWindowController(mContext,
190 mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
Heemin Seogafb3dbc2019-11-04 16:05:19 -0800191 mConfigurationController, mKeyguardBypassController, mColorExtractor,
wilsonshihe8321942019-10-18 18:39:46 +0800192 mSuperStatusBarViewFactory);
193 mNotificationShadeWindowController.attach();
Mady Mellorebdbbb92018-11-15 14:36:48 -0800194
195 // Need notifications for bubbles
Lucas Dupind236ee32019-10-08 15:33:59 -0700196 mNotificationTestHelper = new NotificationTestHelper(mContext, mDependency);
Mark Renouf08bc42a2019-03-07 13:01:59 -0500197 mRow = mNotificationTestHelper.createBubble(mDeleteIntent);
198 mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
Mady Mellorfc02cc32019-04-01 14:47:55 -0700199 mNonBubbleNotifRow = mNotificationTestHelper.createRow();
Mady Mellor3ed46202019-03-26 20:22:35 -0700200
Ned Burns01e38212019-01-03 16:32:52 -0500201 // Return non-null notification data from the NEM
Evan Laird181de622019-10-24 09:53:02 -0400202 when(mNotificationEntryManager
203 .getActiveNotificationUnfiltered(mRow.getEntry().getKey())).thenReturn(
204 mRow.getEntry());
Ned Burns01e38212019-01-03 16:32:52 -0500205
Joshua Tsujidd4d9f92019-05-13 13:57:38 -0400206 mZenModeConfig.suppressedVisualEffects = 0;
207 when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
208
Mady Melloraa8fef22019-04-11 13:36:40 -0700209 TestableNotificationInterruptionStateProvider interruptionStateProvider =
Mady Mellorc55b4122019-06-07 18:14:02 -0700210 new TestableNotificationInterruptionStateProvider(mContext,
211 mock(NotificationFilter.class),
Lucas Dupinbd7366d2019-09-25 13:39:21 -0700212 mock(StatusBarStateController.class),
213 mock(BatteryController.class));
Mady Melloraa8fef22019-04-11 13:36:40 -0700214 interruptionStateProvider.setUpWithPresenter(
215 mock(NotificationPresenter.class),
216 mock(HeadsUpManager.class),
217 mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class));
Mark Renouf71a3af62019-04-08 15:02:54 -0400218 mBubbleData = new BubbleData(mContext);
Mady Mellor22f2f072019-04-18 13:26:18 -0700219 mBubbleController = new TestableBubbleController(mContext,
wilsonshihe8321942019-10-18 18:39:46 +0800220 mNotificationShadeWindowController,
Mady Mellor7f234902019-10-20 12:06:29 -0700221 mStatusBarStateController,
222 mShadeController,
Mady Mellor22f2f072019-04-18 13:26:18 -0700223 mBubbleData,
224 mConfigurationController,
225 interruptionStateProvider,
226 mZenModeController,
227 mLockscreenUserManager,
Mady Mellor7f234902019-10-20 12:06:29 -0700228 mNotificationGroupManager,
Aran Inkaa4dfa72019-11-18 16:49:07 -0500229 mNotificationEntryManager,
230 mRemoteInputUriController);
Mady Melloracb12152019-01-29 15:24:48 -0800231 mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
232 mBubbleController.setExpandListener(mBubbleExpandListener);
Ned Burns01e38212019-01-03 16:32:52 -0500233
234 // Get a reference to the BubbleController's entry listener
235 verify(mNotificationEntryManager, atLeastOnce())
236 .addNotificationEntryListener(mEntryListenerCaptor.capture());
237 mEntryListener = mEntryListenerCaptor.getValue();
Mady Mellorc2ff0112019-03-28 14:18:06 -0700238 // And the remove interceptor
239 verify(mNotificationEntryManager, atLeastOnce())
240 .setNotificationRemoveInterceptor(mRemoveInterceptorCaptor.capture());
241 mRemoveInterceptor = mRemoveInterceptorCaptor.getValue();
Mady Mellorebdbbb92018-11-15 14:36:48 -0800242 }
243
244 @Test
Mady Mellorebdbbb92018-11-15 14:36:48 -0800245 public void testAddBubble() {
Mark Renouff97ed462019-04-05 13:46:24 -0400246 mBubbleController.updateBubble(mRow.getEntry());
Mady Mellorebdbbb92018-11-15 14:36:48 -0800247 assertTrue(mBubbleController.hasBubbles());
Mady Melloracb12152019-01-29 15:24:48 -0800248
249 verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800250 }
251
252 @Test
253 public void testHasBubbles() {
254 assertFalse(mBubbleController.hasBubbles());
Mark Renouff97ed462019-04-05 13:46:24 -0400255 mBubbleController.updateBubble(mRow.getEntry());
Mady Mellorebdbbb92018-11-15 14:36:48 -0800256 assertTrue(mBubbleController.hasBubbles());
257 }
258
259 @Test
260 public void testRemoveBubble() {
Mark Renouff97ed462019-04-05 13:46:24 -0400261 mBubbleController.updateBubble(mRow.getEntry());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400262 assertNotNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
Mady Mellorebdbbb92018-11-15 14:36:48 -0800263 assertTrue(mBubbleController.hasBubbles());
Beverly85d4c192019-09-30 11:40:39 -0400264 verify(mNotificationEntryManager).updateNotifications(any());
Mady Melloracb12152019-01-29 15:24:48 -0800265 verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
266
Ned Burns00b4b2d2019-10-17 22:09:27 -0400267 mBubbleController.removeBubble(
268 mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
wilsonshihe8321942019-10-18 18:39:46 +0800269 assertFalse(mNotificationShadeWindowController.getBubblesShowing());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400270 assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
Beverly85d4c192019-09-30 11:40:39 -0400271 verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
Mady Melloracb12152019-01-29 15:24:48 -0800272 verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800273 }
274
275 @Test
Mady Mellorc2ff0112019-03-28 14:18:06 -0700276 public void testRemoveBubble_withDismissedNotif() {
Mady Mellor58dc5192019-12-16 13:49:56 -0800277 mEntryListener.onNotificationAdded(mRow.getEntry());
Mady Mellorc2ff0112019-03-28 14:18:06 -0700278 mBubbleController.updateBubble(mRow.getEntry());
279
280 assertTrue(mBubbleController.hasBubbles());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400281 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500282 mRow.getEntry()));
Mady Mellorc2ff0112019-03-28 14:18:06 -0700283
284 // Make it look like dismissed notif
Mady Mellorf44b6832020-01-14 13:26:14 -0800285 mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
Mady Mellorc2ff0112019-03-28 14:18:06 -0700286
287 // Now remove the bubble
Ned Burns00b4b2d2019-10-17 22:09:27 -0400288 mBubbleController.removeBubble(
289 mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
Mady Mellorc2ff0112019-03-28 14:18:06 -0700290
291 // Since the notif is dismissed, once the bubble is removed, performRemoveNotification gets
292 // called to really remove the notif
293 verify(mNotificationEntryManager, times(1)).performRemoveNotification(
Ned Burns00b4b2d2019-10-17 22:09:27 -0400294 mRow.getEntry().getSbn(), UNDEFINED_DISMISS_REASON);
Mady Mellorc2ff0112019-03-28 14:18:06 -0700295 assertFalse(mBubbleController.hasBubbles());
296 }
297
298 @Test
Mady Mellorebdbbb92018-11-15 14:36:48 -0800299 public void testDismissStack() {
Mark Renouff97ed462019-04-05 13:46:24 -0400300 mBubbleController.updateBubble(mRow.getEntry());
Beverly85d4c192019-09-30 11:40:39 -0400301 verify(mNotificationEntryManager, times(1)).updateNotifications(any());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400302 assertNotNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
Mark Renouff97ed462019-04-05 13:46:24 -0400303 mBubbleController.updateBubble(mRow2.getEntry());
Beverly85d4c192019-09-30 11:40:39 -0400304 verify(mNotificationEntryManager, times(2)).updateNotifications(any());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400305 assertNotNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
Mady Mellorebdbbb92018-11-15 14:36:48 -0800306 assertTrue(mBubbleController.hasBubbles());
307
Mark Renouf08bc42a2019-03-07 13:01:59 -0500308 mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
wilsonshihe8321942019-10-18 18:39:46 +0800309 assertFalse(mNotificationShadeWindowController.getBubblesShowing());
Beverly85d4c192019-09-30 11:40:39 -0400310 verify(mNotificationEntryManager, times(3)).updateNotifications(any());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400311 assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
312 assertNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
Mady Mellorebdbbb92018-11-15 14:36:48 -0800313 }
314
315 @Test
Mady Melloracb12152019-01-29 15:24:48 -0800316 public void testExpandCollapseStack() {
Mady Mellorebdbbb92018-11-15 14:36:48 -0800317 assertFalse(mBubbleController.isStackExpanded());
Mady Melloracb12152019-01-29 15:24:48 -0800318
319 // Mark it as a bubble and add it explicitly
Mady Mellor58dc5192019-12-16 13:49:56 -0800320 mEntryListener.onNotificationAdded(mRow.getEntry());
Mark Renouff97ed462019-04-05 13:46:24 -0400321 mBubbleController.updateBubble(mRow.getEntry());
Mady Mellorebdbbb92018-11-15 14:36:48 -0800322
Mady Mellorce23c462019-06-17 17:30:07 -0700323 // We should have bubbles & their notifs should not be suppressed
Mady Melloracb12152019-01-29 15:24:48 -0800324 assertTrue(mBubbleController.hasBubbles());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400325 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500326 mRow.getEntry()));
wilsonshihe8321942019-10-18 18:39:46 +0800327 assertFalse(mNotificationShadeWindowController.getBubbleExpanded());
Mady Melloracb12152019-01-29 15:24:48 -0800328
329 // Expand the stack
Mady Mellorebdbbb92018-11-15 14:36:48 -0800330 BubbleStackView stackView = mBubbleController.getStackView();
Mark Renouf71a3af62019-04-08 15:02:54 -0400331 mBubbleController.expandStack();
Mady Mellorebdbbb92018-11-15 14:36:48 -0800332 assertTrue(mBubbleController.isStackExpanded());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400333 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
wilsonshihe8321942019-10-18 18:39:46 +0800334 assertTrue(mNotificationShadeWindowController.getBubbleExpanded());
Mady Mellorebdbbb92018-11-15 14:36:48 -0800335
Mady Mellorce23c462019-06-17 17:30:07 -0700336 // Make sure the notif is suppressed
Ned Burns00b4b2d2019-10-17 22:09:27 -0400337 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500338 mRow.getEntry()));
Mady Melloracb12152019-01-29 15:24:48 -0800339
340 // Collapse
Mark Renouf71a3af62019-04-08 15:02:54 -0400341 mBubbleController.collapseStack();
Ned Burns00b4b2d2019-10-17 22:09:27 -0400342 verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
Mady Mellorebdbbb92018-11-15 14:36:48 -0800343 assertFalse(mBubbleController.isStackExpanded());
wilsonshihe8321942019-10-18 18:39:46 +0800344 assertFalse(mNotificationShadeWindowController.getBubbleExpanded());
Mady Mellorebdbbb92018-11-15 14:36:48 -0800345 }
346
347 @Test
Mady Melloracb12152019-01-29 15:24:48 -0800348 public void testCollapseAfterChangingExpandedBubble() {
349 // Mark it as a bubble and add it explicitly
Mady Mellor58dc5192019-12-16 13:49:56 -0800350 mEntryListener.onNotificationAdded(mRow.getEntry());
351 mEntryListener.onNotificationAdded(mRow2.getEntry());
Mark Renouff97ed462019-04-05 13:46:24 -0400352 mBubbleController.updateBubble(mRow.getEntry());
353 mBubbleController.updateBubble(mRow2.getEntry());
Mady Mellorebdbbb92018-11-15 14:36:48 -0800354
Mady Mellorce23c462019-06-17 17:30:07 -0700355 // We should have bubbles & their notifs should not be suppressed
Mady Melloracb12152019-01-29 15:24:48 -0800356 assertTrue(mBubbleController.hasBubbles());
Mady Mellorce23c462019-06-17 17:30:07 -0700357 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500358 mRow.getEntry()));
Ned Burns00b4b2d2019-10-17 22:09:27 -0400359 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500360 mRow2.getEntry()));
Mady Melloracb12152019-01-29 15:24:48 -0800361
362 // Expand
Mady Mellorebdbbb92018-11-15 14:36:48 -0800363 BubbleStackView stackView = mBubbleController.getStackView();
Mark Renouf71a3af62019-04-08 15:02:54 -0400364 mBubbleController.expandStack();
Mady Mellorebdbbb92018-11-15 14:36:48 -0800365 assertTrue(mBubbleController.isStackExpanded());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400366 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
Mady Mellorebdbbb92018-11-15 14:36:48 -0800367
Mark Renoufba5ab512019-05-02 15:21:01 -0400368 // Last added is the one that is expanded
Mady Mellorb8aaf972019-11-26 10:28:00 -0800369 assertEquals(mRow2.getEntry(), mBubbleData.getSelectedBubble().getEntry());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400370 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500371 mRow2.getEntry()));
Mark Renouf71a3af62019-04-08 15:02:54 -0400372
Mark Renoufba5ab512019-05-02 15:21:01 -0400373 // Switch which bubble is expanded
Ned Burns00b4b2d2019-10-17 22:09:27 -0400374 mBubbleController.selectBubble(mRow.getEntry().getKey());
Mady Mellorf44b6832020-01-14 13:26:14 -0800375 mBubbleData.setExpanded(true);
376 assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400377 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500378 mRow.getEntry()));
Mark Renoufba5ab512019-05-02 15:21:01 -0400379
Mady Melloracb12152019-01-29 15:24:48 -0800380 // collapse for previous bubble
Ned Burns00b4b2d2019-10-17 22:09:27 -0400381 verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
Mady Melloracb12152019-01-29 15:24:48 -0800382 // expand for selected bubble
Ned Burns00b4b2d2019-10-17 22:09:27 -0400383 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
Mady Melloredd4ee12019-01-18 10:45:11 -0800384
Mady Melloracb12152019-01-29 15:24:48 -0800385 // Collapse
Mady Mellorebdbbb92018-11-15 14:36:48 -0800386 mBubbleController.collapseStack();
387 assertFalse(mBubbleController.isStackExpanded());
388 }
389
Ned Burns01e38212019-01-03 16:32:52 -0500390 @Test
Mady Melloraea895f02019-07-10 14:37:48 -0700391 public void testExpansionRemovesShowInShadeAndDot() {
Mady Melloracb12152019-01-29 15:24:48 -0800392 // Mark it as a bubble and add it explicitly
Mady Mellor58dc5192019-12-16 13:49:56 -0800393 mEntryListener.onNotificationAdded(mRow.getEntry());
Mark Renouff97ed462019-04-05 13:46:24 -0400394 mBubbleController.updateBubble(mRow.getEntry());
Mady Melloracb12152019-01-29 15:24:48 -0800395
Mady Mellorce23c462019-06-17 17:30:07 -0700396 // We should have bubbles & their notifs should not be suppressed
Mady Melloracb12152019-01-29 15:24:48 -0800397 assertTrue(mBubbleController.hasBubbles());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400398 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500399 mRow.getEntry()));
Mady Mellorb8aaf972019-11-26 10:28:00 -0800400
401 mTestableLooper.processAllMessages();
402 assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
Mady Melloracb12152019-01-29 15:24:48 -0800403
404 // Expand
Mark Renouf71a3af62019-04-08 15:02:54 -0400405 mBubbleController.expandStack();
Mady Melloracb12152019-01-29 15:24:48 -0800406 assertTrue(mBubbleController.isStackExpanded());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400407 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
Mady Melloracb12152019-01-29 15:24:48 -0800408
Mady Mellorce23c462019-06-17 17:30:07 -0700409 // Notif is suppressed after expansion
Ned Burns00b4b2d2019-10-17 22:09:27 -0400410 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500411 mRow.getEntry()));
Mady Melloraea895f02019-07-10 14:37:48 -0700412 // Notif shouldn't show dot after expansion
Mady Mellorb8aaf972019-11-26 10:28:00 -0800413 assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
Mady Melloraea895f02019-07-10 14:37:48 -0700414 }
415
416 @Test
417 public void testUpdateWhileExpanded_DoesntChangeShowInShadeAndDot() {
418 // Mark it as a bubble and add it explicitly
Mady Mellor58dc5192019-12-16 13:49:56 -0800419 mEntryListener.onNotificationAdded(mRow.getEntry());
Mady Melloraea895f02019-07-10 14:37:48 -0700420 mBubbleController.updateBubble(mRow.getEntry());
421
422 // We should have bubbles & their notifs should not be suppressed
423 assertTrue(mBubbleController.hasBubbles());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400424 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500425 mRow.getEntry()));
Mady Mellorb8aaf972019-11-26 10:28:00 -0800426
427 mTestableLooper.processAllMessages();
428 assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
Mady Melloraea895f02019-07-10 14:37:48 -0700429
430 // Expand
Mady Melloraea895f02019-07-10 14:37:48 -0700431 mBubbleController.expandStack();
432 assertTrue(mBubbleController.isStackExpanded());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400433 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
Mady Melloraea895f02019-07-10 14:37:48 -0700434
435 // Notif is suppressed after expansion
Ned Burns00b4b2d2019-10-17 22:09:27 -0400436 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500437 mRow.getEntry()));
Mady Melloraea895f02019-07-10 14:37:48 -0700438 // Notif shouldn't show dot after expansion
Mady Mellorb8aaf972019-11-26 10:28:00 -0800439 assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
Mady Melloraea895f02019-07-10 14:37:48 -0700440
441 // Send update
442 mEntryListener.onPreEntryUpdated(mRow.getEntry());
443
444 // Nothing should have changed
445 // Notif is suppressed after expansion
Ned Burns00b4b2d2019-10-17 22:09:27 -0400446 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500447 mRow.getEntry()));
Mady Melloraea895f02019-07-10 14:37:48 -0700448 // Notif shouldn't show dot after expansion
Mady Mellorb8aaf972019-11-26 10:28:00 -0800449 assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
Mady Melloracb12152019-01-29 15:24:48 -0800450 }
451
452 @Test
453 public void testRemoveLastExpandedCollapses() {
454 // Mark it as a bubble and add it explicitly
Mady Mellor58dc5192019-12-16 13:49:56 -0800455 mEntryListener.onNotificationAdded(mRow.getEntry());
456 mEntryListener.onNotificationAdded(mRow2.getEntry());
Mark Renouff97ed462019-04-05 13:46:24 -0400457 mBubbleController.updateBubble(mRow.getEntry());
458 mBubbleController.updateBubble(mRow2.getEntry());
Mady Melloracb12152019-01-29 15:24:48 -0800459 verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
460
461 // Expand
462 BubbleStackView stackView = mBubbleController.getStackView();
Mark Renouf71a3af62019-04-08 15:02:54 -0400463 mBubbleController.expandStack();
Mady Melloracb12152019-01-29 15:24:48 -0800464
465 assertTrue(mBubbleController.isStackExpanded());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400466 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
Mady Melloracb12152019-01-29 15:24:48 -0800467
Mark Renoufba5ab512019-05-02 15:21:01 -0400468 // Last added is the one that is expanded
Mady Mellorb8aaf972019-11-26 10:28:00 -0800469 assertEquals(mRow2.getEntry(), stackView.getExpandedBubble().getEntry());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400470 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500471 mRow2.getEntry()));
Mady Melloracb12152019-01-29 15:24:48 -0800472
473 // Dismiss currently expanded
Mark Renouf08bc42a2019-03-07 13:01:59 -0500474 mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(),
475 BubbleController.DISMISS_USER_GESTURE);
Ned Burns00b4b2d2019-10-17 22:09:27 -0400476 verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
Mady Melloracb12152019-01-29 15:24:48 -0800477
Mark Renoufba5ab512019-05-02 15:21:01 -0400478 // Make sure first bubble is selected
Mady Mellorb8aaf972019-11-26 10:28:00 -0800479 assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400480 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
Mady Melloracb12152019-01-29 15:24:48 -0800481
482 // Dismiss that one
Mark Renouf08bc42a2019-03-07 13:01:59 -0500483 mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(),
484 BubbleController.DISMISS_USER_GESTURE);
Mady Melloracb12152019-01-29 15:24:48 -0800485
486 // Make sure state changes and collapse happens
Ned Burns00b4b2d2019-10-17 22:09:27 -0400487 verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
Mady Melloracb12152019-01-29 15:24:48 -0800488 verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
489 assertFalse(mBubbleController.hasBubbles());
490 }
491
492 @Test
Mady Mellorb25f9062019-12-09 12:12:57 -0800493 public void testAutoExpand_fails_noFlag() {
Mady Mellore80930e2019-03-21 16:00:45 -0700494 assertFalse(mBubbleController.isStackExpanded());
Mady Mellor8d25b202019-06-25 13:59:28 -0700495 setMetadataFlags(mRow.getEntry(),
496 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */);
Mady Mellore80930e2019-03-21 16:00:45 -0700497
498 // Add the auto expand bubble
Mady Mellor58dc5192019-12-16 13:49:56 -0800499 mEntryListener.onNotificationAdded(mRow.getEntry());
Mady Mellor8d25b202019-06-25 13:59:28 -0700500 mBubbleController.updateBubble(mRow.getEntry());
Mady Mellore80930e2019-03-21 16:00:45 -0700501
502 // Expansion shouldn't change
503 verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
Ned Burns00b4b2d2019-10-17 22:09:27 -0400504 mRow.getEntry().getKey());
Mady Mellore80930e2019-03-21 16:00:45 -0700505 assertFalse(mBubbleController.isStackExpanded());
506
507 // # of bubbles should change
508 verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
509 }
510
511 @Test
Mady Mellorb25f9062019-12-09 12:12:57 -0800512 public void testAutoExpand_succeeds_withFlag() {
Mady Mellor8d25b202019-06-25 13:59:28 -0700513 setMetadataFlags(mRow.getEntry(),
514 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, true /* enableFlag */);
Mady Mellore80930e2019-03-21 16:00:45 -0700515
516 // Add the auto expand bubble
Mady Mellor58dc5192019-12-16 13:49:56 -0800517 mEntryListener.onNotificationAdded(mRow.getEntry());
Mady Mellor8d25b202019-06-25 13:59:28 -0700518 mBubbleController.updateBubble(mRow.getEntry());
Mady Mellore80930e2019-03-21 16:00:45 -0700519
520 // Expansion should change
521 verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
Ned Burns00b4b2d2019-10-17 22:09:27 -0400522 mRow.getEntry().getKey());
Mady Mellore80930e2019-03-21 16:00:45 -0700523 assertTrue(mBubbleController.isStackExpanded());
524
525 // # of bubbles should change
526 verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
Mady Mellore80930e2019-03-21 16:00:45 -0700527 }
528
Mady Mellor3ed46202019-03-26 20:22:35 -0700529 @Test
Mady Mellorb25f9062019-12-09 12:12:57 -0800530 public void testSuppressNotif_onInitialNotif() {
Mady Mellor8d25b202019-06-25 13:59:28 -0700531 setMetadataFlags(mRow.getEntry(),
532 Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
Mady Mellor3ed46202019-03-26 20:22:35 -0700533
534 // Add the suppress notif bubble
Mady Mellor58dc5192019-12-16 13:49:56 -0800535 mEntryListener.onNotificationAdded(mRow.getEntry());
Mady Mellor8d25b202019-06-25 13:59:28 -0700536 mBubbleController.updateBubble(mRow.getEntry());
Mady Mellor3ed46202019-03-26 20:22:35 -0700537
Mady Mellorce23c462019-06-17 17:30:07 -0700538 // Notif should be suppressed because we were foreground
Ned Burns00b4b2d2019-10-17 22:09:27 -0400539 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500540 mRow.getEntry()));
Mady Mellorb25f9062019-12-09 12:12:57 -0800541 // Dot + flyout is hidden because notif is suppressed
542 assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
543 assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showFlyout());
Mady Mellor3ed46202019-03-26 20:22:35 -0700544
545 // # of bubbles should change
546 verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
Mady Mellor3ed46202019-03-26 20:22:35 -0700547 }
Mady Mellore80930e2019-03-21 16:00:45 -0700548
549 @Test
Mady Mellorb25f9062019-12-09 12:12:57 -0800550 public void testSuppressNotif_onUpdateNotif() {
551 mBubbleController.updateBubble(mRow.getEntry());
552
553 // Should not be suppressed
554 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500555 mRow.getEntry()));
Mady Mellorb25f9062019-12-09 12:12:57 -0800556 // Should show dot
557 assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
558
559 // Update to suppress notif
560 setMetadataFlags(mRow.getEntry(),
561 Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
562 mBubbleController.updateBubble(mRow.getEntry());
563
564 // Notif should be suppressed
565 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500566 mRow.getEntry()));
Mady Mellorb25f9062019-12-09 12:12:57 -0800567 // Dot + flyout is hidden because notif is suppressed
568 assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
569 assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showFlyout());
570
571 // # of bubbles should change
572 verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
573 }
574
Mady Mellorb25f9062019-12-09 12:12:57 -0800575 @Test
Mark Renouffec45da2019-03-13 13:24:27 -0400576 public void testExpandStackAndSelectBubble_removedFirst() {
Ned Burns00b4b2d2019-10-17 22:09:27 -0400577 final String key = mRow.getEntry().getKey();
Mark Renouffec45da2019-03-13 13:24:27 -0400578
Mady Mellor58dc5192019-12-16 13:49:56 -0800579 mEntryListener.onNotificationAdded(mRow.getEntry());
Mark Renouff97ed462019-04-05 13:46:24 -0400580 mBubbleController.updateBubble(mRow.getEntry());
Mark Renouffec45da2019-03-13 13:24:27 -0400581
Mark Renouffec45da2019-03-13 13:24:27 -0400582 // Simulate notification cancellation.
Ned Burns00b4b2d2019-10-17 22:09:27 -0400583 mRemoveInterceptor.onNotificationRemoveRequested(
584 mRow.getEntry().getKey(), REASON_APP_CANCEL);
Mark Renouffec45da2019-03-13 13:24:27 -0400585
586 mBubbleController.expandStackAndSelectBubble(key);
587 }
588
589 @Test
Mady Mellor3f2efdb2018-11-21 11:30:45 -0800590 public void testMarkNewNotificationAsShowInShade() {
Mady Mellor58dc5192019-12-16 13:49:56 -0800591 mEntryListener.onNotificationAdded(mRow.getEntry());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400592 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500593 mRow.getEntry()));
Mady Mellorb8aaf972019-11-26 10:28:00 -0800594
595 mTestableLooper.processAllMessages();
596 assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
Mady Mellor3f2efdb2018-11-21 11:30:45 -0800597 }
598
Mark Renouf08bc42a2019-03-07 13:01:59 -0500599 @Test
Mady Mellorfc02cc32019-04-01 14:47:55 -0700600 public void testAddNotif_notBubble() {
Mady Mellor58dc5192019-12-16 13:49:56 -0800601 mEntryListener.onNotificationAdded(mNonBubbleNotifRow.getEntry());
Mady Mellorfc02cc32019-04-01 14:47:55 -0700602 mEntryListener.onPreEntryUpdated(mNonBubbleNotifRow.getEntry());
603
604 verify(mBubbleStateChangeListener, never()).onHasBubblesChanged(anyBoolean());
605 assertThat(mBubbleController.hasBubbles()).isFalse();
606 }
607
608 @Test
Mark Renouf08bc42a2019-03-07 13:01:59 -0500609 public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
Mark Renouff97ed462019-04-05 13:46:24 -0400610 mBubbleController.updateBubble(mRow.getEntry());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400611 mBubbleController.removeBubble(mRow.getEntry().getKey(), BubbleController.DISMISS_AGED);
Mark Renouf08bc42a2019-03-07 13:01:59 -0500612 verify(mDeleteIntent, never()).send();
613 }
614
615 @Test
616 public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
Mark Renouff97ed462019-04-05 13:46:24 -0400617 mBubbleController.updateBubble(mRow.getEntry());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400618 mBubbleController.removeBubble(
619 mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
Mark Renouf08bc42a2019-03-07 13:01:59 -0500620 verify(mDeleteIntent, times(1)).send();
621 }
622
623 @Test
624 public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException {
Mark Renouff97ed462019-04-05 13:46:24 -0400625 mBubbleController.updateBubble(mRow.getEntry());
626 mBubbleController.updateBubble(mRow2.getEntry());
Mark Renouf08bc42a2019-03-07 13:01:59 -0500627 mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
628 verify(mDeleteIntent, times(2)).send();
629 }
630
Mady Melloraa8fef22019-04-11 13:36:40 -0700631 @Test
632 public void testRemoveBubble_noLongerBubbleAfterUpdate()
633 throws PendingIntent.CanceledException {
634 mBubbleController.updateBubble(mRow.getEntry());
635 assertTrue(mBubbleController.hasBubbles());
636
Ned Burns00b4b2d2019-10-17 22:09:27 -0400637 mRow.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
Mady Melloraa8fef22019-04-11 13:36:40 -0700638 mEntryListener.onPreEntryUpdated(mRow.getEntry());
639
640 assertFalse(mBubbleController.hasBubbles());
641 verify(mDeleteIntent, never()).send();
642 }
643
Mady Mellorc2ff0112019-03-28 14:18:06 -0700644 @Test
645 public void testRemoveBubble_succeeds_appCancel() {
Mady Mellor58dc5192019-12-16 13:49:56 -0800646 mEntryListener.onNotificationAdded(mRow.getEntry());
Mady Mellorc2ff0112019-03-28 14:18:06 -0700647 mBubbleController.updateBubble(mRow.getEntry());
648
649 assertTrue(mBubbleController.hasBubbles());
650
651 boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
Ned Burns00b4b2d2019-10-17 22:09:27 -0400652 mRow.getEntry().getKey(), REASON_APP_CANCEL);
Mady Mellorc2ff0112019-03-28 14:18:06 -0700653
654 // Cancels always remove so no need to intercept
655 assertFalse(intercepted);
656 assertFalse(mBubbleController.hasBubbles());
657 }
658
659 @Test
660 public void removeBubble_fails_clearAll() {
Mady Mellor58dc5192019-12-16 13:49:56 -0800661 mEntryListener.onNotificationAdded(mRow.getEntry());
Mady Mellorc2ff0112019-03-28 14:18:06 -0700662 mBubbleController.updateBubble(mRow.getEntry());
663
664 assertTrue(mBubbleController.hasBubbles());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400665 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500666 mRow.getEntry()));
Mady Mellorc2ff0112019-03-28 14:18:06 -0700667
668 boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
Ned Burns00b4b2d2019-10-17 22:09:27 -0400669 mRow.getEntry().getKey(), REASON_CANCEL_ALL);
Mady Mellorc2ff0112019-03-28 14:18:06 -0700670
671 // Intercept!
672 assertTrue(intercepted);
673 // Should update show in shade state
Ned Burns00b4b2d2019-10-17 22:09:27 -0400674 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500675 mRow.getEntry()));
Mady Mellorc2ff0112019-03-28 14:18:06 -0700676
677 verify(mNotificationEntryManager, never()).performRemoveNotification(
678 any(), anyInt());
679 assertTrue(mBubbleController.hasBubbles());
680 }
681
682 @Test
683 public void removeBubble_fails_userDismissNotif() {
Mady Mellor58dc5192019-12-16 13:49:56 -0800684 mEntryListener.onNotificationAdded(mRow.getEntry());
Mady Mellorc2ff0112019-03-28 14:18:06 -0700685 mBubbleController.updateBubble(mRow.getEntry());
686
687 assertTrue(mBubbleController.hasBubbles());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400688 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500689 mRow.getEntry()));
Mady Mellorc2ff0112019-03-28 14:18:06 -0700690
691 boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
Ned Burns00b4b2d2019-10-17 22:09:27 -0400692 mRow.getEntry().getKey(), REASON_CANCEL);
Mady Mellorc2ff0112019-03-28 14:18:06 -0700693
694 // Intercept!
695 assertTrue(intercepted);
696 // Should update show in shade state
Ned Burns00b4b2d2019-10-17 22:09:27 -0400697 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500698 mRow.getEntry()));
Mady Mellorc2ff0112019-03-28 14:18:06 -0700699
700 verify(mNotificationEntryManager, never()).performRemoveNotification(
701 any(), anyInt());
702 assertTrue(mBubbleController.hasBubbles());
703 }
704
705 @Test
706 public void removeBubble_succeeds_userDismissBubble_userDimissNotif() {
Mady Mellor58dc5192019-12-16 13:49:56 -0800707 mEntryListener.onNotificationAdded(mRow.getEntry());
Mady Mellorc2ff0112019-03-28 14:18:06 -0700708 mBubbleController.updateBubble(mRow.getEntry());
709
710 assertTrue(mBubbleController.hasBubbles());
Ned Burns00b4b2d2019-10-17 22:09:27 -0400711 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500712 mRow.getEntry()));
Mady Mellorc2ff0112019-03-28 14:18:06 -0700713
714 // Dismiss the bubble
Ned Burns00b4b2d2019-10-17 22:09:27 -0400715 mBubbleController.removeBubble(
716 mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
Mady Mellorc2ff0112019-03-28 14:18:06 -0700717 assertFalse(mBubbleController.hasBubbles());
718
719 // Dismiss the notification
720 boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
Ned Burns00b4b2d2019-10-17 22:09:27 -0400721 mRow.getEntry().getKey(), REASON_CANCEL);
Mady Mellorc2ff0112019-03-28 14:18:06 -0700722
723 // It's no longer a bubble so we shouldn't intercept
724 assertFalse(intercepted);
725 }
726
Mady Mellorf44b6832020-01-14 13:26:14 -0800727 @Test
728 public void testNotifyShadeSuppressionChange_notificationDismiss() {
729 BubbleController.NotificationSuppressionChangedListener listener =
730 mock(BubbleController.NotificationSuppressionChangedListener.class);
731 mBubbleData.setSuppressionChangedListener(listener);
732
733 mEntryListener.onNotificationAdded(mRow.getEntry());
734
735 assertTrue(mBubbleController.hasBubbles());
736 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500737 mRow.getEntry()));
Mady Mellorf44b6832020-01-14 13:26:14 -0800738
739 mRemoveInterceptor.onNotificationRemoveRequested(mRow.getEntry().getKey(), REASON_CANCEL);
740
741 // Should update show in shade state
742 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500743 mRow.getEntry()));
Mady Mellorf44b6832020-01-14 13:26:14 -0800744
745 // Should notify delegate that shade state changed
746 verify(listener).onBubbleNotificationSuppressionChange(
747 mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
748 }
749
750 @Test
751 public void testNotifyShadeSuppressionChange_bubbleExpanded() {
752 BubbleController.NotificationSuppressionChangedListener listener =
753 mock(BubbleController.NotificationSuppressionChangedListener.class);
754 mBubbleData.setSuppressionChangedListener(listener);
755
756 mEntryListener.onNotificationAdded(mRow.getEntry());
757
758 assertTrue(mBubbleController.hasBubbles());
759 assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500760 mRow.getEntry()));
Mady Mellorf44b6832020-01-14 13:26:14 -0800761
762 mBubbleData.setExpanded(true);
763
764 // Once a bubble is expanded the notif is suppressed
765 assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
Beverlyed8aea22020-01-22 16:52:47 -0500766 mRow.getEntry()));
Mady Mellorf44b6832020-01-14 13:26:14 -0800767
768 // Should notify delegate that shade state changed
769 verify(listener).onBubbleNotificationSuppressionChange(
770 mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
771 }
772
Mady Mellorebdbbb92018-11-15 14:36:48 -0800773 static class TestableBubbleController extends BubbleController {
Issei Suzukic0387542019-03-08 17:31:14 +0100774 // Let's assume surfaces can be synchronized immediately.
Mady Mellorebdbbb92018-11-15 14:36:48 -0800775 TestableBubbleController(Context context,
wilsonshihe8321942019-10-18 18:39:46 +0800776 NotificationShadeWindowController notificationShadeWindowController,
Mady Mellor7f234902019-10-20 12:06:29 -0700777 StatusBarStateController statusBarStateController,
Heemin Seogba6337f2019-12-10 15:34:37 -0800778 ShadeController shadeController,
Mady Mellor7f234902019-10-20 12:06:29 -0700779 BubbleData data,
Mady Melloraa8fef22019-04-11 13:36:40 -0700780 ConfigurationController configurationController,
Joshua Tsujidd4d9f92019-05-13 13:57:38 -0400781 NotificationInterruptionStateProvider interruptionStateProvider,
Mark Renoufc19b4732019-06-26 12:08:33 -0400782 ZenModeController zenModeController,
Mady Mellor22f2f072019-04-18 13:26:18 -0700783 NotificationLockscreenUserManager lockscreenUserManager,
Mady Mellor7f234902019-10-20 12:06:29 -0700784 NotificationGroupManager groupManager,
Aran Inkaa4dfa72019-11-18 16:49:07 -0500785 NotificationEntryManager entryManager,
786 RemoteInputUriController remoteInputUriController) {
Mady Mellor7f234902019-10-20 12:06:29 -0700787 super(context,
wilsonshihe8321942019-10-18 18:39:46 +0800788 notificationShadeWindowController, statusBarStateController, shadeController,
Mady Mellor7f234902019-10-20 12:06:29 -0700789 data, Runnable::run, configurationController, interruptionStateProvider,
Aran Inkaa4dfa72019-11-18 16:49:07 -0500790 zenModeController, lockscreenUserManager, groupManager, entryManager,
791 remoteInputUriController);
Mady Mellor3df7ab02019-12-09 15:07:10 -0800792 setInflateSynchronously(true);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800793 }
Mady Mellorebdbbb92018-11-15 14:36:48 -0800794 }
Mady Mellore80930e2019-03-21 16:00:45 -0700795
Mady Mellor8d25b202019-06-25 13:59:28 -0700796 static class TestableNotificationInterruptionStateProvider extends
Mady Melloraa8fef22019-04-11 13:36:40 -0700797 NotificationInterruptionStateProvider {
798
Mady Mellor8d25b202019-06-25 13:59:28 -0700799 TestableNotificationInterruptionStateProvider(Context context,
Lucas Dupinbd7366d2019-09-25 13:39:21 -0700800 NotificationFilter filter, StatusBarStateController controller,
801 BatteryController batteryController) {
802 super(context, filter, controller, batteryController);
Mady Melloraa8fef22019-04-11 13:36:40 -0700803 mUseHeadsUp = true;
804 }
805 }
806
Mady Mellore80930e2019-03-21 16:00:45 -0700807 /**
Mady Mellor8d25b202019-06-25 13:59:28 -0700808 * Sets the bubble metadata flags for this entry. These flags are normally set by
809 * NotificationManagerService when the notification is sent, however, these tests do not
810 * go through that path so we set them explicitly when testing.
811 */
812 private void setMetadataFlags(NotificationEntry entry, int flag, boolean enableFlag) {
813 Notification.BubbleMetadata bubbleMetadata =
Ned Burns00b4b2d2019-10-17 22:09:27 -0400814 entry.getSbn().getNotification().getBubbleMetadata();
Mady Mellor8d25b202019-06-25 13:59:28 -0700815 int flags = bubbleMetadata.getFlags();
816 if (enableFlag) {
817 flags |= flag;
818 } else {
819 flags &= ~flag;
820 }
821 bubbleMetadata.setFlags(flags);
822 }
Mady Mellorebdbbb92018-11-15 14:36:48 -0800823}