blob: 06bad80d6f8787d4e80302b0fea14e30b019ba33 [file] [log] [blame]
Eliot Courtney3985ad52017-11-17 16:51:52 +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
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -050014 * limitations under the License.
Eliot Courtney3985ad52017-11-17 16:51:52 +090015 */
16
Rohan Shah20790b82018-07-02 17:21:04 -070017package com.android.systemui.statusbar.notification.logging;
Eliot Courtney3985ad52017-11-17 16:51:52 +090018
Steve Elliott981cca12020-05-14 11:59:49 -040019import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_ALERTING;
Will Brockman492b3812020-03-03 16:29:36 +000020
Chris Wren2e89e8d2018-05-17 18:55:42 -040021import static org.junit.Assert.assertArrayEquals;
Will Brockman492b3812020-03-03 16:29:36 +000022import static org.junit.Assert.assertEquals;
Will Brockmand93cb572020-05-08 17:26:39 -040023import static org.junit.Assert.assertFalse;
24import static org.junit.Assert.assertTrue;
Eliot Courtney3985ad52017-11-17 16:51:52 +090025import static org.mockito.ArgumentMatchers.any;
Chris Wren2e89e8d2018-05-17 18:55:42 -040026import static org.mockito.Mockito.doAnswer;
Jason Monkd97204c2018-12-21 15:49:04 -050027import static org.mockito.Mockito.mock;
Eliot Courtney3985ad52017-11-17 16:51:52 +090028import static org.mockito.Mockito.never;
29import static org.mockito.Mockito.times;
30import static org.mockito.Mockito.verify;
31import static org.mockito.Mockito.when;
32
33import android.app.Notification;
34import android.os.Handler;
35import android.os.Looper;
36import android.os.UserHandle;
Eliot Courtney3985ad52017-11-17 16:51:52 +090037import android.testing.AndroidTestingRunner;
38import android.testing.TestableLooper;
39
Brett Chabot84151d92019-02-27 15:37:59 -080040import androidx.test.filters.SmallTest;
41
Will Brockman492b3812020-03-03 16:29:36 +000042import com.android.internal.logging.InstanceId;
Eliot Courtney3985ad52017-11-17 16:51:52 +090043import com.android.internal.statusbar.IStatusBarService;
44import com.android.internal.statusbar.NotificationVisibility;
45import com.android.systemui.SysuiTestCase;
Rohan Shah20790b82018-07-02 17:21:04 -070046import com.android.systemui.statusbar.NotificationListener;
Will Brockmand93cb572020-05-08 17:26:39 -040047import com.android.systemui.statusbar.StatusBarState;
Beverly8fdb5332019-02-04 14:29:49 -050048import com.android.systemui.statusbar.StatusBarStateControllerImpl;
Ned Burns761af0d2019-01-03 13:51:29 -050049import com.android.systemui.statusbar.notification.NotificationEntryListener;
Jason Monka716bac2018-12-05 15:48:21 -050050import com.android.systemui.statusbar.notification.NotificationEntryManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050051import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Beverly79c89ec2019-12-13 10:33:01 -050052import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
Will Brockman492b3812020-03-03 16:29:36 +000053import com.android.systemui.statusbar.notification.logging.nano.Notifications;
Rohan Shah20790b82018-07-02 17:21:04 -070054import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
55import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -050056import com.android.systemui.util.concurrency.FakeExecutor;
57import com.android.systemui.util.time.FakeSystemClock;
Jason Monka716bac2018-12-05 15:48:21 -050058
Eliot Courtney3985ad52017-11-17 16:51:52 +090059import com.google.android.collect.Lists;
60
61import org.junit.Before;
62import org.junit.Test;
63import org.junit.runner.RunWith;
Ned Burns761af0d2019-01-03 13:51:29 -050064import org.mockito.ArgumentCaptor;
65import org.mockito.Captor;
Eliot Courtney3985ad52017-11-17 16:51:52 +090066import org.mockito.Mock;
67import org.mockito.Mockito;
68import org.mockito.MockitoAnnotations;
Chris Wren2e89e8d2018-05-17 18:55:42 -040069
70import java.util.concurrent.ConcurrentLinkedQueue;
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -050071import java.util.concurrent.Executor;
Eliot Courtney3985ad52017-11-17 16:51:52 +090072
73@SmallTest
74@RunWith(AndroidTestingRunner.class)
Jason Monka716bac2018-12-05 15:48:21 -050075@TestableLooper.RunWithLooper
Eliot Courtney3985ad52017-11-17 16:51:52 +090076public class NotificationLoggerTest extends SysuiTestCase {
77 private static final String TEST_PACKAGE_NAME = "test";
78 private static final int TEST_UID = 0;
79
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090080 @Mock private NotificationListContainer mListContainer;
Eliot Courtney3985ad52017-11-17 16:51:52 +090081 @Mock private IStatusBarService mBarService;
Eliot Courtney3985ad52017-11-17 16:51:52 +090082 @Mock private ExpandableNotificationRow mRow;
Tony Mak202f25d2019-01-07 14:40:39 +000083 @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
Eliot Courtney3985ad52017-11-17 16:51:52 +090084
Eliot Courtney8f56b0e2017-12-14 18:54:28 +090085 // Dependency mocks:
86 @Mock private NotificationEntryManager mEntryManager;
87 @Mock private NotificationListener mListener;
Ned Burns761af0d2019-01-03 13:51:29 -050088 @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
Eliot Courtney8f56b0e2017-12-14 18:54:28 +090089
Ned Burnsf81c4c42019-01-07 14:10:43 -050090 private NotificationEntry mEntry;
Eliot Courtney3985ad52017-11-17 16:51:52 +090091 private TestableNotificationLogger mLogger;
Chris Wren2e89e8d2018-05-17 18:55:42 -040092 private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>();
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -050093 private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
Will Brockman492b3812020-03-03 16:29:36 +000094 private NotificationPanelLoggerFake mNotificationPanelLoggerFake =
95 new NotificationPanelLoggerFake();
Eliot Courtney3985ad52017-11-17 16:51:52 +090096
97 @Before
Gus Prevasca1b6f72018-12-28 10:53:11 -050098 public void setUp() {
Eliot Courtney3985ad52017-11-17 16:51:52 +090099 MockitoAnnotations.initMocks(this);
Eliot Courtney8f56b0e2017-12-14 18:54:28 +0900100 mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
101 mDependency.injectTestDependency(NotificationListener.class, mListener);
Eliot Courtney3985ad52017-11-17 16:51:52 +0900102
Ned Burns636c3792019-09-11 16:59:07 -0400103 mEntry = new NotificationEntryBuilder()
104 .setPkg(TEST_PACKAGE_NAME)
105 .setOpPkg(TEST_PACKAGE_NAME)
106 .setUid(TEST_UID)
107 .setNotification(new Notification())
108 .setUser(UserHandle.CURRENT)
Will Brockman492b3812020-03-03 16:29:36 +0000109 .setInstanceId(InstanceId.fakeInstanceId(1))
Ned Burns636c3792019-09-11 16:59:07 -0400110 .build();
Evan Laird94492852018-10-25 13:43:01 -0400111 mEntry.setRow(mRow);
Eliot Courtney3985ad52017-11-17 16:51:52 +0900112
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500113 mLogger = new TestableNotificationLogger(mListener, mUiBgExecutor,
Beverly8fdb5332019-02-04 14:29:49 -0500114 mEntryManager, mock(StatusBarStateControllerImpl.class), mBarService,
Tony Mak202f25d2019-01-07 14:40:39 +0000115 mExpansionStateLogger);
Jason Monk297c04e2018-08-23 17:16:59 -0400116 mLogger.setUpWithContainer(mListContainer);
Ned Burns761af0d2019-01-03 13:51:29 -0500117 verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
Eliot Courtney3985ad52017-11-17 16:51:52 +0900118 }
119
120 @Test
121 public void testOnChildLocationsChangedReportsVisibilityChanged() throws Exception {
Chris Wren2e89e8d2018-05-17 18:55:42 -0400122 NotificationVisibility[] newlyVisibleKeys = {
Ned Burns00b4b2d2019-10-17 22:09:27 -0400123 NotificationVisibility.obtain(mEntry.getKey(), 0, 1, true)
Chris Wren2e89e8d2018-05-17 18:55:42 -0400124 };
125 NotificationVisibility[] noLongerVisibleKeys = {};
Gus Prevasca1b6f72018-12-28 10:53:11 -0500126 doAnswer(invocation -> {
Chris Wren2e89e8d2018-05-17 18:55:42 -0400127 try {
128 assertArrayEquals(newlyVisibleKeys,
129 (NotificationVisibility[]) invocation.getArguments()[0]);
130 assertArrayEquals(noLongerVisibleKeys,
131 (NotificationVisibility[]) invocation.getArguments()[1]);
132 } catch (AssertionError error) {
133 mErrorQueue.offer(error);
134 }
135 return null;
136 }
137 ).when(mBarService).onNotificationVisibilityChanged(any(NotificationVisibility[].class),
138 any(NotificationVisibility[].class));
139
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900140 when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
Evan Laird181de622019-10-24 09:53:02 -0400141 when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900142 mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
Jason Monk6dceace2018-05-15 20:24:07 -0400143 TestableLooper.get(this).processAllMessages();
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500144 mUiBgExecutor.runAllReady();
Eliot Courtney3985ad52017-11-17 16:51:52 +0900145
Chris Wren2e89e8d2018-05-17 18:55:42 -0400146 if(!mErrorQueue.isEmpty()) {
147 throw mErrorQueue.poll();
148 }
Eliot Courtney3985ad52017-11-17 16:51:52 +0900149
150 // |mEntry| won't change visibility, so it shouldn't be reported again:
151 Mockito.reset(mBarService);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900152 mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
Jason Monk6dceace2018-05-15 20:24:07 -0400153 TestableLooper.get(this).processAllMessages();
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500154 mUiBgExecutor.runAllReady();
Eliot Courtney3985ad52017-11-17 16:51:52 +0900155
156 verify(mBarService, never()).onNotificationVisibilityChanged(any(), any());
157 }
158
159 @Test
160 public void testStoppingNotificationLoggingReportsCurrentNotifications()
161 throws Exception {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900162 when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
Evan Laird181de622019-10-24 09:53:02 -0400163 when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900164 mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
Jason Monk6dceace2018-05-15 20:24:07 -0400165 TestableLooper.get(this).processAllMessages();
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500166 mUiBgExecutor.runAllReady();
Eliot Courtney3985ad52017-11-17 16:51:52 +0900167 Mockito.reset(mBarService);
168
Will Brockmand93cb572020-05-08 17:26:39 -0400169 setStateAsleep();
170 mLogger.onDozingChanged(false); // Wake to lockscreen
171 mLogger.onDozingChanged(true); // And go back to sleep, turning off logging
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500172 mUiBgExecutor.runAllReady();
Eliot Courtney3985ad52017-11-17 16:51:52 +0900173 // The visibility objects are recycled by NotificationLogger, so we can't use specific
174 // matchers here.
175 verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any());
176 }
177
Will Brockmand93cb572020-05-08 17:26:39 -0400178 private void setStateAsleep() {
179 mLogger.onPanelExpandedChanged(true);
180 mLogger.onDozingChanged(true);
181 mLogger.onStateChanged(StatusBarState.KEYGUARD);
182 }
183
184 private void setStateAwake() {
185 mLogger.onPanelExpandedChanged(false);
186 mLogger.onDozingChanged(false);
187 mLogger.onStateChanged(StatusBarState.SHADE);
188 }
189
Will Brockman492b3812020-03-03 16:29:36 +0000190 @Test
Will Brockmand93cb572020-05-08 17:26:39 -0400191 public void testLogPanelShownOnWake() {
Will Brockman492b3812020-03-03 16:29:36 +0000192 when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
Will Brockmand93cb572020-05-08 17:26:39 -0400193 setStateAsleep();
194 mLogger.onDozingChanged(false); // Wake to lockscreen
Will Brockman492b3812020-03-03 16:29:36 +0000195 assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
Will Brockmand93cb572020-05-08 17:26:39 -0400196 assertTrue(mNotificationPanelLoggerFake.get(0).isLockscreen);
Will Brockman492b3812020-03-03 16:29:36 +0000197 assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
198 Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
199 assertEquals(TEST_PACKAGE_NAME, n.packageName);
200 assertEquals(TEST_UID, n.uid);
201 assertEquals(1, n.instanceId);
Will Brockmand93cb572020-05-08 17:26:39 -0400202 assertFalse(n.isGroupSummary);
Will Brockman492b3812020-03-03 16:29:36 +0000203 assertEquals(1 + BUCKET_ALERTING, n.section);
204 }
205
206 @Test
Will Brockmand93cb572020-05-08 17:26:39 -0400207 public void testLogPanelShownOnShadePull() {
208 when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
209 setStateAwake();
210 // Now expand panel
211 mLogger.onPanelExpandedChanged(true);
212 assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
213 assertFalse(mNotificationPanelLoggerFake.get(0).isLockscreen);
214 assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
215 Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
216 assertEquals(TEST_PACKAGE_NAME, n.packageName);
217 assertEquals(TEST_UID, n.uid);
218 assertEquals(1, n.instanceId);
219 assertFalse(n.isGroupSummary);
220 assertEquals(1 + BUCKET_ALERTING, n.section);
221 }
222
223
224 @Test
Will Brockman492b3812020-03-03 16:29:36 +0000225 public void testLogPanelShownHandlesNullInstanceIds() {
226 // Construct a NotificationEntry like mEntry, but with a null instance id.
227 NotificationEntry entry = new NotificationEntryBuilder()
228 .setPkg(TEST_PACKAGE_NAME)
229 .setOpPkg(TEST_PACKAGE_NAME)
230 .setUid(TEST_UID)
231 .setNotification(new Notification())
232 .setUser(UserHandle.CURRENT)
233 .build();
234 entry.setRow(mRow);
235
236 when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(entry));
Will Brockmand93cb572020-05-08 17:26:39 -0400237 setStateAsleep();
238 mLogger.onDozingChanged(false); // Wake to lockscreen
Will Brockman492b3812020-03-03 16:29:36 +0000239 assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
240 assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
241 Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
242 assertEquals(0, n.instanceId);
243 }
244
Eliot Courtney3985ad52017-11-17 16:51:52 +0900245 private class TestableNotificationLogger extends NotificationLogger {
246
Gus Prevasca1b6f72018-12-28 10:53:11 -0500247 TestableNotificationLogger(NotificationListener notificationListener,
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500248 Executor uiBgExecutor,
Jason Monkd97204c2018-12-21 15:49:04 -0500249 NotificationEntryManager entryManager,
Beverly8fdb5332019-02-04 14:29:49 -0500250 StatusBarStateControllerImpl statusBarStateController,
Tony Mak202f25d2019-01-07 14:40:39 +0000251 IStatusBarService barService,
252 ExpansionStateLogger expansionStateLogger) {
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500253 super(notificationListener, uiBgExecutor, entryManager, statusBarStateController,
Will Brockman492b3812020-03-03 16:29:36 +0000254 expansionStateLogger, mNotificationPanelLoggerFake);
Eliot Courtney3985ad52017-11-17 16:51:52 +0900255 mBarService = barService;
Jason Monk6dceace2018-05-15 20:24:07 -0400256 // Make this on the current thread so we can wait for it during tests.
257 mHandler = Handler.createAsync(Looper.myLooper());
Eliot Courtney3985ad52017-11-17 16:51:52 +0900258 }
259
Gus Prevasca1b6f72018-12-28 10:53:11 -0500260 OnChildLocationsChangedListener
Eliot Courtney3985ad52017-11-17 16:51:52 +0900261 getChildLocationsChangedListenerForTest() {
262 return mNotificationLocationsChangedListener;
263 }
Eliot Courtney3985ad52017-11-17 16:51:52 +0900264 }
265}