blob: 62700c0b3b4c7f8236d5c387000a5f844cc05a56 [file] [log] [blame]
Eliot Courtney2b4c3a02017-11-27 13:27:46 +09001/*
2 * Copyright (C) 2017 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.statusbar;
18
19import static junit.framework.Assert.assertTrue;
20
21import static org.junit.Assert.assertEquals;
Julia Reynoldsfc640012018-02-21 12:25:27 -050022import static org.mockito.ArgumentMatchers.any;
Jason Monk09f4d372018-12-20 15:30:54 -050023import static org.mockito.Mockito.mock;
Julia Reynoldsfc640012018-02-21 12:25:27 -050024import static org.mockito.Mockito.spy;
25import static org.mockito.Mockito.times;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090026import static org.mockito.Mockito.verify;
27import static org.mockito.Mockito.when;
28
29import android.support.test.filters.SmallTest;
30import android.testing.AndroidTestingRunner;
31import android.testing.TestableLooper;
32import android.view.View;
33import android.view.ViewGroup;
34import android.widget.LinearLayout;
35
Jason Monk297c04e2018-08-23 17:16:59 -040036import com.android.systemui.Dependency;
37import com.android.systemui.InitController;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090038import com.android.systemui.SysuiTestCase;
39import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
Rohan Shah20790b82018-07-02 17:21:04 -070040import com.android.systemui.statusbar.notification.NotificationEntryManager;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090041import com.android.systemui.statusbar.notification.VisualStabilityManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050042import com.android.systemui.statusbar.notification.collection.NotificationData;
43import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Rohan Shah20790b82018-07-02 17:21:04 -070044import com.android.systemui.statusbar.notification.logging.NotificationLogger;
45import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
46import com.android.systemui.statusbar.notification.row.ExpandableView;
47import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090048import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk297c04e2018-08-23 17:16:59 -040049import com.android.systemui.statusbar.phone.ShadeController;
Jason Monka716bac2018-12-05 15:48:21 -050050import com.android.systemui.util.Assert;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090051
52import com.google.android.collect.Lists;
53
54import org.junit.Before;
55import org.junit.Test;
56import org.junit.runner.RunWith;
57import org.mockito.Mock;
58import org.mockito.MockitoAnnotations;
59import org.mockito.Spy;
60
61import java.util.List;
62
63@SmallTest
64@RunWith(AndroidTestingRunner.class)
Jason Monka716bac2018-12-05 15:48:21 -050065@TestableLooper.RunWithLooper
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090066public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
67 @Mock private NotificationPresenter mPresenter;
Eliot Courtney8f56b0e2017-12-14 18:54:28 +090068 @Mock private NotificationData mNotificationData;
69 @Spy private FakeListContainer mListContainer = new FakeListContainer();
70
71 // Dependency mocks:
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090072 @Mock private NotificationEntryManager mEntryManager;
73 @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
74 @Mock private NotificationGroupManager mGroupManager;
75 @Mock private VisualStabilityManager mVisualStabilityManager;
Jason Monk297c04e2018-08-23 17:16:59 -040076 @Mock private ShadeController mShadeController;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090077
78 private NotificationViewHierarchyManager mViewHierarchyManager;
Ned Burns01e38212019-01-03 16:32:52 -050079 private NotificationTestHelper mHelper;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090080
81 @Before
82 public void setUp() {
83 MockitoAnnotations.initMocks(this);
Jason Monka716bac2018-12-05 15:48:21 -050084 Assert.sMainLooper = TestableLooper.get(this).getLooper();
Eliot Courtney8f56b0e2017-12-14 18:54:28 +090085 mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
86 mDependency.injectTestDependency(NotificationLockscreenUserManager.class,
87 mLockscreenUserManager);
88 mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager);
89 mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
Jason Monk297c04e2018-08-23 17:16:59 -040090 mDependency.injectTestDependency(ShadeController.class, mShadeController);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090091
Ned Burns01e38212019-01-03 16:32:52 -050092 mHelper = new NotificationTestHelper(mContext);
93
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090094 when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
95
Jason Monk09f4d372018-12-20 15:30:54 -050096 mViewHierarchyManager = new NotificationViewHierarchyManager(mContext,
97 mLockscreenUserManager, mGroupManager, mVisualStabilityManager,
Beverly8fdb5332019-02-04 14:29:49 -050098 mock(StatusBarStateControllerImpl.class), mEntryManager,
Jason Monk09f4d372018-12-20 15:30:54 -050099 () -> mShadeController);
Jason Monk297c04e2018-08-23 17:16:59 -0400100 Dependency.get(InitController.class).executePostInitTasks();
101 mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900102 }
103
Ned Burnsf81c4c42019-01-07 14:10:43 -0500104 private NotificationEntry createEntry() throws Exception {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900105 ExpandableNotificationRow row = mHelper.createRow();
Ned Burnsf81c4c42019-01-07 14:10:43 -0500106 NotificationEntry entry = new NotificationEntry(row.getStatusBarNotification());
Evan Laird94492852018-10-25 13:43:01 -0400107 entry.setRow(row);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900108 return entry;
109 }
110
111 @Test
112 public void testNotificationsBecomingBundled() throws Exception {
113 // Tests 3 top level notifications becoming a single bundled notification with |entry0| as
114 // the summary.
Ned Burnsf81c4c42019-01-07 14:10:43 -0500115 NotificationEntry entry0 = createEntry();
116 NotificationEntry entry1 = createEntry();
117 NotificationEntry entry2 = createEntry();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900118
119 // Set up the prior state to look like three top level notifications.
Evan Laird94492852018-10-25 13:43:01 -0400120 mListContainer.addContainerView(entry0.getRow());
121 mListContainer.addContainerView(entry1.getRow());
122 mListContainer.addContainerView(entry2.getRow());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900123 when(mNotificationData.getActiveNotifications()).thenReturn(
124 Lists.newArrayList(entry0, entry1, entry2));
125
126 // Set up group manager to report that they should be bundled now.
127 when(mGroupManager.isChildInGroupWithSummary(entry0.notification)).thenReturn(false);
128 when(mGroupManager.isChildInGroupWithSummary(entry1.notification)).thenReturn(true);
129 when(mGroupManager.isChildInGroupWithSummary(entry2.notification)).thenReturn(true);
Evan Laird94492852018-10-25 13:43:01 -0400130 when(mGroupManager.getGroupSummary(entry1.notification)).thenReturn(entry0);
131 when(mGroupManager.getGroupSummary(entry2.notification)).thenReturn(entry0);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900132
133 // Run updateNotifications - the view hierarchy should be reorganized.
134 mViewHierarchyManager.updateNotificationViews();
135
Evan Laird94492852018-10-25 13:43:01 -0400136 verify(mListContainer).notifyGroupChildAdded(entry1.getRow());
137 verify(mListContainer).notifyGroupChildAdded(entry2.getRow());
138 assertTrue(Lists.newArrayList(entry0.getRow()).equals(mListContainer.mRows));
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900139 }
140
141 @Test
142 public void testNotificationsBecomingUnbundled() throws Exception {
143 // Tests a bundled notification becoming three top level notifications.
Ned Burnsf81c4c42019-01-07 14:10:43 -0500144 NotificationEntry entry0 = createEntry();
145 NotificationEntry entry1 = createEntry();
146 NotificationEntry entry2 = createEntry();
Evan Laird94492852018-10-25 13:43:01 -0400147 entry0.getRow().addChildNotification(entry1.getRow());
148 entry0.getRow().addChildNotification(entry2.getRow());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900149
150 // Set up the prior state to look like one top level notification.
Evan Laird94492852018-10-25 13:43:01 -0400151 mListContainer.addContainerView(entry0.getRow());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900152 when(mNotificationData.getActiveNotifications()).thenReturn(
153 Lists.newArrayList(entry0, entry1, entry2));
154
155 // Set up group manager to report that they should not be bundled now.
156 when(mGroupManager.isChildInGroupWithSummary(entry0.notification)).thenReturn(false);
157 when(mGroupManager.isChildInGroupWithSummary(entry1.notification)).thenReturn(false);
158 when(mGroupManager.isChildInGroupWithSummary(entry2.notification)).thenReturn(false);
159
160 // Run updateNotifications - the view hierarchy should be reorganized.
161 mViewHierarchyManager.updateNotificationViews();
162
163 verify(mListContainer).notifyGroupChildRemoved(
Evan Laird94492852018-10-25 13:43:01 -0400164 entry1.getRow(), entry0.getRow().getChildrenContainer());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900165 verify(mListContainer).notifyGroupChildRemoved(
Evan Laird94492852018-10-25 13:43:01 -0400166 entry2.getRow(), entry0.getRow().getChildrenContainer());
167 assertTrue(
168 Lists.newArrayList(entry0.getRow(), entry1.getRow(), entry2.getRow())
169 .equals(mListContainer.mRows));
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900170 }
171
172 @Test
173 public void testNotificationsBecomingSuppressed() throws Exception {
174 // Tests two top level notifications becoming a suppressed summary and a child.
Ned Burnsf81c4c42019-01-07 14:10:43 -0500175 NotificationEntry entry0 = createEntry();
176 NotificationEntry entry1 = createEntry();
Evan Laird94492852018-10-25 13:43:01 -0400177 entry0.getRow().addChildNotification(entry1.getRow());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900178
179 // Set up the prior state to look like a top level notification.
Evan Laird94492852018-10-25 13:43:01 -0400180 mListContainer.addContainerView(entry0.getRow());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900181 when(mNotificationData.getActiveNotifications()).thenReturn(
182 Lists.newArrayList(entry0, entry1));
183
184 // Set up group manager to report a suppressed summary now.
185 when(mGroupManager.isChildInGroupWithSummary(entry0.notification)).thenReturn(false);
186 when(mGroupManager.isChildInGroupWithSummary(entry1.notification)).thenReturn(false);
187 when(mGroupManager.isSummaryOfSuppressedGroup(entry0.notification)).thenReturn(true);
188
189 // Run updateNotifications - the view hierarchy should be reorganized.
190 mViewHierarchyManager.updateNotificationViews();
191
192 verify(mListContainer).notifyGroupChildRemoved(
Evan Laird94492852018-10-25 13:43:01 -0400193 entry1.getRow(), entry0.getRow().getChildrenContainer());
194 assertTrue(Lists.newArrayList(entry0.getRow(), entry1.getRow()).equals(mListContainer.mRows));
195 assertEquals(View.GONE, entry0.getRow().getVisibility());
196 assertEquals(View.VISIBLE, entry1.getRow().getVisibility());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900197 }
198
Julia Reynoldsfc640012018-02-21 12:25:27 -0500199 @Test
200 public void testUpdateNotificationViews_appOps() throws Exception {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500201 NotificationEntry entry0 = createEntry();
Evan Laird94492852018-10-25 13:43:01 -0400202 entry0.setRow(spy(entry0.getRow()));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500203 when(mNotificationData.getActiveNotifications()).thenReturn(
204 Lists.newArrayList(entry0));
Evan Laird94492852018-10-25 13:43:01 -0400205 mListContainer.addContainerView(entry0.getRow());
Julia Reynoldsfc640012018-02-21 12:25:27 -0500206
207 mViewHierarchyManager.updateNotificationViews();
208
Evan Laird94492852018-10-25 13:43:01 -0400209 verify(entry0.getRow(), times(1)).showAppOpsIcons(any());
Julia Reynoldsfc640012018-02-21 12:25:27 -0500210 }
211
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900212 private class FakeListContainer implements NotificationListContainer {
213 final LinearLayout mLayout = new LinearLayout(mContext);
214 final List<View> mRows = Lists.newArrayList();
215
216 @Override
217 public void setChildTransferInProgress(boolean childTransferInProgress) {}
218
219 @Override
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500220 public void changeViewPosition(ExpandableView child, int newIndex) {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900221 mRows.remove(child);
222 mRows.add(newIndex, child);
223 }
224
225 @Override
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500226 public void notifyGroupChildAdded(ExpandableView row) {}
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900227
228 @Override
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500229 public void notifyGroupChildRemoved(ExpandableView row, ViewGroup childrenContainer) {}
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900230
231 @Override
Dave Mankoffa4d195d2018-11-16 13:33:27 -0500232 public void generateAddAnimation(ExpandableView child, boolean fromMoreCard) {}
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900233
234 @Override
235 public void generateChildOrderChangedEvent() {}
236
237 @Override
Aaron Heuckrothcd944dc2018-10-01 16:31:08 -0400238 public void onReset(ExpandableView view) {}
239
240 @Override
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900241 public int getContainerChildCount() {
242 return mRows.size();
243 }
244
245 @Override
246 public View getContainerChildAt(int i) {
247 return mRows.get(i);
248 }
249
250 @Override
251 public void removeContainerView(View v) {
252 mLayout.removeView(v);
253 mRows.remove(v);
254 }
255
256 @Override
257 public void addContainerView(View v) {
258 mLayout.addView(v);
259 mRows.add(v);
260 }
261
262 @Override
263 public void setMaxDisplayedNotifications(int maxNotifications) {}
264
265 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500266 public ViewGroup getViewParentForNotification(NotificationEntry entry) {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900267 return null;
268 }
269
270 @Override
271 public void onHeightChanged(ExpandableView view, boolean animate) {}
272
273 @Override
274 public void resetExposedMenuView(boolean animate, boolean force) {}
275
276 @Override
277 public NotificationSwipeActionHelper getSwipeActionHelper() {
278 return null;
279 }
280
281 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500282 public void cleanUpViewStateForEntry(NotificationEntry entry) { }
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900283
284 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500285 public boolean isInVisibleLocation(NotificationEntry entry) {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900286 return true;
287 }
288
289 @Override
290 public void setChildLocationsChangedListener(
291 NotificationLogger.OnChildLocationsChangedListener listener) {}
292
293 @Override
294 public boolean hasPulsingNotifications() {
295 return false;
296 }
Evan Laird94492852018-10-25 13:43:01 -0400297
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900298 }
299}