/* * 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; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AppOpsManager; import android.app.NotificationChannel; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.util.ArraySet; import android.view.NotificationHeaderView; import android.view.View; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.notification.AboveShelfChangedListener; import com.android.systemui.statusbar.stack.NotificationChildrenContainer; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.util.List; @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper(setAsMainLooper = true) public class ExpandableNotificationRowTest extends SysuiTestCase { private ExpandableNotificationRow mGroupRow; private NotificationTestHelper mNotificationTestHelper; boolean mHeadsUpAnimatingAway = false; @Rule public MockitoRule mockito = MockitoJUnit.rule(); @Mock private NotificationBlockingHelperManager mBlockingHelperManager; @Before public void setUp() throws Exception { mNotificationTestHelper = new NotificationTestHelper(mContext); mGroupRow = mNotificationTestHelper.createGroup(); mGroupRow.setHeadsUpAnimatingAwayListener( animatingAway -> mHeadsUpAnimatingAway = animatingAway); mDependency.injectTestDependency( NotificationBlockingHelperManager.class, mBlockingHelperManager); } @Test public void testGroupSummaryNotShowingIconWhenPublic() { mGroupRow.setSensitive(true, true); mGroupRow.setHideSensitiveForIntrinsicHeight(true); assertTrue(mGroupRow.isSummaryWithChildren()); assertFalse(mGroupRow.isShowingIcon()); } @Test public void testNotificationHeaderVisibleWhenAnimating() { mGroupRow.setSensitive(true, true); mGroupRow.setHideSensitive(true, false, 0, 0); mGroupRow.setHideSensitive(false, true, 0, 0); assertTrue(mGroupRow.getChildrenContainer().getVisibleHeader().getVisibility() == View.VISIBLE); } @Test public void testUserLockedResetEvenWhenNoChildren() { mGroupRow.setUserLocked(true); mGroupRow.removeAllChildren(); mGroupRow.setUserLocked(false); assertFalse("The childrencontainer should not be userlocked but is, the state " + "seems out of sync.", mGroupRow.getChildrenContainer().isUserLocked()); } @Test public void testReinflatedOnDensityChange() { mGroupRow.setUserLocked(true); mGroupRow.removeAllChildren(); mGroupRow.setUserLocked(false); NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class); mGroupRow.setChildrenContainer(mockContainer); mGroupRow.onDensityOrFontScaleChanged(); verify(mockContainer).reInflateViews(any(), any()); } @Test public void testIconColorShouldBeUpdatedWhenSensitive() throws Exception { ExpandableNotificationRow row = spy(mNotificationTestHelper.createRow()); row.setSensitive(true, true); row.setHideSensitive(true, false, 0, 0); verify(row).updateShelfIconColor(); } @Test public void testIconColorShouldBeUpdatedWhenSettingDark() throws Exception { ExpandableNotificationRow row = spy(mNotificationTestHelper.createRow()); row.setDark(true, false, 0); verify(row).updateShelfIconColor(); } @Test public void testAboveShelfChangedListenerCalled() throws Exception { ExpandableNotificationRow row = mNotificationTestHelper.createRow(); AboveShelfChangedListener listener = mock(AboveShelfChangedListener.class); row.setAboveShelfChangedListener(listener); row.setHeadsUp(true); verify(listener).onAboveShelfStateChanged(true); } @Test public void testAboveShelfChangedListenerCalledPinned() throws Exception { ExpandableNotificationRow row = mNotificationTestHelper.createRow(); AboveShelfChangedListener listener = mock(AboveShelfChangedListener.class); row.setAboveShelfChangedListener(listener); row.setPinned(true); verify(listener).onAboveShelfStateChanged(true); } @Test public void testAboveShelfChangedListenerCalledHeadsUpGoingAway() throws Exception { ExpandableNotificationRow row = mNotificationTestHelper.createRow(); AboveShelfChangedListener listener = mock(AboveShelfChangedListener.class); row.setAboveShelfChangedListener(listener); row.setHeadsUpAnimatingAway(true); verify(listener).onAboveShelfStateChanged(true); } @Test public void testAboveShelfChangedListenerCalledWhenGoingBelow() throws Exception { ExpandableNotificationRow row = mNotificationTestHelper.createRow(); row.setHeadsUp(true); AboveShelfChangedListener listener = mock(AboveShelfChangedListener.class); row.setAboveShelfChangedListener(listener); row.setAboveShelf(false); verify(listener).onAboveShelfStateChanged(false); } @Test public void testClickSound() throws Exception { assertTrue("Should play sounds by default.", mGroupRow.isSoundEffectsEnabled()); mGroupRow.setDark(true /* dark */, false /* fade */, 0 /* delay */); mGroupRow.setSecureStateProvider(()-> false); assertFalse("Shouldn't play sounds when dark and trusted.", mGroupRow.isSoundEffectsEnabled()); mGroupRow.setSecureStateProvider(()-> true); assertTrue("Should always play sounds when not trusted.", mGroupRow.isSoundEffectsEnabled()); } @Test public void testSetDismissed_longPressListenerRemoved() { ExpandableNotificationRow.LongPressListener listener = mock(ExpandableNotificationRow.LongPressListener.class); mGroupRow.setLongPressListener(listener); mGroupRow.doLongClickCallback(0,0); verify(listener, times(1)).onLongPress(eq(mGroupRow), eq(0), eq(0), any(NotificationMenuRowPlugin.MenuItem.class)); reset(listener); mGroupRow.setDismissed(true); mGroupRow.doLongClickCallback(0,0); verify(listener, times(0)).onLongPress(eq(mGroupRow), eq(0), eq(0), any(NotificationMenuRowPlugin.MenuItem.class)); } @Test public void testShowAppOps_noHeader() { // public notification is custom layout - no header mGroupRow.setSensitive(true, true); mGroupRow.setAppOpsOnClickListener(null); mGroupRow.showAppOpsIcons(null); } @Test public void testShowAppOpsIcons_header() { NotificationHeaderView mockHeader = mock(NotificationHeaderView.class); NotificationContentView publicLayout = mock(NotificationContentView.class); mGroupRow.setPublicLayout(publicLayout); NotificationContentView privateLayout = mock(NotificationContentView.class); mGroupRow.setPrivateLayout(privateLayout); NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class); when(mockContainer.getNotificationChildCount()).thenReturn(1); when(mockContainer.getHeaderView()).thenReturn(mockHeader); mGroupRow.setChildrenContainer(mockContainer); ArraySet ops = new ArraySet<>(); ops.add(AppOpsManager.OP_ANSWER_PHONE_CALLS); mGroupRow.showAppOpsIcons(ops); verify(mockHeader, times(1)).showAppOpsIcons(ops); verify(privateLayout, times(1)).showAppOpsIcons(ops); verify(publicLayout, times(1)).showAppOpsIcons(ops); } @Test public void testAppOpsOnClick() { ExpandableNotificationRow.OnAppOpsClickListener l = mock( ExpandableNotificationRow.OnAppOpsClickListener.class); View view = mock(View.class); mGroupRow.setAppOpsOnClickListener(l); mGroupRow.getAppOpsOnClickListener().onClick(view); verify(l, times(1)).onClick(any(), anyInt(), anyInt(), any()); } @Test public void testHeadsUpAnimatingAwayListener() { mGroupRow.setHeadsUpAnimatingAway(true); Assert.assertEquals(true, mHeadsUpAnimatingAway); mGroupRow.setHeadsUpAnimatingAway(false); Assert.assertEquals(false, mHeadsUpAnimatingAway); } @Test public void testPerformDismissWithBlockingHelper_falseWhenBlockingHelperIsntShown() { when(mBlockingHelperManager.perhapsShowBlockingHelper( eq(mGroupRow), any(NotificationMenuRowPlugin.class))).thenReturn(false); assertFalse( mGroupRow.performDismissWithBlockingHelper(false /* fromAccessibility */)); } @Test public void testPerformDismissWithBlockingHelper_doesntPerformOnGroupSummary() { ExpandableNotificationRow childRow = mGroupRow.getChildrenContainer().getViewAtPosition(0); when(mBlockingHelperManager.perhapsShowBlockingHelper(eq(childRow), any(NotificationMenuRowPlugin.class))) .thenReturn(true); assertTrue( childRow.performDismissWithBlockingHelper(false /* fromAccessibility */)); verify(mBlockingHelperManager, times(1)) .perhapsShowBlockingHelper(eq(childRow), any(NotificationMenuRowPlugin.class)); verify(mBlockingHelperManager, times(0)) .perhapsShowBlockingHelper(eq(mGroupRow), any(NotificationMenuRowPlugin.class)); } @Test public void testIsBlockingHelperShowing_isCorrectlyUpdated() { mGroupRow.setBlockingHelperShowing(true); assertTrue(mGroupRow.isBlockingHelperShowing()); mGroupRow.setBlockingHelperShowing(false); assertFalse(mGroupRow.isBlockingHelperShowing()); } @Test public void testGetNumUniqueChildren_defaultChannel() { assertEquals(1, mGroupRow.getNumUniqueChannels()); } @Test public void testGetNumUniqueChildren_multiChannel() { List childRows = mGroupRow.getChildrenContainer().getNotificationChildren(); // Give each child a unique channel id/name. int i = 0; for (ExpandableNotificationRow childRow : childRows) { childRow.getEntry().channel = new NotificationChannel("id" + i, "dinnertime" + i, IMPORTANCE_DEFAULT); i++; } assertEquals(3, mGroupRow.getNumUniqueChannels()); } @Test public void testIconScrollXAfterTranslationAndReset() throws Exception { mGroupRow.setTranslation(50); assertEquals(50, -mGroupRow.getEntry().expandedIcon.getScrollX()); mGroupRow.resetTranslation(); assertEquals(0, mGroupRow.getEntry().expandedIcon.getScrollX()); } }