blob: c979dc637fde8973ffbd251d059948a9cb99cfb2 [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
Chris Wren2e89e8d2018-05-17 18:55:42 -040019import static org.junit.Assert.assertArrayEquals;
Will Brockman492b3812020-03-03 16:29:36 +000020import static org.junit.Assert.assertEquals;
Will Brockmand93cb572020-05-08 17:26:39 -040021import static org.junit.Assert.assertFalse;
22import static org.junit.Assert.assertTrue;
Eliot Courtney3985ad52017-11-17 16:51:52 +090023import static org.mockito.ArgumentMatchers.any;
Chris Wren2e89e8d2018-05-17 18:55:42 -040024import static org.mockito.Mockito.doAnswer;
Jason Monkd97204c2018-12-21 15:49:04 -050025import static org.mockito.Mockito.mock;
Eliot Courtney3985ad52017-11-17 16:51:52 +090026import static org.mockito.Mockito.never;
27import static org.mockito.Mockito.times;
28import static org.mockito.Mockito.verify;
29import static org.mockito.Mockito.when;
30
31import android.app.Notification;
32import android.os.Handler;
33import android.os.Looper;
34import android.os.UserHandle;
Eliot Courtney3985ad52017-11-17 16:51:52 +090035import android.testing.AndroidTestingRunner;
36import android.testing.TestableLooper;
37
Brett Chabot84151d92019-02-27 15:37:59 -080038import androidx.test.filters.SmallTest;
39
Will Brockman492b3812020-03-03 16:29:36 +000040import com.android.internal.logging.InstanceId;
Eliot Courtney3985ad52017-11-17 16:51:52 +090041import com.android.internal.statusbar.IStatusBarService;
42import com.android.internal.statusbar.NotificationVisibility;
43import com.android.systemui.SysuiTestCase;
Rohan Shah20790b82018-07-02 17:21:04 -070044import com.android.systemui.statusbar.NotificationListener;
Will Brockmand93cb572020-05-08 17:26:39 -040045import com.android.systemui.statusbar.StatusBarState;
Beverly8fdb5332019-02-04 14:29:49 -050046import com.android.systemui.statusbar.StatusBarStateControllerImpl;
Ned Burns761af0d2019-01-03 13:51:29 -050047import com.android.systemui.statusbar.notification.NotificationEntryListener;
Jason Monka716bac2018-12-05 15:48:21 -050048import com.android.systemui.statusbar.notification.NotificationEntryManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050049import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Beverly79c89ec2019-12-13 10:33:01 -050050import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
Will Brockman492b3812020-03-03 16:29:36 +000051import com.android.systemui.statusbar.notification.logging.nano.Notifications;
Rohan Shah20790b82018-07-02 17:21:04 -070052import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
53import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -050054import com.android.systemui.util.concurrency.FakeExecutor;
55import com.android.systemui.util.time.FakeSystemClock;
Jason Monka716bac2018-12-05 15:48:21 -050056
Eliot Courtney3985ad52017-11-17 16:51:52 +090057import com.google.android.collect.Lists;
58
59import org.junit.Before;
60import org.junit.Test;
61import org.junit.runner.RunWith;
Ned Burns761af0d2019-01-03 13:51:29 -050062import org.mockito.ArgumentCaptor;
63import org.mockito.Captor;
Eliot Courtney3985ad52017-11-17 16:51:52 +090064import org.mockito.Mock;
65import org.mockito.Mockito;
66import org.mockito.MockitoAnnotations;
Chris Wren2e89e8d2018-05-17 18:55:42 -040067
68import java.util.concurrent.ConcurrentLinkedQueue;
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -050069import java.util.concurrent.Executor;
Eliot Courtney3985ad52017-11-17 16:51:52 +090070
71@SmallTest
72@RunWith(AndroidTestingRunner.class)
Jason Monka716bac2018-12-05 15:48:21 -050073@TestableLooper.RunWithLooper
Eliot Courtney3985ad52017-11-17 16:51:52 +090074public class NotificationLoggerTest extends SysuiTestCase {
75 private static final String TEST_PACKAGE_NAME = "test";
76 private static final int TEST_UID = 0;
77
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090078 @Mock private NotificationListContainer mListContainer;
Eliot Courtney3985ad52017-11-17 16:51:52 +090079 @Mock private IStatusBarService mBarService;
Eliot Courtney3985ad52017-11-17 16:51:52 +090080 @Mock private ExpandableNotificationRow mRow;
Tony Mak202f25d2019-01-07 14:40:39 +000081 @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
Eliot Courtney3985ad52017-11-17 16:51:52 +090082
Eliot Courtney8f56b0e2017-12-14 18:54:28 +090083 // Dependency mocks:
84 @Mock private NotificationEntryManager mEntryManager;
85 @Mock private NotificationListener mListener;
Ned Burns761af0d2019-01-03 13:51:29 -050086 @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
Eliot Courtney8f56b0e2017-12-14 18:54:28 +090087
Ned Burnsf81c4c42019-01-07 14:10:43 -050088 private NotificationEntry mEntry;
Eliot Courtney3985ad52017-11-17 16:51:52 +090089 private TestableNotificationLogger mLogger;
Chris Wren2e89e8d2018-05-17 18:55:42 -040090 private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>();
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -050091 private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
Will Brockman492b3812020-03-03 16:29:36 +000092 private NotificationPanelLoggerFake mNotificationPanelLoggerFake =
93 new NotificationPanelLoggerFake();
Eliot Courtney3985ad52017-11-17 16:51:52 +090094
95 @Before
Gus Prevasca1b6f72018-12-28 10:53:11 -050096 public void setUp() {
Eliot Courtney3985ad52017-11-17 16:51:52 +090097 MockitoAnnotations.initMocks(this);
Eliot Courtney8f56b0e2017-12-14 18:54:28 +090098 mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
99 mDependency.injectTestDependency(NotificationListener.class, mListener);
Eliot Courtney3985ad52017-11-17 16:51:52 +0900100
Ned Burns636c3792019-09-11 16:59:07 -0400101 mEntry = new NotificationEntryBuilder()
102 .setPkg(TEST_PACKAGE_NAME)
103 .setOpPkg(TEST_PACKAGE_NAME)
104 .setUid(TEST_UID)
105 .setNotification(new Notification())
106 .setUser(UserHandle.CURRENT)
Will Brockman492b3812020-03-03 16:29:36 +0000107 .setInstanceId(InstanceId.fakeInstanceId(1))
Ned Burns636c3792019-09-11 16:59:07 -0400108 .build();
Evan Laird94492852018-10-25 13:43:01 -0400109 mEntry.setRow(mRow);
Eliot Courtney3985ad52017-11-17 16:51:52 +0900110
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500111 mLogger = new TestableNotificationLogger(mListener, mUiBgExecutor,
Beverly8fdb5332019-02-04 14:29:49 -0500112 mEntryManager, mock(StatusBarStateControllerImpl.class), mBarService,
Tony Mak202f25d2019-01-07 14:40:39 +0000113 mExpansionStateLogger);
Jason Monk297c04e2018-08-23 17:16:59 -0400114 mLogger.setUpWithContainer(mListContainer);
Ned Burns761af0d2019-01-03 13:51:29 -0500115 verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
Eliot Courtney3985ad52017-11-17 16:51:52 +0900116 }
117
118 @Test
119 public void testOnChildLocationsChangedReportsVisibilityChanged() throws Exception {
Chris Wren2e89e8d2018-05-17 18:55:42 -0400120 NotificationVisibility[] newlyVisibleKeys = {
Ned Burns00b4b2d2019-10-17 22:09:27 -0400121 NotificationVisibility.obtain(mEntry.getKey(), 0, 1, true)
Chris Wren2e89e8d2018-05-17 18:55:42 -0400122 };
123 NotificationVisibility[] noLongerVisibleKeys = {};
Gus Prevasca1b6f72018-12-28 10:53:11 -0500124 doAnswer(invocation -> {
Chris Wren2e89e8d2018-05-17 18:55:42 -0400125 try {
126 assertArrayEquals(newlyVisibleKeys,
127 (NotificationVisibility[]) invocation.getArguments()[0]);
128 assertArrayEquals(noLongerVisibleKeys,
129 (NotificationVisibility[]) invocation.getArguments()[1]);
130 } catch (AssertionError error) {
131 mErrorQueue.offer(error);
132 }
133 return null;
134 }
135 ).when(mBarService).onNotificationVisibilityChanged(any(NotificationVisibility[].class),
136 any(NotificationVisibility[].class));
137
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900138 when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
Evan Laird181de622019-10-24 09:53:02 -0400139 when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900140 mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
Jason Monk6dceace2018-05-15 20:24:07 -0400141 TestableLooper.get(this).processAllMessages();
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500142 mUiBgExecutor.runAllReady();
Eliot Courtney3985ad52017-11-17 16:51:52 +0900143
Chris Wren2e89e8d2018-05-17 18:55:42 -0400144 if(!mErrorQueue.isEmpty()) {
145 throw mErrorQueue.poll();
146 }
Eliot Courtney3985ad52017-11-17 16:51:52 +0900147
148 // |mEntry| won't change visibility, so it shouldn't be reported again:
149 Mockito.reset(mBarService);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900150 mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
Jason Monk6dceace2018-05-15 20:24:07 -0400151 TestableLooper.get(this).processAllMessages();
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500152 mUiBgExecutor.runAllReady();
Eliot Courtney3985ad52017-11-17 16:51:52 +0900153
154 verify(mBarService, never()).onNotificationVisibilityChanged(any(), any());
155 }
156
157 @Test
158 public void testStoppingNotificationLoggingReportsCurrentNotifications()
159 throws Exception {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900160 when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
Evan Laird181de622019-10-24 09:53:02 -0400161 when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900162 mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
Jason Monk6dceace2018-05-15 20:24:07 -0400163 TestableLooper.get(this).processAllMessages();
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500164 mUiBgExecutor.runAllReady();
Eliot Courtney3985ad52017-11-17 16:51:52 +0900165 Mockito.reset(mBarService);
166
Will Brockmand93cb572020-05-08 17:26:39 -0400167 setStateAsleep();
168 mLogger.onDozingChanged(false); // Wake to lockscreen
169 mLogger.onDozingChanged(true); // And go back to sleep, turning off logging
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500170 mUiBgExecutor.runAllReady();
Eliot Courtney3985ad52017-11-17 16:51:52 +0900171 // The visibility objects are recycled by NotificationLogger, so we can't use specific
172 // matchers here.
173 verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any());
174 }
175
Will Brockmand93cb572020-05-08 17:26:39 -0400176 private void setStateAsleep() {
177 mLogger.onPanelExpandedChanged(true);
178 mLogger.onDozingChanged(true);
179 mLogger.onStateChanged(StatusBarState.KEYGUARD);
180 }
181
182 private void setStateAwake() {
183 mLogger.onPanelExpandedChanged(false);
184 mLogger.onDozingChanged(false);
185 mLogger.onStateChanged(StatusBarState.SHADE);
186 }
187
Will Brockman492b3812020-03-03 16:29:36 +0000188 @Test
Will Brockmand93cb572020-05-08 17:26:39 -0400189 public void testLogPanelShownOnWake() {
Will Brockman492b3812020-03-03 16:29:36 +0000190 when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
Will Brockmand93cb572020-05-08 17:26:39 -0400191 setStateAsleep();
192 mLogger.onDozingChanged(false); // Wake to lockscreen
Will Brockman492b3812020-03-03 16:29:36 +0000193 assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
Will Brockmand93cb572020-05-08 17:26:39 -0400194 assertTrue(mNotificationPanelLoggerFake.get(0).isLockscreen);
Will Brockman492b3812020-03-03 16:29:36 +0000195 assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
196 Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
197 assertEquals(TEST_PACKAGE_NAME, n.packageName);
198 assertEquals(TEST_UID, n.uid);
199 assertEquals(1, n.instanceId);
Will Brockmand93cb572020-05-08 17:26:39 -0400200 assertFalse(n.isGroupSummary);
Will Brockman61ae2862020-06-21 21:36:51 -0400201 assertEquals(Notifications.Notification.SECTION_ALERTING, n.section);
Will Brockman492b3812020-03-03 16:29:36 +0000202 }
203
204 @Test
Will Brockmand93cb572020-05-08 17:26:39 -0400205 public void testLogPanelShownOnShadePull() {
206 when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
207 setStateAwake();
208 // Now expand panel
209 mLogger.onPanelExpandedChanged(true);
210 assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
211 assertFalse(mNotificationPanelLoggerFake.get(0).isLockscreen);
212 assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
213 Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
214 assertEquals(TEST_PACKAGE_NAME, n.packageName);
215 assertEquals(TEST_UID, n.uid);
216 assertEquals(1, n.instanceId);
217 assertFalse(n.isGroupSummary);
Will Brockman61ae2862020-06-21 21:36:51 -0400218 assertEquals(Notifications.Notification.SECTION_ALERTING, n.section);
Will Brockmand93cb572020-05-08 17:26:39 -0400219 }
220
221
222 @Test
Will Brockman492b3812020-03-03 16:29:36 +0000223 public void testLogPanelShownHandlesNullInstanceIds() {
224 // Construct a NotificationEntry like mEntry, but with a null instance id.
225 NotificationEntry entry = new NotificationEntryBuilder()
226 .setPkg(TEST_PACKAGE_NAME)
227 .setOpPkg(TEST_PACKAGE_NAME)
228 .setUid(TEST_UID)
229 .setNotification(new Notification())
230 .setUser(UserHandle.CURRENT)
231 .build();
232 entry.setRow(mRow);
233
234 when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(entry));
Will Brockmand93cb572020-05-08 17:26:39 -0400235 setStateAsleep();
236 mLogger.onDozingChanged(false); // Wake to lockscreen
Will Brockman492b3812020-03-03 16:29:36 +0000237 assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
238 assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
239 Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
240 assertEquals(0, n.instanceId);
241 }
242
Eliot Courtney3985ad52017-11-17 16:51:52 +0900243 private class TestableNotificationLogger extends NotificationLogger {
244
Gus Prevasca1b6f72018-12-28 10:53:11 -0500245 TestableNotificationLogger(NotificationListener notificationListener,
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500246 Executor uiBgExecutor,
Jason Monkd97204c2018-12-21 15:49:04 -0500247 NotificationEntryManager entryManager,
Beverly8fdb5332019-02-04 14:29:49 -0500248 StatusBarStateControllerImpl statusBarStateController,
Tony Mak202f25d2019-01-07 14:40:39 +0000249 IStatusBarService barService,
250 ExpansionStateLogger expansionStateLogger) {
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500251 super(notificationListener, uiBgExecutor, entryManager, statusBarStateController,
Will Brockman492b3812020-03-03 16:29:36 +0000252 expansionStateLogger, mNotificationPanelLoggerFake);
Eliot Courtney3985ad52017-11-17 16:51:52 +0900253 mBarService = barService;
Jason Monk6dceace2018-05-15 20:24:07 -0400254 // Make this on the current thread so we can wait for it during tests.
255 mHandler = Handler.createAsync(Looper.myLooper());
Eliot Courtney3985ad52017-11-17 16:51:52 +0900256 }
257
Gus Prevasca1b6f72018-12-28 10:53:11 -0500258 OnChildLocationsChangedListener
Eliot Courtney3985ad52017-11-17 16:51:52 +0900259 getChildLocationsChangedListenerForTest() {
260 return mNotificationLocationsChangedListener;
261 }
Eliot Courtney3985ad52017-11-17 16:51:52 +0900262 }
263}