blob: 5e16721fe54821c281804eed2a9d22e1498f6b67 [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 Mellore80930e2019-03-21 16:00:45 -070019import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
20
Mady Mellorfc02cc32019-04-01 14:47:55 -070021import static com.google.common.truth.Truth.assertThat;
22
Mady Melloredd4ee12019-01-18 10:45:11 -080023import static org.junit.Assert.assertEquals;
Mady Mellorebdbbb92018-11-15 14:36:48 -080024import static org.junit.Assert.assertFalse;
25import static org.junit.Assert.assertTrue;
Mady Mellorfc02cc32019-04-01 14:47:55 -070026import static org.mockito.ArgumentMatchers.anyBoolean;
Ned Burns01e38212019-01-03 16:32:52 -050027import static org.mockito.Mockito.atLeastOnce;
Mark Renouf08bc42a2019-03-07 13:01:59 -050028import static org.mockito.Mockito.never;
29import static org.mockito.Mockito.times;
Ned Burns01e38212019-01-03 16:32:52 -050030import static org.mockito.Mockito.verify;
31import static org.mockito.Mockito.when;
Mady Mellorebdbbb92018-11-15 14:36:48 -080032
33import android.app.IActivityManager;
Mady Mellore80930e2019-03-21 16:00:45 -070034import android.app.Notification;
Mark Renouf08bc42a2019-03-07 13:01:59 -050035import android.app.PendingIntent;
Mady Mellore80930e2019-03-21 16:00:45 -070036import android.content.BroadcastReceiver;
Mady Mellorebdbbb92018-11-15 14:36:48 -080037import android.content.Context;
Mady Mellore80930e2019-03-21 16:00:45 -070038import android.content.Intent;
39import android.content.IntentFilter;
40import android.graphics.drawable.Icon;
Mady Mellorebdbbb92018-11-15 14:36:48 -080041import android.testing.AndroidTestingRunner;
42import android.testing.TestableLooper;
43import android.view.WindowManager;
44import android.widget.FrameLayout;
45
Brett Chabot84151d92019-02-27 15:37:59 -080046import androidx.test.filters.SmallTest;
47
Mady Mellore80930e2019-03-21 16:00:45 -070048import com.android.systemui.R;
Mady Mellorebdbbb92018-11-15 14:36:48 -080049import com.android.systemui.SysuiTestCase;
50import com.android.systemui.statusbar.NotificationTestHelper;
Ned Burns01e38212019-01-03 16:32:52 -050051import com.android.systemui.statusbar.notification.NotificationEntryListener;
52import com.android.systemui.statusbar.notification.NotificationEntryManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050053import com.android.systemui.statusbar.notification.collection.NotificationData;
Mady Mellor9bad2242019-01-28 11:21:51 -080054import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Mady Mellorebdbbb92018-11-15 14:36:48 -080055import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
56import com.android.systemui.statusbar.phone.DozeParameters;
57import com.android.systemui.statusbar.phone.StatusBarWindowController;
Lyn Hanf1c9b8b2019-03-14 16:49:48 -070058import com.android.systemui.statusbar.policy.ConfigurationController;
Mady Mellorebdbbb92018-11-15 14:36:48 -080059
60import org.junit.Before;
61import org.junit.Test;
62import org.junit.runner.RunWith;
Ned Burns01e38212019-01-03 16:32:52 -050063import org.mockito.ArgumentCaptor;
64import org.mockito.Captor;
Mady Mellorebdbbb92018-11-15 14:36:48 -080065import org.mockito.Mock;
66import org.mockito.MockitoAnnotations;
67
Mady Mellore80930e2019-03-21 16:00:45 -070068import java.util.concurrent.CountDownLatch;
69import java.util.concurrent.TimeUnit;
70
Mady Mellorebdbbb92018-11-15 14:36:48 -080071@SmallTest
72@RunWith(AndroidTestingRunner.class)
73@TestableLooper.RunWithLooper(setAsMainLooper = true)
74public class BubbleControllerTest extends SysuiTestCase {
75
Mady Mellor3ed46202019-03-26 20:22:35 -070076 // Some APIs rely on the app being foreground, check is via pkg name
77 private static final String FOREGROUND_TEST_PKG_NAME = "com.android.systemui.tests";
78
Mady Mellorebdbbb92018-11-15 14:36:48 -080079 @Mock
Ned Burns01e38212019-01-03 16:32:52 -050080 private NotificationEntryManager mNotificationEntryManager;
81 @Mock
Mady Mellorebdbbb92018-11-15 14:36:48 -080082 private WindowManager mWindowManager;
83 @Mock
84 private IActivityManager mActivityManager;
85 @Mock
86 private DozeParameters mDozeParameters;
Lyn Hanf1c9b8b2019-03-14 16:49:48 -070087 @Mock
88 private ConfigurationController mConfigurationController;
89
Mady Mellorebdbbb92018-11-15 14:36:48 -080090 private FrameLayout mStatusBarView;
Ned Burns01e38212019-01-03 16:32:52 -050091 @Captor
92 private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
Mady Mellorebdbbb92018-11-15 14:36:48 -080093
94 private TestableBubbleController mBubbleController;
95 private StatusBarWindowController mStatusBarWindowController;
Ned Burns01e38212019-01-03 16:32:52 -050096 private NotificationEntryListener mEntryListener;
Mady Mellorebdbbb92018-11-15 14:36:48 -080097
98 private NotificationTestHelper mNotificationTestHelper;
99 private ExpandableNotificationRow mRow;
100 private ExpandableNotificationRow mRow2;
Mady Mellore80930e2019-03-21 16:00:45 -0700101 private ExpandableNotificationRow mAutoExpandRow;
Mady Mellor3ed46202019-03-26 20:22:35 -0700102 private ExpandableNotificationRow mSuppressNotifRow;
Mady Mellorfc02cc32019-04-01 14:47:55 -0700103 private ExpandableNotificationRow mNonBubbleNotifRow;
Mady Mellorebdbbb92018-11-15 14:36:48 -0800104
Mady Mellorb4991e62019-01-10 15:14:51 -0800105 @Mock
106 private NotificationData mNotificationData;
Mady Melloracb12152019-01-29 15:24:48 -0800107 @Mock
108 private BubbleController.BubbleStateChangeListener mBubbleStateChangeListener;
109 @Mock
110 private BubbleController.BubbleExpandListener mBubbleExpandListener;
Mark Renouf6b2331c2019-03-21 13:40:08 -0400111 @Mock
Mark Renouf08bc42a2019-03-07 13:01:59 -0500112 private PendingIntent mDeleteIntent;
113
Mady Mellorcfd06c12019-02-13 14:32:12 -0800114 private BubbleData mBubbleData;
115
Mady Mellorebdbbb92018-11-15 14:36:48 -0800116 @Before
117 public void setUp() throws Exception {
118 MockitoAnnotations.initMocks(this);
Joshua Tsujib1a796b2019-01-16 15:43:12 -0800119 mStatusBarView = new FrameLayout(mContext);
Ned Burns01e38212019-01-03 16:32:52 -0500120 mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800121
122 // Bubbles get added to status bar window view
123 mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
124 mActivityManager, mDozeParameters);
125 mStatusBarWindowController.add(mStatusBarView, 120 /* height */);
126
127 // Need notifications for bubbles
128 mNotificationTestHelper = new NotificationTestHelper(mContext);
Mark Renouf08bc42a2019-03-07 13:01:59 -0500129 mRow = mNotificationTestHelper.createBubble(mDeleteIntent);
130 mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
Mady Mellorfc02cc32019-04-01 14:47:55 -0700131 mNonBubbleNotifRow = mNotificationTestHelper.createRow();
Mady Mellor3ed46202019-03-26 20:22:35 -0700132
133 // Some bubbles want to auto expand
134 Notification.BubbleMetadata autoExpandMetadata =
135 getBuilder().setAutoExpandBubble(true).build();
136 mAutoExpandRow = mNotificationTestHelper.createBubble(autoExpandMetadata,
137 FOREGROUND_TEST_PKG_NAME);
138
139 // Some bubbles want to suppress notifs
140 Notification.BubbleMetadata suppressNotifMetadata =
141 getBuilder().setSuppressInitialNotification(true).build();
142 mSuppressNotifRow = mNotificationTestHelper.createBubble(suppressNotifMetadata,
143 FOREGROUND_TEST_PKG_NAME);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800144
Ned Burns01e38212019-01-03 16:32:52 -0500145 // Return non-null notification data from the NEM
146 when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData);
Mady Mellorb4991e62019-01-10 15:14:51 -0800147 when(mNotificationData.getChannel(mRow.getEntry().key)).thenReturn(mRow.getEntry().channel);
Ned Burns01e38212019-01-03 16:32:52 -0500148
Mady Mellorcfd06c12019-02-13 14:32:12 -0800149 mBubbleData = new BubbleData();
150 mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController,
Lyn Hanf1c9b8b2019-03-14 16:49:48 -0700151 mBubbleData, mConfigurationController);
Mady Melloracb12152019-01-29 15:24:48 -0800152 mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
153 mBubbleController.setExpandListener(mBubbleExpandListener);
Ned Burns01e38212019-01-03 16:32:52 -0500154
155 // Get a reference to the BubbleController's entry listener
156 verify(mNotificationEntryManager, atLeastOnce())
157 .addNotificationEntryListener(mEntryListenerCaptor.capture());
158 mEntryListener = mEntryListenerCaptor.getValue();
Mady Mellorebdbbb92018-11-15 14:36:48 -0800159 }
160
161 @Test
Mady Mellorebdbbb92018-11-15 14:36:48 -0800162 public void testAddBubble() {
Mady Mellor3f2efdb2018-11-21 11:30:45 -0800163 mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800164 assertTrue(mBubbleController.hasBubbles());
Mady Melloracb12152019-01-29 15:24:48 -0800165
166 verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800167 }
168
169 @Test
170 public void testHasBubbles() {
171 assertFalse(mBubbleController.hasBubbles());
Mady Mellor3f2efdb2018-11-21 11:30:45 -0800172 mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800173 assertTrue(mBubbleController.hasBubbles());
174 }
175
176 @Test
177 public void testRemoveBubble() {
Mady Mellor3f2efdb2018-11-21 11:30:45 -0800178 mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800179 assertTrue(mBubbleController.hasBubbles());
180
Mady Melloracb12152019-01-29 15:24:48 -0800181 verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
182
Mark Renouf08bc42a2019-03-07 13:01:59 -0500183 mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_USER_GESTURE);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800184 assertFalse(mStatusBarWindowController.getBubblesShowing());
Ned Burns01e38212019-01-03 16:32:52 -0500185 assertTrue(mRow.getEntry().isBubbleDismissed());
186 verify(mNotificationEntryManager).updateNotifications();
Mady Melloracb12152019-01-29 15:24:48 -0800187 verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800188 }
189
190 @Test
191 public void testDismissStack() {
Mady Mellor3f2efdb2018-11-21 11:30:45 -0800192 mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
193 mBubbleController.updateBubble(mRow2.getEntry(), true /* updatePosition */);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800194 assertTrue(mBubbleController.hasBubbles());
195
Mark Renouf08bc42a2019-03-07 13:01:59 -0500196 mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800197 assertFalse(mStatusBarWindowController.getBubblesShowing());
Mady Mellor3f2efdb2018-11-21 11:30:45 -0800198 verify(mNotificationEntryManager).updateNotifications();
Mady Melloracb12152019-01-29 15:24:48 -0800199 assertTrue(mRow.getEntry().isBubbleDismissed());
200 assertTrue(mRow2.getEntry().isBubbleDismissed());
Mady Mellorebdbbb92018-11-15 14:36:48 -0800201 }
202
203 @Test
Mady Melloracb12152019-01-29 15:24:48 -0800204 public void testExpandCollapseStack() {
Mady Mellorebdbbb92018-11-15 14:36:48 -0800205 assertFalse(mBubbleController.isStackExpanded());
Mady Melloracb12152019-01-29 15:24:48 -0800206
207 // Mark it as a bubble and add it explicitly
208 mEntryListener.onPendingEntryAdded(mRow.getEntry());
Mady Mellor3f2efdb2018-11-21 11:30:45 -0800209 mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800210
Mady Melloracb12152019-01-29 15:24:48 -0800211 // We should have bubbles & their notifs should show in the shade
212 assertTrue(mBubbleController.hasBubbles());
213 assertTrue(mRow.getEntry().showInShadeWhenBubble());
Issei Suzukiac9fcb72019-02-04 17:45:57 +0100214 assertFalse(mStatusBarWindowController.getBubbleExpanded());
Mady Melloracb12152019-01-29 15:24:48 -0800215
216 // Expand the stack
Mady Mellorebdbbb92018-11-15 14:36:48 -0800217 BubbleStackView stackView = mBubbleController.getStackView();
Mady Mellor3f2efdb2018-11-21 11:30:45 -0800218 stackView.expandStack();
Mady Mellorebdbbb92018-11-15 14:36:48 -0800219 assertTrue(mBubbleController.isStackExpanded());
Mady Melloracb12152019-01-29 15:24:48 -0800220 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key);
Issei Suzukiac9fcb72019-02-04 17:45:57 +0100221 assertTrue(mStatusBarWindowController.getBubbleExpanded());
Mady Mellorebdbbb92018-11-15 14:36:48 -0800222
Mady Melloracb12152019-01-29 15:24:48 -0800223 // Make sure it's no longer in the shade
224 assertFalse(mRow.getEntry().showInShadeWhenBubble());
225
226 // Collapse
Mady Mellor3f2efdb2018-11-21 11:30:45 -0800227 stackView.collapseStack();
Mady Melloracb12152019-01-29 15:24:48 -0800228 verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800229 assertFalse(mBubbleController.isStackExpanded());
Issei Suzukiac9fcb72019-02-04 17:45:57 +0100230 assertFalse(mStatusBarWindowController.getBubbleExpanded());
Mady Mellorebdbbb92018-11-15 14:36:48 -0800231 }
232
233 @Test
Mady Melloracb12152019-01-29 15:24:48 -0800234 public void testCollapseAfterChangingExpandedBubble() {
235 // Mark it as a bubble and add it explicitly
236 mEntryListener.onPendingEntryAdded(mRow.getEntry());
237 mEntryListener.onPendingEntryAdded(mRow2.getEntry());
Mady Mellor3f2efdb2018-11-21 11:30:45 -0800238 mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
239 mBubbleController.updateBubble(mRow2.getEntry(), true /* updatePosition */);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800240
Mady Melloracb12152019-01-29 15:24:48 -0800241 // We should have bubbles & their notifs should show in the shade
242 assertTrue(mBubbleController.hasBubbles());
243 assertTrue(mRow.getEntry().showInShadeWhenBubble());
244 assertTrue(mRow2.getEntry().showInShadeWhenBubble());
245
246 // Expand
Mady Mellorebdbbb92018-11-15 14:36:48 -0800247 BubbleStackView stackView = mBubbleController.getStackView();
Mady Mellor3f2efdb2018-11-21 11:30:45 -0800248 stackView.expandStack();
Mady Mellorebdbbb92018-11-15 14:36:48 -0800249 assertTrue(mBubbleController.isStackExpanded());
Mady Melloracb12152019-01-29 15:24:48 -0800250 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800251
Mady Melloracb12152019-01-29 15:24:48 -0800252 // Last added is the one that is expanded
Mady Mellor3dff9e62019-02-05 18:12:53 -0800253 assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry());
Mady Melloracb12152019-01-29 15:24:48 -0800254 assertFalse(mRow2.getEntry().showInShadeWhenBubble());
255
256 // Switch which bubble is expanded
Mady Melloredd4ee12019-01-18 10:45:11 -0800257 stackView.setExpandedBubble(mRow.getEntry());
Mady Mellor3dff9e62019-02-05 18:12:53 -0800258 assertEquals(mRow.getEntry(), stackView.getExpandedBubbleView().getEntry());
Mady Melloracb12152019-01-29 15:24:48 -0800259 assertFalse(mRow.getEntry().showInShadeWhenBubble());
Mady Melloredd4ee12019-01-18 10:45:11 -0800260
Mady Melloracb12152019-01-29 15:24:48 -0800261 // collapse for previous bubble
262 verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key);
263 // expand for selected bubble
264 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key);
Mady Melloredd4ee12019-01-18 10:45:11 -0800265
Mady Melloracb12152019-01-29 15:24:48 -0800266 // Collapse
Mady Mellorebdbbb92018-11-15 14:36:48 -0800267 mBubbleController.collapseStack();
268 assertFalse(mBubbleController.isStackExpanded());
269 }
270
Ned Burns01e38212019-01-03 16:32:52 -0500271 @Test
Mady Melloracb12152019-01-29 15:24:48 -0800272 public void testExpansionRemovesShowInShade() {
273 // Mark it as a bubble and add it explicitly
274 mEntryListener.onPendingEntryAdded(mRow.getEntry());
275 mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
276
277 // We should have bubbles & their notifs should show in the shade
278 assertTrue(mBubbleController.hasBubbles());
279 assertTrue(mRow.getEntry().showInShadeWhenBubble());
280
281 // Expand
282 BubbleStackView stackView = mBubbleController.getStackView();
283 stackView.expandStack();
284 assertTrue(mBubbleController.isStackExpanded());
285 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key);
286
287 // No longer show shade in notif after expansion
288 assertFalse(mRow.getEntry().showInShadeWhenBubble());
289 }
290
291 @Test
292 public void testRemoveLastExpandedCollapses() {
293 // Mark it as a bubble and add it explicitly
294 mEntryListener.onPendingEntryAdded(mRow.getEntry());
295 mEntryListener.onPendingEntryAdded(mRow2.getEntry());
296 mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
297 mBubbleController.updateBubble(mRow2.getEntry(), true /* updatePosition */);
298 verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
299
300 // Expand
301 BubbleStackView stackView = mBubbleController.getStackView();
302 stackView.expandStack();
303
304 assertTrue(mBubbleController.isStackExpanded());
305 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key);
306
307 // Last added is the one that is expanded
Mady Mellor3dff9e62019-02-05 18:12:53 -0800308 assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry());
Mady Melloracb12152019-01-29 15:24:48 -0800309 assertFalse(mRow2.getEntry().showInShadeWhenBubble());
310
311 // Dismiss currently expanded
Mark Renouf08bc42a2019-03-07 13:01:59 -0500312 mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(),
313 BubbleController.DISMISS_USER_GESTURE);
Mady Melloracb12152019-01-29 15:24:48 -0800314 verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key);
315
316 // Make sure next bubble is selected
Mady Mellor3dff9e62019-02-05 18:12:53 -0800317 assertEquals(mRow.getEntry(), stackView.getExpandedBubbleView().getEntry());
Mady Melloracb12152019-01-29 15:24:48 -0800318 verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key);
319
320 // Dismiss that one
Mark Renouf08bc42a2019-03-07 13:01:59 -0500321 mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(),
322 BubbleController.DISMISS_USER_GESTURE);
Mady Melloracb12152019-01-29 15:24:48 -0800323
324 // Make sure state changes and collapse happens
325 verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key);
326 verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
327 assertFalse(mBubbleController.hasBubbles());
328 }
329
330 @Test
Mady Mellor3ed46202019-03-26 20:22:35 -0700331 public void testAutoExpand_FailsNotForeground() {
Mady Mellore80930e2019-03-21 16:00:45 -0700332 assertFalse(mBubbleController.isStackExpanded());
333
334 // Add the auto expand bubble
335 mEntryListener.onPendingEntryAdded(mAutoExpandRow.getEntry());
336 mBubbleController.updateBubble(mAutoExpandRow.getEntry(), true /* updatePosition */);
337
338 // Expansion shouldn't change
339 verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
340 mAutoExpandRow.getEntry().key);
341 assertFalse(mBubbleController.isStackExpanded());
342
343 // # of bubbles should change
344 verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
345 }
346
347 @Test
Mady Mellor3ed46202019-03-26 20:22:35 -0700348 public void testAutoExpand_SucceedsForeground() {
Mady Mellore80930e2019-03-21 16:00:45 -0700349 final CountDownLatch latch = new CountDownLatch(1);
350 BroadcastReceiver receiver = new BroadcastReceiver() {
351 @Override
352 public void onReceive(Context context, Intent intent) {
353 latch.countDown();
354 }
355 };
356 IntentFilter filter = new IntentFilter(BubblesTestActivity.BUBBLE_ACTIVITY_OPENED);
357 mContext.registerReceiver(receiver, filter);
358
359 assertFalse(mBubbleController.isStackExpanded());
360
361 // Make ourselves foreground
362 Intent i = new Intent(mContext, BubblesTestActivity.class);
363 i.setFlags(FLAG_ACTIVITY_NEW_TASK);
364 mContext.startActivity(i);
365
366 try {
367 latch.await(100, TimeUnit.MILLISECONDS);
368 } catch (InterruptedException e) {
369 e.printStackTrace();
370 }
371
372 // Add the auto expand bubble
373 mEntryListener.onPendingEntryAdded(mAutoExpandRow.getEntry());
374 mBubbleController.updateBubble(mAutoExpandRow.getEntry(), true /* updatePosition */);
375
376 // Expansion should change
377 verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
378 mAutoExpandRow.getEntry().key);
379 assertTrue(mBubbleController.isStackExpanded());
380
381 // # of bubbles should change
382 verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
383 mContext.unregisterReceiver(receiver);
384 }
385
Mady Mellor3ed46202019-03-26 20:22:35 -0700386 @Test
387 public void testSuppressNotif_FailsNotForeground() {
388 // Add the suppress notif bubble
389 mEntryListener.onPendingEntryAdded(mSuppressNotifRow.getEntry());
390 mBubbleController.updateBubble(mSuppressNotifRow.getEntry(), true /* updatePosition */);
391
Mady Mellorfc02cc32019-04-01 14:47:55 -0700392 // Should show in shade because we weren't forground
Mady Mellor3ed46202019-03-26 20:22:35 -0700393 assertTrue(mSuppressNotifRow.getEntry().showInShadeWhenBubble());
394
395 // # of bubbles should change
396 verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
397 }
398
399 @Test
400 public void testSuppressNotif_SucceedsForeground() {
401 final CountDownLatch latch = new CountDownLatch(1);
402 BroadcastReceiver receiver = new BroadcastReceiver() {
403 @Override
404 public void onReceive(Context context, Intent intent) {
405 latch.countDown();
406 }
407 };
408 IntentFilter filter = new IntentFilter(BubblesTestActivity.BUBBLE_ACTIVITY_OPENED);
409 mContext.registerReceiver(receiver, filter);
410
411 assertFalse(mBubbleController.isStackExpanded());
412
413 // Make ourselves foreground
414 Intent i = new Intent(mContext, BubblesTestActivity.class);
415 i.setFlags(FLAG_ACTIVITY_NEW_TASK);
416 mContext.startActivity(i);
417
418 try {
419 latch.await(100, TimeUnit.MILLISECONDS);
420 } catch (InterruptedException e) {
421 e.printStackTrace();
422 }
423
424 // Add the suppress notif bubble
425 mEntryListener.onPendingEntryAdded(mSuppressNotifRow.getEntry());
426 mBubbleController.updateBubble(mSuppressNotifRow.getEntry(), true /* updatePosition */);
427
Mady Mellorfc02cc32019-04-01 14:47:55 -0700428 // Should NOT show in shade because we were foreground
Mady Mellor3ed46202019-03-26 20:22:35 -0700429 assertFalse(mSuppressNotifRow.getEntry().showInShadeWhenBubble());
430
431 // # of bubbles should change
432 verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
433 mContext.unregisterReceiver(receiver);
434 }
Mady Mellore80930e2019-03-21 16:00:45 -0700435
436 @Test
Mark Renouffec45da2019-03-13 13:24:27 -0400437 public void testExpandStackAndSelectBubble_removedFirst() {
438 final String key = mRow.getEntry().key;
439
440 mEntryListener.onPendingEntryAdded(mRow.getEntry());
441 mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
442
Mark Renouffec45da2019-03-13 13:24:27 -0400443 // Simulate notification cancellation.
444 mEntryListener.onEntryRemoved(mRow.getEntry(), null /* notificationVisibility (unused) */,
445 false /* removedbyUser */);
446
447 mBubbleController.expandStackAndSelectBubble(key);
448 }
449
450 @Test
Mady Mellor3f2efdb2018-11-21 11:30:45 -0800451 public void testMarkNewNotificationAsShowInShade() {
452 mEntryListener.onPendingEntryAdded(mRow.getEntry());
453 assertTrue(mRow.getEntry().showInShadeWhenBubble());
454 }
455
Mark Renouf08bc42a2019-03-07 13:01:59 -0500456 @Test
Mady Mellorfc02cc32019-04-01 14:47:55 -0700457 public void testAddNotif_notBubble() {
458 mEntryListener.onPendingEntryAdded(mNonBubbleNotifRow.getEntry());
459 mEntryListener.onPreEntryUpdated(mNonBubbleNotifRow.getEntry());
460
461 verify(mBubbleStateChangeListener, never()).onHasBubblesChanged(anyBoolean());
462 assertThat(mBubbleController.hasBubbles()).isFalse();
463 }
464
465 @Test
Mark Renouf08bc42a2019-03-07 13:01:59 -0500466 public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
467 mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
468 mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_AGED);
469 verify(mDeleteIntent, never()).send();
470 }
471
472 @Test
473 public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
474 mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
475 mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_USER_GESTURE);
476 verify(mDeleteIntent, times(1)).send();
477 }
478
479 @Test
480 public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException {
481 mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
482 mBubbleController.updateBubble(mRow2.getEntry(), true /* updatePosition */);
483 mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
484 verify(mDeleteIntent, times(2)).send();
485 }
486
Mady Mellorebdbbb92018-11-15 14:36:48 -0800487 static class TestableBubbleController extends BubbleController {
Issei Suzukic0387542019-03-08 17:31:14 +0100488 // Let's assume surfaces can be synchronized immediately.
Mady Mellorebdbbb92018-11-15 14:36:48 -0800489 TestableBubbleController(Context context,
Lyn Hanf1c9b8b2019-03-14 16:49:48 -0700490 StatusBarWindowController statusBarWindowController, BubbleData data,
491 ConfigurationController configurationController) {
492 super(context, statusBarWindowController, data, Runnable::run, configurationController);
Mady Mellorebdbbb92018-11-15 14:36:48 -0800493 }
Mady Mellor9bad2242019-01-28 11:21:51 -0800494
495 @Override
Mady Mellorf6e3ac02019-01-29 10:37:52 -0800496 public boolean shouldAutoBubbleForFlags(Context c, NotificationEntry entry) {
Mady Mellor9bad2242019-01-28 11:21:51 -0800497 return entry.notification.getNotification().getBubbleMetadata() != null;
498 }
Mady Mellorebdbbb92018-11-15 14:36:48 -0800499 }
Mady Mellore80930e2019-03-21 16:00:45 -0700500
501 /**
502 * @return basic {@link android.app.Notification.BubbleMetadata.Builder}
503 */
504 private Notification.BubbleMetadata.Builder getBuilder() {
505 Intent target = new Intent(mContext, BubblesTestActivity.class);
506 PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target, 0);
507 return new Notification.BubbleMetadata.Builder()
508 .setIntent(bubbleIntent)
509 .setIcon(Icon.createWithResource(mContext, R.drawable.android));
510 }
Mady Mellorebdbbb92018-11-15 14:36:48 -0800511}