blob: 5e587f848ece280bf09482934508f0e2db83b4b7 [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
Rohan Shah20790b82018-07-02 17:21:04 -070014 * 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;
Eliot Courtney3985ad52017-11-17 16:51:52 +090020import static org.mockito.ArgumentMatchers.any;
Chris Wren2e89e8d2018-05-17 18:55:42 -040021import static org.mockito.Mockito.doAnswer;
Jason Monkd97204c2018-12-21 15:49:04 -050022import static org.mockito.Mockito.mock;
Eliot Courtney3985ad52017-11-17 16:51:52 +090023import static org.mockito.Mockito.never;
24import static org.mockito.Mockito.times;
25import static org.mockito.Mockito.verify;
26import static org.mockito.Mockito.when;
27
28import android.app.Notification;
29import android.os.Handler;
30import android.os.Looper;
31import android.os.UserHandle;
Eliot Courtney3985ad52017-11-17 16:51:52 +090032import android.service.notification.StatusBarNotification;
Eliot Courtney3985ad52017-11-17 16:51:52 +090033import android.testing.AndroidTestingRunner;
34import android.testing.TestableLooper;
35
Brett Chabot84151d92019-02-27 15:37:59 -080036import androidx.test.filters.SmallTest;
37
Eliot Courtney3985ad52017-11-17 16:51:52 +090038import com.android.internal.statusbar.IStatusBarService;
39import com.android.internal.statusbar.NotificationVisibility;
Jason Monkd97204c2018-12-21 15:49:04 -050040import com.android.systemui.Dependency;
Eliot Courtney3985ad52017-11-17 16:51:52 +090041import com.android.systemui.SysuiTestCase;
Jason Monkd97204c2018-12-21 15:49:04 -050042import com.android.systemui.UiOffloadThread;
Rohan Shah20790b82018-07-02 17:21:04 -070043import com.android.systemui.statusbar.NotificationListener;
Beverly8fdb5332019-02-04 14:29:49 -050044import com.android.systemui.statusbar.StatusBarStateControllerImpl;
Ned Burns761af0d2019-01-03 13:51:29 -050045import com.android.systemui.statusbar.notification.NotificationEntryListener;
Jason Monka716bac2018-12-05 15:48:21 -050046import com.android.systemui.statusbar.notification.NotificationEntryManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050047import com.android.systemui.statusbar.notification.collection.NotificationData;
48import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Rohan Shah20790b82018-07-02 17:21:04 -070049import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
50import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
Jason Monka716bac2018-12-05 15:48:21 -050051
Eliot Courtney3985ad52017-11-17 16:51:52 +090052import com.google.android.collect.Lists;
53
54import org.junit.Before;
55import org.junit.Test;
56import org.junit.runner.RunWith;
Ned Burns761af0d2019-01-03 13:51:29 -050057import org.mockito.ArgumentCaptor;
58import org.mockito.Captor;
Eliot Courtney3985ad52017-11-17 16:51:52 +090059import org.mockito.Mock;
60import org.mockito.Mockito;
61import org.mockito.MockitoAnnotations;
Chris Wren2e89e8d2018-05-17 18:55:42 -040062
63import java.util.concurrent.ConcurrentLinkedQueue;
Eliot Courtney3985ad52017-11-17 16:51:52 +090064
65@SmallTest
66@RunWith(AndroidTestingRunner.class)
Jason Monka716bac2018-12-05 15:48:21 -050067@TestableLooper.RunWithLooper
Eliot Courtney3985ad52017-11-17 16:51:52 +090068public class NotificationLoggerTest extends SysuiTestCase {
69 private static final String TEST_PACKAGE_NAME = "test";
70 private static final int TEST_UID = 0;
71
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090072 @Mock private NotificationListContainer mListContainer;
Eliot Courtney3985ad52017-11-17 16:51:52 +090073 @Mock private IStatusBarService mBarService;
74 @Mock private NotificationData mNotificationData;
75 @Mock private ExpandableNotificationRow mRow;
Tony Mak202f25d2019-01-07 14:40:39 +000076 @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
Eliot Courtney3985ad52017-11-17 16:51:52 +090077
Eliot Courtney8f56b0e2017-12-14 18:54:28 +090078 // Dependency mocks:
79 @Mock private NotificationEntryManager mEntryManager;
80 @Mock private NotificationListener mListener;
Ned Burns761af0d2019-01-03 13:51:29 -050081 @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
Eliot Courtney8f56b0e2017-12-14 18:54:28 +090082
Ned Burnsf81c4c42019-01-07 14:10:43 -050083 private NotificationEntry mEntry;
Eliot Courtney3985ad52017-11-17 16:51:52 +090084 private TestableNotificationLogger mLogger;
Ned Burns761af0d2019-01-03 13:51:29 -050085 private NotificationEntryListener mNotificationEntryListener;
Chris Wren2e89e8d2018-05-17 18:55:42 -040086 private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>();
Eliot Courtney3985ad52017-11-17 16:51:52 +090087
88 @Before
Gus Prevasca1b6f72018-12-28 10:53:11 -050089 public void setUp() {
Eliot Courtney3985ad52017-11-17 16:51:52 +090090 MockitoAnnotations.initMocks(this);
Eliot Courtney8f56b0e2017-12-14 18:54:28 +090091 mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
92 mDependency.injectTestDependency(NotificationListener.class, mListener);
Eliot Courtney3985ad52017-11-17 16:51:52 +090093
Eliot Courtneya6d8cf22017-10-20 13:26:58 +090094 when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
Eliot Courtney3985ad52017-11-17 16:51:52 +090095
Gus Prevasca1b6f72018-12-28 10:53:11 -050096 StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
97 0, null, TEST_UID,
Eliot Courtney3985ad52017-11-17 16:51:52 +090098 0, new Notification(), UserHandle.CURRENT, null, 0);
Ned Burnsf81c4c42019-01-07 14:10:43 -050099 mEntry = new NotificationEntry(sbn);
Evan Laird94492852018-10-25 13:43:01 -0400100 mEntry.setRow(mRow);
Eliot Courtney3985ad52017-11-17 16:51:52 +0900101
Jason Monkd97204c2018-12-21 15:49:04 -0500102 mLogger = new TestableNotificationLogger(mListener, Dependency.get(UiOffloadThread.class),
Beverly8fdb5332019-02-04 14:29:49 -0500103 mEntryManager, mock(StatusBarStateControllerImpl.class), mBarService,
Tony Mak202f25d2019-01-07 14:40:39 +0000104 mExpansionStateLogger);
Jason Monk297c04e2018-08-23 17:16:59 -0400105 mLogger.setUpWithContainer(mListContainer);
Ned Burns761af0d2019-01-03 13:51:29 -0500106 verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
107 mNotificationEntryListener = mEntryListenerCaptor.getValue();
Eliot Courtney3985ad52017-11-17 16:51:52 +0900108 }
109
110 @Test
111 public void testOnChildLocationsChangedReportsVisibilityChanged() throws Exception {
Chris Wren2e89e8d2018-05-17 18:55:42 -0400112 NotificationVisibility[] newlyVisibleKeys = {
113 NotificationVisibility.obtain(mEntry.key, 0, 1, true)
114 };
115 NotificationVisibility[] noLongerVisibleKeys = {};
Gus Prevasca1b6f72018-12-28 10:53:11 -0500116 doAnswer(invocation -> {
Chris Wren2e89e8d2018-05-17 18:55:42 -0400117 try {
118 assertArrayEquals(newlyVisibleKeys,
119 (NotificationVisibility[]) invocation.getArguments()[0]);
120 assertArrayEquals(noLongerVisibleKeys,
121 (NotificationVisibility[]) invocation.getArguments()[1]);
122 } catch (AssertionError error) {
123 mErrorQueue.offer(error);
124 }
125 return null;
126 }
127 ).when(mBarService).onNotificationVisibilityChanged(any(NotificationVisibility[].class),
128 any(NotificationVisibility[].class));
129
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900130 when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
Eliot Courtney3985ad52017-11-17 16:51:52 +0900131 when(mNotificationData.getActiveNotifications()).thenReturn(Lists.newArrayList(mEntry));
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900132 mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
Jason Monk6dceace2018-05-15 20:24:07 -0400133 TestableLooper.get(this).processAllMessages();
Eliot Courtney3985ad52017-11-17 16:51:52 +0900134 waitForUiOffloadThread();
135
Chris Wren2e89e8d2018-05-17 18:55:42 -0400136 if(!mErrorQueue.isEmpty()) {
137 throw mErrorQueue.poll();
138 }
Eliot Courtney3985ad52017-11-17 16:51:52 +0900139
140 // |mEntry| won't change visibility, so it shouldn't be reported again:
141 Mockito.reset(mBarService);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900142 mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
Jason Monk6dceace2018-05-15 20:24:07 -0400143 TestableLooper.get(this).processAllMessages();
Eliot Courtney3985ad52017-11-17 16:51:52 +0900144 waitForUiOffloadThread();
145
146 verify(mBarService, never()).onNotificationVisibilityChanged(any(), any());
147 }
148
149 @Test
150 public void testStoppingNotificationLoggingReportsCurrentNotifications()
151 throws Exception {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900152 when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
Eliot Courtney3985ad52017-11-17 16:51:52 +0900153 when(mNotificationData.getActiveNotifications()).thenReturn(Lists.newArrayList(mEntry));
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900154 mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
Jason Monk6dceace2018-05-15 20:24:07 -0400155 TestableLooper.get(this).processAllMessages();
Eliot Courtney3985ad52017-11-17 16:51:52 +0900156 waitForUiOffloadThread();
157 Mockito.reset(mBarService);
158
159 mLogger.stopNotificationLogging();
160 waitForUiOffloadThread();
161 // The visibility objects are recycled by NotificationLogger, so we can't use specific
162 // matchers here.
163 verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any());
164 }
165
166 private class TestableNotificationLogger extends NotificationLogger {
167
Gus Prevasca1b6f72018-12-28 10:53:11 -0500168 TestableNotificationLogger(NotificationListener notificationListener,
Jason Monkd97204c2018-12-21 15:49:04 -0500169 UiOffloadThread uiOffloadThread,
170 NotificationEntryManager entryManager,
Beverly8fdb5332019-02-04 14:29:49 -0500171 StatusBarStateControllerImpl statusBarStateController,
Tony Mak202f25d2019-01-07 14:40:39 +0000172 IStatusBarService barService,
173 ExpansionStateLogger expansionStateLogger) {
174 super(notificationListener, uiOffloadThread, entryManager, statusBarStateController,
175 expansionStateLogger);
Eliot Courtney3985ad52017-11-17 16:51:52 +0900176 mBarService = barService;
Jason Monk6dceace2018-05-15 20:24:07 -0400177 // Make this on the current thread so we can wait for it during tests.
178 mHandler = Handler.createAsync(Looper.myLooper());
Eliot Courtney3985ad52017-11-17 16:51:52 +0900179 }
180
Gus Prevasca1b6f72018-12-28 10:53:11 -0500181 OnChildLocationsChangedListener
Eliot Courtney3985ad52017-11-17 16:51:52 +0900182 getChildLocationsChangedListenerForTest() {
183 return mNotificationLocationsChangedListener;
184 }
Eliot Courtney3985ad52017-11-17 16:51:52 +0900185 }
186}