blob: b286f9486e13c438a78a69678c47b3197448c433 [file] [log] [blame]
Selim Cinek8a9308d2017-08-24 09:31:08 -07001/*
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.
Jason Monke59dc402018-08-16 12:05:01 -04006 * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 *
Selim Cinek8a9308d2017-08-24 09:31:08 -07007 * Unless required by applicable law or agreed to in writing, software
8 * distributed under the License is distributed on an "AS IS" BASIS,
9 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 * See the License for the specific language governing permissions and
11 * limitations under the License
12 */
13
Rohan Shah20790b82018-07-02 17:21:04 -070014package com.android.systemui.statusbar.notification.stack;
Selim Cinek8a9308d2017-08-24 09:31:08 -070015
Julia Reynoldsda7c2452020-04-16 16:44:58 -040016import static android.provider.Settings.Secure.NOTIFICATION_HISTORY_ENABLED;
Gus Prevase2d6f042018-10-17 15:25:30 -040017import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL;
18
Jason Monke59dc402018-08-16 12:05:01 -040019import static junit.framework.Assert.assertEquals;
20import static junit.framework.Assert.assertNotNull;
Gus Prevas99ba4ba2018-10-01 16:40:23 -040021import static junit.framework.Assert.assertNull;
22
Jason Monk297c04e2018-08-23 17:16:59 -040023import static org.junit.Assert.assertFalse;
Rohan Shah524cf7b2018-03-15 14:40:02 -070024import static org.mockito.ArgumentMatchers.any;
25import static org.mockito.ArgumentMatchers.anyBoolean;
Jason Monke59dc402018-08-16 12:05:01 -040026import static org.mockito.ArgumentMatchers.anyInt;
Will Brockmane718d582019-01-17 16:38:38 -050027import static org.mockito.ArgumentMatchers.argThat;
Selim Cinekd60ef9e2018-05-16 16:01:05 -070028import static org.mockito.ArgumentMatchers.eq;
Gus Prevase2d6f042018-10-17 15:25:30 -040029import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
Evan Lairdfec77662018-09-18 16:56:50 -040030import static org.mockito.Mockito.atLeastOnce;
Jason Monke59dc402018-08-16 12:05:01 -040031import static org.mockito.Mockito.clearInvocations;
Rohan Shah524cf7b2018-03-15 14:40:02 -070032import static org.mockito.Mockito.doNothing;
Selim Cinek8a9308d2017-08-24 09:31:08 -070033import static org.mockito.Mockito.mock;
Rohan Shah524cf7b2018-03-15 14:40:02 -070034import static org.mockito.Mockito.reset;
35import static org.mockito.Mockito.spy;
Julia Reynolds9cf17562018-03-14 09:49:35 -040036import static org.mockito.Mockito.verify;
Selim Cinek8a9308d2017-08-24 09:31:08 -070037import static org.mockito.Mockito.when;
38
Will Brockmane718d582019-01-17 16:38:38 -050039import android.metrics.LogMaker;
Julia Reynolds1f94a9d2020-05-05 12:40:21 -040040import android.os.UserHandle;
Gus Prevase2d6f042018-10-17 15:25:30 -040041import android.provider.Settings;
Ned Burnsd4a69f72019-06-19 19:49:19 -040042import android.testing.AndroidTestingRunner;
43import android.testing.TestableLooper;
Gus Prevas99ba4ba2018-10-01 16:40:23 -040044import android.view.View;
Selim Cinek8a9308d2017-08-24 09:31:08 -070045
Brett Chabot84151d92019-02-27 15:37:59 -080046import androidx.test.annotation.UiThreadTest;
47import androidx.test.filters.SmallTest;
Brett Chabot84151d92019-02-27 15:37:59 -080048
Will Brockmane718d582019-01-17 16:38:38 -050049import com.android.internal.logging.MetricsLogger;
50import com.android.internal.logging.nano.MetricsProto;
Will Brockmanb65faa82020-03-06 10:26:04 -050051import com.android.internal.logging.testing.UiEventLoggerFake;
Rohan Shah524cf7b2018-03-15 14:40:02 -070052import com.android.systemui.ExpandHelper;
Julia Reynolds9cf17562018-03-14 09:49:35 -040053import com.android.systemui.R;
Selim Cinek8a9308d2017-08-24 09:31:08 -070054import com.android.systemui.SysuiTestCase;
Dave Mankoffc195ea82019-06-28 16:33:25 -040055import com.android.systemui.classifier.FalsingManagerFake;
Selim Cinekafae4e72020-06-16 18:21:41 -070056import com.android.systemui.media.KeyguardMediaController;
Will Brockmane718d582019-01-17 16:38:38 -050057import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
Julia Reynolds9cf17562018-03-14 09:49:35 -040058import com.android.systemui.statusbar.EmptyShadeView;
Beverly8b493df2019-12-18 14:16:50 -050059import com.android.systemui.statusbar.FeatureFlags;
Lucas Dupind236ee32019-10-08 15:33:59 -070060import com.android.systemui.statusbar.NotificationLockscreenUserManager;
Lucas Dupin28790c02020-01-30 14:18:41 -080061import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
Evan Laird181de622019-10-24 09:53:02 -040062import com.android.systemui.statusbar.NotificationMediaManager;
Jason Monke59dc402018-08-16 12:05:01 -040063import com.android.systemui.statusbar.NotificationPresenter;
Jason Monk297c04e2018-08-23 17:16:59 -040064import com.android.systemui.statusbar.NotificationRemoteInputManager;
65import com.android.systemui.statusbar.NotificationShelf;
66import com.android.systemui.statusbar.RemoteInputController;
67import com.android.systemui.statusbar.StatusBarState;
Selim Cinek5454a0d2019-07-30 17:14:50 -070068import com.android.systemui.statusbar.SysuiStatusBarStateController;
Selim Cinek6f0a62a2019-04-09 18:40:12 -070069import com.android.systemui.statusbar.notification.DynamicPrivacyController;
Evan Laird04373662020-01-24 17:37:39 -050070import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
Jason Monke59dc402018-08-16 12:05:01 -040071import com.android.systemui.statusbar.notification.NotificationEntryManager;
Ned Burnsafe77bc2020-01-30 20:45:07 -050072import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
Evan Laird181de622019-10-24 09:53:02 -040073import com.android.systemui.statusbar.notification.NotificationFilter;
Evan Laird367b6142019-08-30 14:40:34 -040074import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
Evan Laird181de622019-10-24 09:53:02 -040075import com.android.systemui.statusbar.notification.VisualStabilityManager;
Beverly7e0d6492020-02-07 16:22:14 -050076import com.android.systemui.statusbar.notification.collection.NotifCollection;
77import com.android.systemui.statusbar.notification.collection.NotifPipeline;
Ned Burnsf81c4c42019-01-07 14:10:43 -050078import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Beverly79c89ec2019-12-13 10:33:01 -050079import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
Evan Laird181de622019-10-24 09:53:02 -040080import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
Ned Burnsc0cd2832020-01-10 00:37:03 -050081import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
Beverlye558f1d2020-01-07 16:28:58 -050082import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
Steve Elliott960f4ce2019-12-04 15:13:52 -050083import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
Jason Monke59dc402018-08-16 12:05:01 -040084import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Rohan Shah20790b82018-07-02 17:21:04 -070085import com.android.systemui.statusbar.notification.row.FooterView;
86import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
Lucas Dupind236ee32019-10-08 15:33:59 -070087import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
Rohan Shah524cf7b2018-03-15 14:40:02 -070088import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
Selim Cinekc3fec682019-06-06 18:11:07 -070089import com.android.systemui.statusbar.phone.KeyguardBypassController;
Rohan Shah524cf7b2018-03-15 14:40:02 -070090import com.android.systemui.statusbar.phone.NotificationGroupManager;
Lucas Dupinfe218782019-06-11 15:20:32 -070091import com.android.systemui.statusbar.phone.NotificationIconAreaController;
Selim Cinek8a9308d2017-08-24 09:31:08 -070092import com.android.systemui.statusbar.phone.ScrimController;
Jason Monk297c04e2018-08-23 17:16:59 -040093import com.android.systemui.statusbar.phone.ShadeController;
Selim Cinek8a9308d2017-08-24 09:31:08 -070094import com.android.systemui.statusbar.phone.StatusBar;
Beverly482ad6a2019-11-06 16:57:05 -050095import com.android.systemui.statusbar.policy.ZenModeController;
Dave Mankoff02dcaf52020-01-08 15:42:06 -050096import com.android.systemui.util.leak.LeakDetector;
Jason Monke59dc402018-08-16 12:05:01 -040097
Gus Prevase2d6f042018-10-17 15:25:30 -040098import org.junit.After;
Selim Cinek8a9308d2017-08-24 09:31:08 -070099import org.junit.Before;
Rohan Shah524cf7b2018-03-15 14:40:02 -0700100import org.junit.Rule;
Selim Cinek8a9308d2017-08-24 09:31:08 -0700101import org.junit.Test;
102import org.junit.runner.RunWith;
Jason Monke59dc402018-08-16 12:05:01 -0400103import org.mockito.ArgumentCaptor;
Will Brockmane718d582019-01-17 16:38:38 -0500104import org.mockito.ArgumentMatcher;
Rohan Shah524cf7b2018-03-15 14:40:02 -0700105import org.mockito.Mock;
106import org.mockito.junit.MockitoJUnit;
107import org.mockito.junit.MockitoRule;
Selim Cinek8a9308d2017-08-24 09:31:08 -0700108
Jason Monk297c04e2018-08-23 17:16:59 -0400109import java.util.ArrayList;
Evan Laird181de622019-10-24 09:53:02 -0400110import java.util.List;
Jason Monk297c04e2018-08-23 17:16:59 -0400111
Rohan Shah524cf7b2018-03-15 14:40:02 -0700112/**
113 * Tests for {@link NotificationStackScrollLayout}.
114 */
Selim Cinek8a9308d2017-08-24 09:31:08 -0700115@SmallTest
Ned Burnsd4a69f72019-06-19 19:49:19 -0400116@RunWith(AndroidTestingRunner.class)
117@TestableLooper.RunWithLooper
Selim Cinek8a9308d2017-08-24 09:31:08 -0700118public class NotificationStackScrollLayoutTest extends SysuiTestCase {
119
Will Brockmane718d582019-01-17 16:38:38 -0500120 private NotificationStackScrollLayout mStackScroller; // Normally test this
121 private NotificationStackScrollLayout mStackScrollerInternal; // See explanation below
Rohan Shah524cf7b2018-03-15 14:40:02 -0700122
123 @Rule public MockitoRule mockito = MockitoJUnit.rule();
124 @Mock private StatusBar mBar;
Selim Cinek5454a0d2019-07-30 17:14:50 -0700125 @Mock private SysuiStatusBarStateController mBarState;
Rohan Shah524cf7b2018-03-15 14:40:02 -0700126 @Mock private HeadsUpManagerPhone mHeadsUpManager;
127 @Mock private NotificationBlockingHelperManager mBlockingHelperManager;
128 @Mock private NotificationGroupManager mGroupManager;
129 @Mock private ExpandHelper mExpandHelper;
130 @Mock private EmptyShadeView mEmptyShadeView;
Jason Monke59dc402018-08-16 12:05:01 -0400131 @Mock private NotificationRemoteInputManager mRemoteInputManager;
132 @Mock private RemoteInputController mRemoteInputController;
Lucas Dupinfe218782019-06-11 15:20:32 -0700133 @Mock private NotificationIconAreaController mNotificationIconAreaController;
Will Brockmane718d582019-01-17 16:38:38 -0500134 @Mock private MetricsLogger mMetricsLogger;
Lucas Dupin00be88f2019-01-03 17:50:52 -0800135 @Mock private NotificationRoundnessManager mNotificationRoundnessManager;
Selim Cinekc3fec682019-06-06 18:11:07 -0700136 @Mock private KeyguardBypassController mKeyguardBypassController;
Selim Cinekafae4e72020-06-16 18:21:41 -0700137 @Mock private KeyguardMediaController mKeyguardMediaController;
Beverly482ad6a2019-11-06 16:57:05 -0500138 @Mock private ZenModeController mZenModeController;
Dave Mankoff56fe9e42020-01-08 15:42:06 -0500139 @Mock private NotificationSectionsManager mNotificationSectionsManager;
140 @Mock private NotificationSection mNotificationSection;
Lucas Dupin28790c02020-01-30 14:18:41 -0800141 @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
Beverly7e0d6492020-02-07 16:22:14 -0500142 @Mock private FeatureFlags mFeatureFlags;
Lucas Dupin28790c02020-01-30 14:18:41 -0800143 private UserChangedListener mUserChangedListener;
Kevin Hanbd142932020-03-10 18:27:50 -0700144 private NotificationEntryManager mEntryManager;
Gus Prevase2d6f042018-10-17 15:25:30 -0400145 private int mOriginalInterruptionModelSetting;
Will Brockmanb65faa82020-03-06 10:26:04 -0500146 private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
Selim Cinek8a9308d2017-08-24 09:31:08 -0700147
Will Brockmane718d582019-01-17 16:38:38 -0500148
Selim Cinek8a9308d2017-08-24 09:31:08 -0700149 @Before
150 @UiThreadTest
151 public void setUp() throws Exception {
Beverly1467c9e2020-02-18 13:31:29 -0500152 allowTestableLooperAsMainThread();
Ned Burnsd4a69f72019-06-19 19:49:19 -0400153
Ned Burns9eb06332019-04-23 16:02:12 -0400154 mOriginalInterruptionModelSetting = Settings.Secure.getInt(mContext.getContentResolver(),
155 NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
156 Settings.Secure.putInt(mContext.getContentResolver(),
157 NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
Julia Reynolds1f94a9d2020-05-05 12:40:21 -0400158 Settings.Secure.putIntForUser(mContext.getContentResolver(), NOTIFICATION_HISTORY_ENABLED,
159 1, UserHandle.USER_CURRENT);
Ned Burns9eb06332019-04-23 16:02:12 -0400160
Rohan Shah524cf7b2018-03-15 14:40:02 -0700161 // Inject dependencies before initializing the layout
Evan Laird181de622019-10-24 09:53:02 -0400162 mDependency.injectMockDependency(VisualStabilityManager.class);
Rohan Shah524cf7b2018-03-15 14:40:02 -0700163 mDependency.injectTestDependency(
164 NotificationBlockingHelperManager.class,
165 mBlockingHelperManager);
Selim Cinekeec58842019-08-02 09:35:28 -0700166 mDependency.injectTestDependency(SysuiStatusBarStateController.class, mBarState);
Will Brockmane718d582019-01-17 16:38:38 -0500167 mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
Jason Monke59dc402018-08-16 12:05:01 -0400168 mDependency.injectTestDependency(NotificationRemoteInputManager.class,
169 mRemoteInputManager);
Jason Monk297c04e2018-08-23 17:16:59 -0400170 mDependency.injectMockDependency(ShadeController.class);
Jason Monke59dc402018-08-16 12:05:01 -0400171 when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
172
Lucas Dupin28790c02020-01-30 14:18:41 -0800173 ArgumentCaptor<UserChangedListener> userChangedCaptor = ArgumentCaptor
174 .forClass(UserChangedListener.class);
Kevin Hanbd142932020-03-10 18:27:50 -0700175 mEntryManager = new NotificationEntryManager(
Ned Burnsafe77bc2020-01-30 20:45:07 -0500176 mock(NotificationEntryManagerLogger.class),
Evan Laird181de622019-10-24 09:53:02 -0400177 mock(NotificationGroupManager.class),
178 new NotificationRankingManager(
179 () -> mock(NotificationMediaManager.class),
180 mGroupManager,
181 mHeadsUpManager,
182 mock(NotificationFilter.class),
Ned Burnsafe77bc2020-01-30 20:45:07 -0500183 mock(NotificationEntryManagerLogger.class),
Steve Elliott960f4ce2019-12-04 15:13:52 -0500184 mock(NotificationSectionsFeatureManager.class),
Beverlye558f1d2020-01-07 16:28:58 -0500185 mock(PeopleNotificationIdentifier.class),
186 mock(HighPriorityProvider.class)
Evan Laird181de622019-10-24 09:53:02 -0400187 ),
Beverly8b493df2019-12-18 14:16:50 -0500188 mock(NotificationEntryManager.KeyguardEnvironment.class),
Dave Mankoff02dcaf52020-01-08 15:42:06 -0500189 mock(FeatureFlags.class),
190 () -> mock(NotificationRowBinder.class),
191 () -> mRemoteInputManager,
Evan Laird04373662020-01-24 17:37:39 -0500192 mock(LeakDetector.class),
193 mock(ForegroundServiceDismissalFeatureController.class)
194 );
Kevin Hanbd142932020-03-10 18:27:50 -0700195 mEntryManager.setUpWithPresenter(mock(NotificationPresenter.class));
Beverly7e0d6492020-02-07 16:22:14 -0500196 when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
Jason Monk297c04e2018-08-23 17:16:59 -0400197
198 NotificationShelf notificationShelf = mock(NotificationShelf.class);
Dave Mankoff56fe9e42020-01-08 15:42:06 -0500199 when(mNotificationSectionsManager.createSectionsForBuckets()).thenReturn(
200 new NotificationSection[]{
201 mNotificationSection
202 });
Will Brockmane718d582019-01-17 16:38:38 -0500203 // The actual class under test. You may need to work with this class directly when
204 // testing anonymous class members of mStackScroller, like mMenuEventListener,
205 // which refer to members of NotificationStackScrollLayout. The spy
Evan Laird181de622019-10-24 09:53:02 -0400206 // holds a copy of the CUT's instances of these KeyguardBypassController, so they still
207 // refer to the CUT's member variables, not the spy's member variables.
Will Brockmane718d582019-01-17 16:38:38 -0500208 mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null,
Selim Cinek34518f62019-02-28 19:41:18 -0800209 true /* allowLongPress */, mNotificationRoundnessManager,
Ned Burns9eb06332019-04-23 16:02:12 -0400210 mock(DynamicPrivacyController.class),
Selim Cinekeec58842019-08-02 09:35:28 -0700211 mock(SysuiStatusBarStateController.class),
Selim Cinekc3fec682019-06-06 18:11:07 -0700212 mHeadsUpManager,
Dave Mankoffc195ea82019-06-28 16:33:25 -0400213 mKeyguardBypassController,
Selim Cinekafae4e72020-06-16 18:21:41 -0700214 mKeyguardMediaController,
Evan Laird367b6142019-08-30 14:40:34 -0400215 new FalsingManagerFake(),
Lucas Dupin28790c02020-01-30 14:18:41 -0800216 mLockscreenUserManager,
Lucas Dupind236ee32019-10-08 15:33:59 -0700217 mock(NotificationGutsManager.class),
Dave Mankoff56fe9e42020-01-08 15:42:06 -0500218 mZenModeController,
Evan Laird04373662020-01-24 17:37:39 -0500219 mNotificationSectionsManager,
220 mock(ForegroundServiceSectionController.class),
Beverly7e0d6492020-02-07 16:22:14 -0500221 mock(ForegroundServiceDismissalFeatureController.class),
222 mFeatureFlags,
223 mock(NotifPipeline.class),
224 mEntryManager,
Will Brockmanb65faa82020-03-06 10:26:04 -0500225 mock(NotifCollection.class),
226 mUiEventLoggerFake
Evan Laird04373662020-01-24 17:37:39 -0500227 );
Lucas Dupin28790c02020-01-30 14:18:41 -0800228 verify(mLockscreenUserManager).addUserChangedListener(userChangedCaptor.capture());
229 mUserChangedListener = userChangedCaptor.getValue();
Will Brockmane718d582019-01-17 16:38:38 -0500230 mStackScroller = spy(mStackScrollerInternal);
Rohan Shah524cf7b2018-03-15 14:40:02 -0700231 mStackScroller.setShelf(notificationShelf);
Selim Cinek8a9308d2017-08-24 09:31:08 -0700232 mStackScroller.setStatusBar(mBar);
233 mStackScroller.setScrimController(mock(ScrimController.class));
Rohan Shah524cf7b2018-03-15 14:40:02 -0700234 mStackScroller.setGroupManager(mGroupManager);
235 mStackScroller.setEmptyShadeView(mEmptyShadeView);
Lucas Dupinfe218782019-06-11 15:20:32 -0700236 mStackScroller.setIconAreaController(mNotificationIconAreaController);
Rohan Shah524cf7b2018-03-15 14:40:02 -0700237
238 // Stub out functionality that isn't necessary to test.
239 doNothing().when(mBar)
240 .executeRunnableDismissingKeyguard(any(Runnable.class),
241 any(Runnable.class),
242 anyBoolean(),
243 anyBoolean(),
244 anyBoolean());
245 doNothing().when(mGroupManager).collapseAllGroups();
246 doNothing().when(mExpandHelper).cancelImmediately();
247 doNothing().when(notificationShelf).setAnimationsEnabled(anyBoolean());
Gus Prevase2d6f042018-10-17 15:25:30 -0400248 }
249
250 @After
251 public void tearDown() {
252 Settings.Secure.putInt(mContext.getContentResolver(),
253 NOTIFICATION_NEW_INTERRUPTION_MODEL, mOriginalInterruptionModelSetting);
Selim Cinek8a9308d2017-08-24 09:31:08 -0700254 }
255
256 @Test
257 public void testNotDimmedOnKeyguard() {
Jason Monk1fd3fc32018-08-14 17:20:09 -0400258 when(mBarState.getState()).thenReturn(StatusBarState.SHADE);
Selim Cinek8a9308d2017-08-24 09:31:08 -0700259 mStackScroller.setDimmed(true /* dimmed */, false /* animate */);
260 mStackScroller.setDimmed(true /* dimmed */, true /* animate */);
Jason Monk297c04e2018-08-23 17:16:59 -0400261 assertFalse(mStackScroller.isDimmed());
Selim Cinek8a9308d2017-08-24 09:31:08 -0700262 }
263
Lucas Dupin0cd882f2018-01-30 12:19:49 -0800264 @Test
Julia Reynolds34f14962018-05-03 12:40:20 +0000265 public void updateEmptyView_dndSuppressing() {
266 when(mEmptyShadeView.willBeGone()).thenReturn(true);
Beverly482ad6a2019-11-06 16:57:05 -0500267 when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
Julia Reynolds34f14962018-05-03 12:40:20 +0000268
269 mStackScroller.updateEmptyShadeView(true);
270
271 verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
272 }
273
274 @Test
275 public void updateEmptyView_dndNotSuppressing() {
276 mStackScroller.setEmptyShadeView(mEmptyShadeView);
277 when(mEmptyShadeView.willBeGone()).thenReturn(true);
Beverly482ad6a2019-11-06 16:57:05 -0500278 when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
Julia Reynolds34f14962018-05-03 12:40:20 +0000279
280 mStackScroller.updateEmptyShadeView(true);
281
282 verify(mEmptyShadeView).setText(R.string.empty_shade_text);
283 }
284
285 @Test
286 public void updateEmptyView_noNotificationsToDndSuppressing() {
287 mStackScroller.setEmptyShadeView(mEmptyShadeView);
288 when(mEmptyShadeView.willBeGone()).thenReturn(true);
Beverly482ad6a2019-11-06 16:57:05 -0500289 when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
Julia Reynolds34f14962018-05-03 12:40:20 +0000290 mStackScroller.updateEmptyShadeView(true);
291 verify(mEmptyShadeView).setText(R.string.empty_shade_text);
292
Beverly482ad6a2019-11-06 16:57:05 -0500293 when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
Julia Reynolds34f14962018-05-03 12:40:20 +0000294 mStackScroller.updateEmptyShadeView(true);
295 verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
296 }
297
298 @Test
Rohan Shah524cf7b2018-03-15 14:40:02 -0700299 @UiThreadTest
300 public void testSetExpandedHeight_blockingHelperManagerReceivedCallbacks() {
301 mStackScroller.setExpandedHeight(0f);
302 verify(mBlockingHelperManager).setNotificationShadeExpanded(0f);
303 reset(mBlockingHelperManager);
304
305 mStackScroller.setExpandedHeight(100f);
306 verify(mBlockingHelperManager).setNotificationShadeExpanded(100f);
Julia Reynolds9cf17562018-03-14 09:49:35 -0400307 }
Julia Reynoldsed1c9af2018-03-21 15:21:09 -0400308
309 @Test
Lucas Dupin28790c02020-01-30 14:18:41 -0800310 public void testOnStatePostChange_verifyIfProfileIsPublic() {
311 mUserChangedListener.onUserChanged(0);
312 verify(mLockscreenUserManager).isAnyProfilePublicMode();
313 }
314
315 @Test
Julia Reynoldsed1c9af2018-03-21 15:21:09 -0400316 public void manageNotifications_visible() {
317 FooterView view = mock(FooterView.class);
318 mStackScroller.setFooterView(view);
319 when(view.willBeGone()).thenReturn(true);
Julia Reynoldsed1c9af2018-03-21 15:21:09 -0400320
Julia Reynoldsda7c2452020-04-16 16:44:58 -0400321 mStackScroller.updateFooterView(true, false, true);
Julia Reynoldsed1c9af2018-03-21 15:21:09 -0400322
Selim Cinekd60ef9e2018-05-16 16:01:05 -0700323 verify(view).setVisible(eq(true), anyBoolean());
324 verify(view).setSecondaryVisible(eq(false), anyBoolean());
Julia Reynoldsed1c9af2018-03-21 15:21:09 -0400325 }
326
327 @Test
328 public void clearAll_visible() {
329 FooterView view = mock(FooterView.class);
330 mStackScroller.setFooterView(view);
331 when(view.willBeGone()).thenReturn(true);
Julia Reynoldsed1c9af2018-03-21 15:21:09 -0400332
Julia Reynoldsda7c2452020-04-16 16:44:58 -0400333 mStackScroller.updateFooterView(true, true, true);
Julia Reynoldsed1c9af2018-03-21 15:21:09 -0400334
Selim Cinekd60ef9e2018-05-16 16:01:05 -0700335 verify(view).setVisible(eq(true), anyBoolean());
336 verify(view).setSecondaryVisible(eq(true), anyBoolean());
Julia Reynoldsed1c9af2018-03-21 15:21:09 -0400337 }
Jason Monke59dc402018-08-16 12:05:01 -0400338
339 @Test
340 public void testInflateFooterView() {
341 mStackScroller.inflateFooterView();
342 ArgumentCaptor<FooterView> captor = ArgumentCaptor.forClass(FooterView.class);
343 verify(mStackScroller).setFooterView(captor.capture());
344
345 assertNotNull(captor.getValue().findViewById(R.id.manage_text).hasOnClickListeners());
346 assertNotNull(captor.getValue().findViewById(R.id.dismiss_text).hasOnClickListeners());
347 }
348
349 @Test
350 public void testUpdateFooter_noNotifications() {
351 setBarStateForTest(StatusBarState.SHADE);
Evan Laird181de622019-10-24 09:53:02 -0400352 assertEquals(0, mEntryManager.getActiveNotificationsCount());
Jason Monke59dc402018-08-16 12:05:01 -0400353
Julia Reynoldsda7c2452020-04-16 16:44:58 -0400354 FooterView view = mock(FooterView.class);
355 mStackScroller.setFooterView(view);
Jason Monke59dc402018-08-16 12:05:01 -0400356 mStackScroller.updateFooter();
Julia Reynoldsda7c2452020-04-16 16:44:58 -0400357 verify(mStackScroller, atLeastOnce()).updateFooterView(false, false, true);
Jason Monke59dc402018-08-16 12:05:01 -0400358 }
359
360 @Test
361 public void testUpdateFooter_remoteInput() {
362 setBarStateForTest(StatusBarState.SHADE);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500363 ArrayList<NotificationEntry> entries = new ArrayList<>();
Evan Laird181de622019-10-24 09:53:02 -0400364 entries.add(new NotificationEntryBuilder().build());
365 addEntriesToEntryManager(entries);
Jason Monke59dc402018-08-16 12:05:01 -0400366
367 ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
368 when(row.canViewBeDismissed()).thenReturn(true);
369 when(mStackScroller.getChildCount()).thenReturn(1);
370 when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
371 when(mRemoteInputController.isRemoteInputActive()).thenReturn(true);
372
Julia Reynoldsda7c2452020-04-16 16:44:58 -0400373 FooterView view = mock(FooterView.class);
374 mStackScroller.setFooterView(view);
Jason Monke59dc402018-08-16 12:05:01 -0400375 mStackScroller.updateFooter();
Julia Reynoldsda7c2452020-04-16 16:44:58 -0400376 verify(mStackScroller).updateFooterView(false, true, true);
Jason Monke59dc402018-08-16 12:05:01 -0400377 }
378
379 @Test
380 public void testUpdateFooter_oneClearableNotification() {
381 setBarStateForTest(StatusBarState.SHADE);
Evan Laird181de622019-10-24 09:53:02 -0400382
Ned Burnsf81c4c42019-01-07 14:10:43 -0500383 ArrayList<NotificationEntry> entries = new ArrayList<>();
Evan Laird181de622019-10-24 09:53:02 -0400384 entries.add(new NotificationEntryBuilder().build());
385 addEntriesToEntryManager(entries);
Jason Monke59dc402018-08-16 12:05:01 -0400386
387 ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
388 when(row.canViewBeDismissed()).thenReturn(true);
389 when(mStackScroller.getChildCount()).thenReturn(1);
390 when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
391
Julia Reynoldsda7c2452020-04-16 16:44:58 -0400392 FooterView view = mock(FooterView.class);
393 mStackScroller.setFooterView(view);
Jason Monke59dc402018-08-16 12:05:01 -0400394 mStackScroller.updateFooter();
Julia Reynoldsda7c2452020-04-16 16:44:58 -0400395 verify(mStackScroller).updateFooterView(true, true, true);
Jason Monke59dc402018-08-16 12:05:01 -0400396 }
397
398 @Test
399 public void testUpdateFooter_oneNonClearableNotification() {
400 setBarStateForTest(StatusBarState.SHADE);
Evan Laird181de622019-10-24 09:53:02 -0400401
Ned Burnsf81c4c42019-01-07 14:10:43 -0500402 ArrayList<NotificationEntry> entries = new ArrayList<>();
Evan Laird181de622019-10-24 09:53:02 -0400403 entries.add(new NotificationEntryBuilder().build());
404 addEntriesToEntryManager(entries);
Jason Monke59dc402018-08-16 12:05:01 -0400405
Julia Reynoldsda7c2452020-04-16 16:44:58 -0400406 FooterView view = mock(FooterView.class);
407 mStackScroller.setFooterView(view);
Jason Monke59dc402018-08-16 12:05:01 -0400408 mStackScroller.updateFooter();
Julia Reynoldsda7c2452020-04-16 16:44:58 -0400409 verify(mStackScroller).updateFooterView(true, false, true);
Jason Monke59dc402018-08-16 12:05:01 -0400410 }
411
412 @Test
413 public void testUpdateFooter_atEnd() {
414 // add footer
415 mStackScroller.inflateFooterView();
416
417 // add notification
418 ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500419 NotificationEntry entry = mock(NotificationEntry.class);
Evan Laird94492852018-10-25 13:43:01 -0400420 when(row.getEntry()).thenReturn(entry);
421 when(entry.isClearable()).thenReturn(true);
Jason Monke59dc402018-08-16 12:05:01 -0400422 mStackScroller.addContainerView(row);
423
424 mStackScroller.onUpdateRowStates();
425
Evan Laird04373662020-01-24 17:37:39 -0500426 // Expecting the footer to be the last child
427 int expected = mStackScroller.getChildCount() - 1;
428
Jason Monke59dc402018-08-16 12:05:01 -0400429 // move footer to end
Evan Laird04373662020-01-24 17:37:39 -0500430 verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(expected));
Jason Monke59dc402018-08-16 12:05:01 -0400431 }
432
433 @Test
434 public void testOnDensityOrFontScaleChanged_reInflatesFooterViews() {
435 clearInvocations(mStackScroller);
436 mStackScroller.onDensityOrFontScaleChanged();
437 verify(mStackScroller).setFooterView(any());
438 verify(mStackScroller).setEmptyShadeView(any());
439 }
440
Gus Prevas99ba4ba2018-10-01 16:40:23 -0400441 @Test
442 @UiThreadTest
443 public void testSetIsBeingDraggedResetsExposedMenu() {
444 NotificationSwipeHelper swipeActionHelper =
445 (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
446 swipeActionHelper.setExposedMenuView(new View(mContext));
447 mStackScroller.setIsBeingDragged(true);
448 assertNull(swipeActionHelper.getExposedMenuView());
449 }
450
451 @Test
452 @UiThreadTest
453 public void testPanelTrackingStartResetsExposedMenu() {
454 NotificationSwipeHelper swipeActionHelper =
455 (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
456 swipeActionHelper.setExposedMenuView(new View(mContext));
457 mStackScroller.onPanelTrackingStarted();
458 assertNull(swipeActionHelper.getExposedMenuView());
459 }
460
461 @Test
462 @UiThreadTest
463 public void testDarkModeResetsExposedMenu() {
464 NotificationSwipeHelper swipeActionHelper =
465 (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
466 swipeActionHelper.setExposedMenuView(new View(mContext));
Selim Cinek195dfc52019-05-30 19:35:05 -0700467 mStackScroller.setHideAmount(0.1f, 0.1f);
Gus Prevas99ba4ba2018-10-01 16:40:23 -0400468 assertNull(swipeActionHelper.getExposedMenuView());
469 }
470
Will Brockmane718d582019-01-17 16:38:38 -0500471 class LogMatcher implements ArgumentMatcher<LogMaker> {
472 private int mCategory, mType;
473
474 LogMatcher(int category, int type) {
475 mCategory = category;
476 mType = type;
477 }
478 public boolean matches(LogMaker l) {
479 return (l.getCategory() == mCategory)
480 && (l.getType() == mType);
481 }
482
483 public String toString() {
484 return String.format("LogMaker(%d, %d)", mCategory, mType);
485 }
486 }
487
488 private LogMaker logMatcher(int category, int type) {
489 return argThat(new LogMatcher(category, type));
490 }
491
492 @Test
493 @UiThreadTest
494 public void testOnMenuClickedLogging() {
495 // Set up the object under test to have a valid mLongPressListener. We're testing an
496 // anonymous-class member, mMenuEventListener, so we need to modify the state of the
497 // class itself, not the Mockito spy copied from it. See notes in setup.
498 mStackScrollerInternal.setLongPressListener(
499 mock(ExpandableNotificationRow.LongPressListener.class));
500
501 ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
Ned Burns1c2b85a42019-11-14 15:37:03 -0500502 when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
Will Brockmane718d582019-01-17 16:38:38 -0500503 MetricsProto.MetricsEvent.VIEW_UNKNOWN));
504
505 mStackScroller.mMenuEventListener.onMenuClicked(row, 0, 0, mock(
506 NotificationMenuRowPlugin.MenuItem.class));
Ned Burns1c2b85a42019-11-14 15:37:03 -0500507 verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data
Will Brockmane718d582019-01-17 16:38:38 -0500508 verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR,
509 MetricsProto.MetricsEvent.TYPE_ACTION));
510 }
511
512 @Test
513 @UiThreadTest
Selim Cinekc3fec682019-06-06 18:11:07 -0700514 public void testOnMenuShownLogging() { ;
Will Brockmane718d582019-01-17 16:38:38 -0500515
516 ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
Ned Burns1c2b85a42019-11-14 15:37:03 -0500517 when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
Will Brockmane718d582019-01-17 16:38:38 -0500518 MetricsProto.MetricsEvent.VIEW_UNKNOWN));
519
520 mStackScroller.mMenuEventListener.onMenuShown(row);
Ned Burns1c2b85a42019-11-14 15:37:03 -0500521 verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data
Will Brockmane718d582019-01-17 16:38:38 -0500522 verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR,
523 MetricsProto.MetricsEvent.TYPE_ACTION));
524 }
525
Will Brockmanb65faa82020-03-06 10:26:04 -0500526 @Test
527 public void testClearNotifications_All() {
528 mStackScroller.clearNotifications(NotificationStackScrollLayout.ROWS_ALL, true);
529 assertEquals(1, mUiEventLoggerFake.numLogs());
530 assertEquals(NotificationStackScrollLayout.NotificationPanelEvent
531 .DISMISS_ALL_NOTIFICATIONS_PANEL.getId(), mUiEventLoggerFake.eventId(0));
532 }
533
534 @Test
535 public void testClearNotifications_Gentle() {
536 mStackScroller.clearNotifications(NotificationStackScrollLayout.ROWS_GENTLE, false);
537 assertEquals(1, mUiEventLoggerFake.numLogs());
538 assertEquals(NotificationStackScrollLayout.NotificationPanelEvent
539 .DISMISS_SILENT_NOTIFICATIONS_PANEL.getId(), mUiEventLoggerFake.eventId(0));
540 }
541
Jason Monke59dc402018-08-16 12:05:01 -0400542 private void setBarStateForTest(int state) {
Jason Monk297c04e2018-08-23 17:16:59 -0400543 // Can't inject this through the listener or we end up on the actual implementation
544 // rather than the mock because the spy just coppied the anonymous inner /shruggie.
545 mStackScroller.setStatusBarState(state);
Jason Monke59dc402018-08-16 12:05:01 -0400546 }
Evan Laird181de622019-10-24 09:53:02 -0400547
548 private void addEntriesToEntryManager(List<NotificationEntry> entries) {
549 for (NotificationEntry e : entries) {
550 mEntryManager.addActiveNotificationForTest(e);
551 }
552 }
Selim Cinek8a9308d2017-08-24 09:31:08 -0700553}