blob: c19188c9b7c0b7147ba662ebd109eaabb06c2727 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.statusbar.notification.stack;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.Looper;
import android.os.PowerManager;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarTest.TestableNotificationEntryManager;
import java.util.ArrayList;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
/**
* Tests for {@link NotificationStackScrollLayout}.
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
public class NotificationStackScrollLayoutTest extends SysuiTestCase {
private NotificationStackScrollLayout mStackScroller;
@Rule public MockitoRule mockito = MockitoJUnit.rule();
@Mock private StatusBar mBar;
@Mock private StatusBarStateController mBarState;
@Mock private HeadsUpManagerPhone mHeadsUpManager;
@Mock private NotificationBlockingHelperManager mBlockingHelperManager;
@Mock private NotificationGroupManager mGroupManager;
@Mock private ExpandHelper mExpandHelper;
@Mock private EmptyShadeView mEmptyShadeView;
@Mock private NotificationData mNotificationData;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@Mock private RemoteInputController mRemoteInputController;
@Mock private SystemServicesProxy mSystemServicesProxy;
private PowerManager mPowerManager;
private TestableNotificationEntryManager mEntryManager;
@Before
@UiThreadTest
public void setUp() throws Exception {
// Inject dependencies before initializing the layout
mDependency.injectTestDependency(
NotificationBlockingHelperManager.class,
mBlockingHelperManager);
mDependency.injectTestDependency(StatusBarStateController.class, mBarState);
mDependency.injectTestDependency(NotificationRemoteInputManager.class,
mRemoteInputManager);
when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
IPowerManager powerManagerService = mock(IPowerManager.class);
mPowerManager = new PowerManager(mContext, powerManagerService,
Handler.createAsync(Looper.myLooper()));
mEntryManager = new TestableNotificationEntryManager(mSystemServicesProxy, mPowerManager,
mContext);
mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, null, null, mNotificationData);
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
NotificationShelf notificationShelf = spy(new NotificationShelf(getContext(), null));
mStackScroller = spy(new NotificationStackScrollLayout(getContext()));
mStackScroller.setShelf(notificationShelf);
mStackScroller.setStatusBar(mBar);
mStackScroller.setScrimController(mock(ScrimController.class));
mStackScroller.setHeadsUpManager(mHeadsUpManager);
mStackScroller.setGroupManager(mGroupManager);
mStackScroller.setEmptyShadeView(mEmptyShadeView);
// Stub out functionality that isn't necessary to test.
doNothing().when(mBar)
.executeRunnableDismissingKeyguard(any(Runnable.class),
any(Runnable.class),
anyBoolean(),
anyBoolean(),
anyBoolean());
doNothing().when(mGroupManager).collapseAllGroups();
doNothing().when(mExpandHelper).cancelImmediately();
doNothing().when(notificationShelf).setAnimationsEnabled(anyBoolean());
doNothing().when(notificationShelf).fadeInTranslating();
}
@Test
public void testNotDimmedOnKeyguard() {
when(mBarState.getState()).thenReturn(StatusBarState.SHADE);
mStackScroller.setDimmed(true /* dimmed */, false /* animate */);
mStackScroller.setDimmed(true /* dimmed */, true /* animate */);
Assert.assertFalse(mStackScroller.isDimmed());
}
@Test
public void testAntiBurnInOffset() {
final int burnInOffset = 30;
mStackScroller.setAntiBurnInOffsetX(burnInOffset);
mStackScroller.setDark(false /* dark */, false /* animated */, null /* touch */);
Assert.assertEquals(0 /* expected */, mStackScroller.getTranslationX(), 0.01 /* delta */);
mStackScroller.setDark(true /* dark */, false /* animated */, null /* touch */);
Assert.assertEquals(burnInOffset /* expected */, mStackScroller.getTranslationX(),
0.01 /* delta */);
}
@Test
public void updateEmptyView_dndSuppressing() {
when(mEmptyShadeView.willBeGone()).thenReturn(true);
when(mBar.areNotificationsHidden()).thenReturn(true);
mStackScroller.updateEmptyShadeView(true);
verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
}
@Test
public void updateEmptyView_dndNotSuppressing() {
mStackScroller.setEmptyShadeView(mEmptyShadeView);
when(mEmptyShadeView.willBeGone()).thenReturn(true);
when(mBar.areNotificationsHidden()).thenReturn(false);
mStackScroller.updateEmptyShadeView(true);
verify(mEmptyShadeView).setText(R.string.empty_shade_text);
}
@Test
public void updateEmptyView_noNotificationsToDndSuppressing() {
mStackScroller.setEmptyShadeView(mEmptyShadeView);
when(mEmptyShadeView.willBeGone()).thenReturn(true);
when(mBar.areNotificationsHidden()).thenReturn(false);
mStackScroller.updateEmptyShadeView(true);
verify(mEmptyShadeView).setText(R.string.empty_shade_text);
when(mBar.areNotificationsHidden()).thenReturn(true);
mStackScroller.updateEmptyShadeView(true);
verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
}
@Test
@UiThreadTest
public void testSetExpandedHeight_blockingHelperManagerReceivedCallbacks() {
mStackScroller.setExpandedHeight(0f);
verify(mBlockingHelperManager).setNotificationShadeExpanded(0f);
reset(mBlockingHelperManager);
mStackScroller.setExpandedHeight(100f);
verify(mBlockingHelperManager).setNotificationShadeExpanded(100f);
}
@Test
public void manageNotifications_visible() {
FooterView view = mock(FooterView.class);
mStackScroller.setFooterView(view);
when(view.willBeGone()).thenReturn(true);
mStackScroller.updateFooterView(true, false);
verify(view).setVisible(eq(true), anyBoolean());
verify(view).setSecondaryVisible(eq(false), anyBoolean());
}
@Test
public void clearAll_visible() {
FooterView view = mock(FooterView.class);
mStackScroller.setFooterView(view);
when(view.willBeGone()).thenReturn(true);
mStackScroller.updateFooterView(true, true);
verify(view).setVisible(eq(true), anyBoolean());
verify(view).setSecondaryVisible(eq(true), anyBoolean());
}
@Test
public void testInflateFooterView() {
mStackScroller.inflateFooterView();
ArgumentCaptor<FooterView> captor = ArgumentCaptor.forClass(FooterView.class);
verify(mStackScroller).setFooterView(captor.capture());
assertNotNull(captor.getValue().findViewById(R.id.manage_text).hasOnClickListeners());
assertNotNull(captor.getValue().findViewById(R.id.dismiss_text).hasOnClickListeners());
}
@Test
public void testUpdateFooter_noNotifications() {
setBarStateForTest(StatusBarState.SHADE);
assertEquals(0, mNotificationData.getActiveNotifications().size());
mStackScroller.updateFooter();
verify(mStackScroller).updateFooterView(false, false);
}
@Test
public void testUpdateFooter_remoteInput() {
setBarStateForTest(StatusBarState.SHADE);
ArrayList<Entry> entries = new ArrayList<>();
entries.add(mock(Entry.class));
when(mNotificationData.getActiveNotifications()).thenReturn(entries);
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
when(row.canViewBeDismissed()).thenReturn(true);
when(mStackScroller.getChildCount()).thenReturn(1);
when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
when(mRemoteInputController.isRemoteInputActive()).thenReturn(true);
mStackScroller.updateFooter();
verify(mStackScroller).updateFooterView(false, true);
}
@Test
public void testUpdateFooter_oneClearableNotification() {
setBarStateForTest(StatusBarState.SHADE);
ArrayList<Entry> entries = new ArrayList<>();
entries.add(mock(Entry.class));
when(mNotificationData.getActiveNotifications()).thenReturn(entries);
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
when(row.canViewBeDismissed()).thenReturn(true);
when(mStackScroller.getChildCount()).thenReturn(1);
when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
mStackScroller.updateFooter();
verify(mStackScroller).updateFooterView(true, true);
}
@Test
public void testUpdateFooter_oneNonClearableNotification() {
setBarStateForTest(StatusBarState.SHADE);
ArrayList<Entry> entries = new ArrayList<>();
entries.add(mock(Entry.class));
when(mNotificationData.getActiveNotifications()).thenReturn(entries);
mStackScroller.updateFooter();
verify(mStackScroller).updateFooterView(true, false);
}
@Test
public void testUpdateFooter_atEnd() {
// add footer
mStackScroller.inflateFooterView();
// add notification
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
when(row.isClearable()).thenReturn(true);
mStackScroller.addContainerView(row);
mStackScroller.onUpdateRowStates();
// move footer to end
verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(-1 /* end */));
}
@Test
public void testOnDensityOrFontScaleChanged_reInflatesFooterViews() {
clearInvocations(mStackScroller);
mStackScroller.onDensityOrFontScaleChanged();
verify(mStackScroller).setFooterView(any());
verify(mStackScroller).setEmptyShadeView(any());
}
private void setBarStateForTest(int state) {
ArgumentCaptor<StatusBarStateController.StateListener> captor =
ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
verify(mBarState).addListener(captor.capture());
captor.getValue().onStateChanged(state);
}
}