From 9512e0c7553aac1b12b350886ec35ba796a1c4ba Mon Sep 17 00:00:00 2001 From: Ned Burns Date: Thu, 30 May 2019 19:36:04 -0400 Subject: [PATCH] Allow notification reordering after user adjusts importance After the user adjusts the priority of a notification, we need to temporarily lift the VisualStabilityManager's ban on reordering to allow the priority adjustment to take effect. There's no clear signal as to when this reprieve should end -- eventually, we'll get a ranking update, but there's no way to tell that it was the update that our change triggered. So instead we just wait for 1000ms and then drop the adjustment ban again. If a few extra reorders slip in during that time, so be it. Test: atest, manual Bug: 129772718 Change-Id: Iefb6917bb41935ed6bfc720b51738c66ffa83457 --- .../notification/VisualStabilityManager.java | 62 +- .../row/NotificationGutsManager.java | 8 +- .../notification/row/NotificationInfo.java | 8 +- .../VisualStabilityManagerTest.java | 111 ++- .../row/NotificationGutsManagerTest.java | 10 +- .../row/NotificationInfoTest.java | 870 ++++++++++++++---- 6 files changed, 854 insertions(+), 215 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java index 396a3a7834fb8..4a6c7d27516c8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java @@ -16,18 +16,26 @@ package com.android.systemui.statusbar.notification; +import static com.android.systemui.Dependency.MAIN_HANDLER_NAME; + +import android.os.Handler; +import android.os.SystemClock; import android.view.View; import androidx.collection.ArraySet; +import com.android.systemui.Dumpable; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.ArrayList; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; /** @@ -35,14 +43,19 @@ import javax.inject.Singleton; * and reorder at the right time when they are out of view. */ @Singleton -public class VisualStabilityManager implements OnHeadsUpChangedListener { +public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpable { + + private static final long TEMPORARY_REORDERING_ALLOWED_DURATION = 1000; private final ArrayList mCallbacks = new ArrayList<>(); + private final Handler mHandler; private NotificationPresenter mPresenter; private boolean mPanelExpanded; private boolean mScreenOn; private boolean mReorderingAllowed; + private boolean mIsTemporaryReorderingAllowed; + private long mTemporaryReorderingStart; private VisibilityLocationProvider mVisibilityLocationProvider; private ArraySet mAllowedReorderViews = new ArraySet<>(); private ArraySet mLowPriorityReorderingViews = new ArraySet<>(); @@ -50,7 +63,12 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener { private boolean mPulsing; @Inject - public VisualStabilityManager(NotificationEntryManager notificationEntryManager) { + public VisualStabilityManager( + NotificationEntryManager notificationEntryManager, + @Named(MAIN_HANDLER_NAME) Handler handler) { + + mHandler = handler; + notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() { @Override public void onPreEntryUpdated(NotificationEntry entry) { @@ -114,10 +132,11 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener { } private void updateReorderingAllowed() { - boolean reorderingAllowed = (!mScreenOn || !mPanelExpanded) && !mPulsing; - boolean changed = reorderingAllowed && !mReorderingAllowed; + boolean reorderingAllowed = + (!mScreenOn || !mPanelExpanded || mIsTemporaryReorderingAllowed) && !mPulsing; + boolean changedToTrue = reorderingAllowed && !mReorderingAllowed; mReorderingAllowed = reorderingAllowed; - if (changed) { + if (changedToTrue) { notifyCallbacks(); } } @@ -179,6 +198,25 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener { } } + /** + * Temporarily allows reordering of the entire shade for a period of 1000ms. Subsequent calls + * to this method will extend the timer. + */ + public void temporarilyAllowReordering() { + mHandler.removeCallbacks(mOnTemporaryReorderingExpired); + mHandler.postDelayed(mOnTemporaryReorderingExpired, TEMPORARY_REORDERING_ALLOWED_DURATION); + if (!mIsTemporaryReorderingAllowed) { + mTemporaryReorderingStart = SystemClock.elapsedRealtime(); + } + mIsTemporaryReorderingAllowed = true; + updateReorderingAllowed(); + } + + private final Runnable mOnTemporaryReorderingExpired = () -> { + mIsTemporaryReorderingAllowed = false; + updateReorderingAllowed(); + }; + /** * Notify the visual stability manager that a new view was added and should be allowed to * reorder next time. @@ -187,6 +225,20 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener { mAddedChildren.add(view); } + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("VisualStabilityManager state:"); + pw.print(" mIsTemporaryReorderingAllowed="); pw.println(mIsTemporaryReorderingAllowed); + pw.print(" mTemporaryReorderingStart="); pw.println(mTemporaryReorderingStart); + + long now = SystemClock.elapsedRealtime(); + pw.print(" Temporary reordering window has been open for "); + pw.print(now - (mIsTemporaryReorderingAllowed ? mTemporaryReorderingStart : now)); + pw.println("ms"); + + pw.println(); + } + public interface Callback { /** * Called when reordering is allowed again. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index f15d6b75020f9..fe890fb3b471d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -48,6 +48,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.NotificationActivityStarter; +import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -73,6 +74,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); private final Context mContext; + private final VisualStabilityManager mVisualStabilityManager; private final AccessibilityManager mAccessibilityManager; // Dependencies: @@ -96,8 +98,11 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx protected String mKeyToRemoveOnGutsClosed; @Inject - public NotificationGutsManager(Context context) { + public NotificationGutsManager( + Context context, + VisualStabilityManager visualStabilityManager) { mContext = context; + mVisualStabilityManager = visualStabilityManager; mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); } @@ -304,6 +309,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx notificationInfoView.bindNotification( pmUser, iNotificationManager, + mVisualStabilityManager, packageName, row.getEntry().channel, row.getUniqueChannels(), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java index 1dc96b82f4a58..ac24bbd6bc833 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java @@ -65,6 +65,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.logging.NotificationCounters; import java.lang.annotation.Retention; @@ -104,6 +105,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private INotificationManager mINotificationManager; private PackageManager mPm; private MetricsLogger mMetricsLogger; + private VisualStabilityManager mVisualStabilityManager; private ChannelEditorDialogController mChannelEditorDialogController; private String mPackageName; @@ -244,6 +246,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G void bindNotification( final PackageManager pm, final INotificationManager iNotificationManager, + final VisualStabilityManager visualStabilityManager, final String pkg, final NotificationChannel notificationChannel, final Set uniqueChannelsInRow, @@ -256,7 +259,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G int importance, boolean wasShownHighPriority) throws RemoteException { - bindNotification(pm, iNotificationManager, pkg, notificationChannel, + bindNotification(pm, iNotificationManager, visualStabilityManager, pkg, notificationChannel, uniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick, onAppSettingsClick, isDeviceProvisioned, isNonblockable, false /* isBlockingHelper */, @@ -266,6 +269,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G public void bindNotification( PackageManager pm, INotificationManager iNotificationManager, + VisualStabilityManager visualStabilityManager, String pkg, NotificationChannel notificationChannel, Set uniqueChannelsInRow, @@ -281,6 +285,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G throws RemoteException { mINotificationManager = iNotificationManager; mMetricsLogger = Dependency.get(MetricsLogger.class); + mVisualStabilityManager = visualStabilityManager; mChannelEditorDialogController = Dependency.get(ChannelEditorDialogController.class); mPackageName = pkg; mUniqueChannelsInRow = uniqueChannelsInRow; @@ -537,6 +542,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G new UpdateImportanceRunnable(mINotificationManager, mPackageName, mAppUid, mNumUniqueChannelsInRow == 1 ? mSingleNotificationChannel : null, mStartingChannelImportance, newImportance)); + mVisualStabilityManager.temporarilyAllowReordering(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java index b35dcb62136c5..dd2630bc3417a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java @@ -16,17 +16,20 @@ package com.android.systemui.statusbar.notification; -import static junit.framework.Assert.assertEquals; - -import static org.mockito.Matchers.anyObject; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.os.Handler; import android.service.notification.StatusBarNotification; -import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationPresenter; @@ -38,11 +41,13 @@ import org.junit.Test; import org.junit.runner.RunWith; @SmallTest -@RunWith(AndroidJUnit4.class) +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper() public class VisualStabilityManagerTest extends SysuiTestCase { - private VisualStabilityManager mVisualStabilityManager = new VisualStabilityManager( - mock(NotificationEntryManager.class)); + private TestableLooper mTestableLooper; + + private VisualStabilityManager mVisualStabilityManager; private VisualStabilityManager.Callback mCallback = mock(VisualStabilityManager.Callback.class); private VisibilityLocationProvider mLocationProvider = mock(VisibilityLocationProvider.class); private ExpandableNotificationRow mRow = mock(ExpandableNotificationRow.class); @@ -50,46 +55,53 @@ public class VisualStabilityManagerTest extends SysuiTestCase { @Before public void setUp() { + mTestableLooper = TestableLooper.get(this); + mVisualStabilityManager = new VisualStabilityManager( + mock(NotificationEntryManager.class), + new Handler(mTestableLooper.getLooper())); + mVisualStabilityManager.setUpWithPresenter(mock(NotificationPresenter.class)); mVisualStabilityManager.setVisibilityLocationProvider(mLocationProvider); mEntry = new NotificationEntry(mock(StatusBarNotification.class)); mEntry.setRow(mRow); + + when(mRow.getEntry()).thenReturn(mEntry); } @Test public void testPanelExpansion() { mVisualStabilityManager.setPanelExpanded(true); mVisualStabilityManager.setScreenOn(true); - assertEquals(mVisualStabilityManager.canReorderNotification(mRow), false); + assertFalse(mVisualStabilityManager.canReorderNotification(mRow)); mVisualStabilityManager.setPanelExpanded(false); - assertEquals(mVisualStabilityManager.canReorderNotification(mRow), true); + assertTrue(mVisualStabilityManager.canReorderNotification(mRow)); } @Test public void testScreenOn() { mVisualStabilityManager.setPanelExpanded(true); mVisualStabilityManager.setScreenOn(true); - assertEquals(mVisualStabilityManager.canReorderNotification(mRow), false); + assertFalse(mVisualStabilityManager.canReorderNotification(mRow)); mVisualStabilityManager.setScreenOn(false); - assertEquals(mVisualStabilityManager.canReorderNotification(mRow), true); + assertTrue(mVisualStabilityManager.canReorderNotification(mRow)); } @Test public void testReorderingAllowedChangesScreenOn() { mVisualStabilityManager.setPanelExpanded(true); mVisualStabilityManager.setScreenOn(true); - assertEquals(mVisualStabilityManager.isReorderingAllowed(), false); + assertFalse(mVisualStabilityManager.isReorderingAllowed()); mVisualStabilityManager.setScreenOn(false); - assertEquals(mVisualStabilityManager.isReorderingAllowed(), true); + assertTrue(mVisualStabilityManager.isReorderingAllowed()); } @Test public void testReorderingAllowedChangesPanel() { mVisualStabilityManager.setPanelExpanded(true); mVisualStabilityManager.setScreenOn(true); - assertEquals(mVisualStabilityManager.isReorderingAllowed(), false); + assertFalse(mVisualStabilityManager.isReorderingAllowed()); mVisualStabilityManager.setPanelExpanded(false); - assertEquals(mVisualStabilityManager.isReorderingAllowed(), true); + assertTrue(mVisualStabilityManager.isReorderingAllowed()); } @Test @@ -126,51 +138,51 @@ public class VisualStabilityManagerTest extends SysuiTestCase { mVisualStabilityManager.setPanelExpanded(true); mVisualStabilityManager.setScreenOn(true); mVisualStabilityManager.notifyViewAddition(mRow); - assertEquals(mVisualStabilityManager.canReorderNotification(mRow), true); + assertTrue(mVisualStabilityManager.canReorderNotification(mRow)); } @Test public void testReorderingVisibleHeadsUpNotAllowed() { mVisualStabilityManager.setPanelExpanded(true); mVisualStabilityManager.setScreenOn(true); - when(mLocationProvider.isInVisibleLocation(anyObject())).thenReturn(true); + when(mLocationProvider.isInVisibleLocation(any(NotificationEntry.class))).thenReturn(true); mVisualStabilityManager.onHeadsUpStateChanged(mEntry, true); - assertEquals(mVisualStabilityManager.canReorderNotification(mRow), false); + assertFalse(mVisualStabilityManager.canReorderNotification(mRow)); } @Test public void testReorderingVisibleHeadsUpAllowed() { mVisualStabilityManager.setPanelExpanded(true); mVisualStabilityManager.setScreenOn(true); - when(mLocationProvider.isInVisibleLocation(anyObject())).thenReturn(false); + when(mLocationProvider.isInVisibleLocation(any(NotificationEntry.class))).thenReturn(false); mVisualStabilityManager.onHeadsUpStateChanged(mEntry, true); - assertEquals(mVisualStabilityManager.canReorderNotification(mRow), true); + assertTrue(mVisualStabilityManager.canReorderNotification(mRow)); } @Test public void testReorderingVisibleHeadsUpAllowedOnce() { mVisualStabilityManager.setPanelExpanded(true); mVisualStabilityManager.setScreenOn(true); - when(mLocationProvider.isInVisibleLocation(anyObject())).thenReturn(false); + when(mLocationProvider.isInVisibleLocation(any(NotificationEntry.class))).thenReturn(false); mVisualStabilityManager.onHeadsUpStateChanged(mEntry, true); mVisualStabilityManager.onReorderingFinished(); - assertEquals(mVisualStabilityManager.canReorderNotification(mRow), false); + assertFalse(mVisualStabilityManager.canReorderNotification(mRow)); } @Test public void testPulsing() { mVisualStabilityManager.setPulsing(true); - assertEquals(mVisualStabilityManager.canReorderNotification(mRow), false); + assertFalse(mVisualStabilityManager.canReorderNotification(mRow)); mVisualStabilityManager.setPulsing(false); - assertEquals(mVisualStabilityManager.canReorderNotification(mRow), true); + assertTrue(mVisualStabilityManager.canReorderNotification(mRow)); } @Test public void testReorderingAllowedChanges_Pulsing() { mVisualStabilityManager.setPulsing(true); - assertEquals(mVisualStabilityManager.isReorderingAllowed(), false); + assertFalse(mVisualStabilityManager.isReorderingAllowed()); mVisualStabilityManager.setPulsing(false); - assertEquals(mVisualStabilityManager.isReorderingAllowed(), true); + assertTrue(mVisualStabilityManager.isReorderingAllowed()); } @Test @@ -180,4 +192,49 @@ public class VisualStabilityManagerTest extends SysuiTestCase { mVisualStabilityManager.setPulsing(false); verify(mCallback).onReorderingAllowed(); } + + @Test + public void testTemporarilyAllowReorderingNotifiesCallbacks() { + // GIVEN having the panel open (which would block reordering) + mVisualStabilityManager.setScreenOn(true); + mVisualStabilityManager.setPanelExpanded(true); + mVisualStabilityManager.addReorderingAllowedCallback(mCallback); + + // WHEN we temprarily allow reordering + mVisualStabilityManager.temporarilyAllowReordering(); + + // THEN callbacks are notified that reordering is allowed + verify(mCallback).onReorderingAllowed(); + assertTrue(mVisualStabilityManager.isReorderingAllowed()); + } + + @Test + public void testTemporarilyAllowReorderingDoesntOverridePulsing() { + // GIVEN we are in a pulsing state + mVisualStabilityManager.setPulsing(true); + mVisualStabilityManager.addReorderingAllowedCallback(mCallback); + + // WHEN we temprarily allow reordering + mVisualStabilityManager.temporarilyAllowReordering(); + + // THEN reordering is still not allowed + verify(mCallback, never()).onReorderingAllowed(); + assertFalse(mVisualStabilityManager.isReorderingAllowed()); + } + + @Test + public void testTemporarilyAllowReorderingExpires() { + // GIVEN having the panel open (which would block reordering) + mVisualStabilityManager.setScreenOn(true); + mVisualStabilityManager.setPanelExpanded(true); + mVisualStabilityManager.addReorderingAllowedCallback(mCallback); + + // WHEN we temprarily allow reordering and then wait until the window expires + mVisualStabilityManager.temporarilyAllowReordering(); + assertTrue(mVisualStabilityManager.isReorderingAllowed()); + mTestableLooper.processMessages(1); + + // THEN reordering is no longer allowed + assertFalse(mVisualStabilityManager.isReorderingAllowed()); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index 6376bd3e00e47..ef13b61162c5f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -63,6 +63,7 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationTestHelper; import com.android.systemui.statusbar.notification.NotificationActivityStarter; +import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; @@ -97,6 +98,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Rule public MockitoRule mockito = MockitoJUnit.rule(); @Mock private MetricsLogger mMetricsLogger; + @Mock private VisualStabilityManager mVisualStabilityManager; @Mock private NotificationPresenter mPresenter; @Mock private NotificationActivityStarter mNotificationActivityStarter; @Mock private NotificationStackScrollLayout mStackScroller; @@ -111,11 +113,12 @@ public class NotificationGutsManagerTest extends SysuiTestCase { mDependency.injectTestDependency(DeviceProvisionedController.class, mDeviceProvisionedController); mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger); + mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager); mHandler = Handler.createAsync(mTestableLooper.getLooper()); mHelper = new NotificationTestHelper(mContext); - mGutsManager = new NotificationGutsManager(mContext); + mGutsManager = new NotificationGutsManager(mContext, mVisualStabilityManager); mGutsManager.setUpWithPresenter(mPresenter, mStackScroller, mCheckSaveListener, mOnSettingsClickListener); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); @@ -316,6 +319,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { verify(notificationInfoView).bindNotification( any(PackageManager.class), any(INotificationManager.class), + eq(mVisualStabilityManager), eq(statusBarNotification.getPackageName()), any(NotificationChannel.class), anySet(), @@ -344,6 +348,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { verify(notificationInfoView).bindNotification( any(PackageManager.class), any(INotificationManager.class), + eq(mVisualStabilityManager), eq(statusBarNotification.getPackageName()), any(NotificationChannel.class), anySet(), @@ -374,6 +379,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { verify(notificationInfoView).bindNotification( any(PackageManager.class), any(INotificationManager.class), + eq(mVisualStabilityManager), eq(statusBarNotification.getPackageName()), any(NotificationChannel.class), anySet(), @@ -403,6 +409,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { verify(notificationInfoView).bindNotification( any(PackageManager.class), any(INotificationManager.class), + eq(mVisualStabilityManager), eq(statusBarNotification.getPackageName()), any(NotificationChannel.class), anySet(), @@ -431,6 +438,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { verify(notificationInfoView).bindNotification( any(PackageManager.class), any(INotificationManager.class), + eq(mVisualStabilityManager), eq(statusBarNotification.getPackageName()), any(NotificationChannel.class), anySet(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java index 06acc73ac48ca..655dbb679f159 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java @@ -72,6 +72,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.notification.VisualStabilityManager; import org.junit.After; import org.junit.Before; @@ -116,6 +117,8 @@ public class NotificationInfoTest extends SysuiTestCase { private PackageManager mMockPackageManager; @Mock private NotificationBlockingHelperManager mBlockingHelperManager; + @Mock + private VisualStabilityManager mVisualStabilityManager; @Before public void setUp() throws Exception { @@ -193,11 +196,21 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testBindNotification_SetsTextApplicationName() throws Exception { when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name"); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, - null, null, null, - true, false, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); final TextView textView = mNotificationInfo.findViewById(R.id.pkgname); assertTrue(textView.getText().toString().contains("App Name")); assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility()); @@ -208,20 +221,42 @@ public class NotificationInfoTest extends SysuiTestCase { final Drawable iconDrawable = mock(Drawable.class); when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class))) .thenReturn(iconDrawable); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, - null, null, null, true, false, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); final ImageView iconView = mNotificationInfo.findViewById(R.id.pkgicon); assertEquals(iconDrawable, iconView.getDrawable()); } @Test public void testBindNotification_noDelegate() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, - null, null, null, true, false, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name); assertEquals(GONE, nameView.getVisibility()); final TextView dividerView = mNotificationInfo.findViewById(R.id.pkg_divider); @@ -238,10 +273,21 @@ public class NotificationInfoTest extends SysuiTestCase { applicationInfo); when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Other"); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name); assertEquals(VISIBLE, nameView.getVisibility()); assertTrue(nameView.getText().toString().contains("Proxied")); @@ -251,10 +297,21 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name); assertEquals(GONE, groupNameView.getVisibility()); } @@ -267,10 +324,21 @@ public class NotificationInfoTest extends SysuiTestCase { when(mMockINotificationManager.getNotificationChannelGroupForPackage( eq("test_group_id"), eq(TEST_PACKAGE_NAME), eq(TEST_UID))) .thenReturn(notificationChannelGroup); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name); assertEquals(View.VISIBLE, groupNameView.getVisibility()); assertEquals("Test Group Name", groupNameView.getText()); @@ -278,19 +346,42 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testBindNotification_SetsTextChannelName() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); final TextView textView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(TEST_CHANNEL_NAME, textView.getText()); } @Test public void testBindNotification_DefaultChannelDoesNotUseChannelName() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mDefaultNotificationChannel, mDefaultNotificationChannelSet, - mSbn, null, null, null, true, false, IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mDefaultNotificationChannel, + mDefaultNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); final TextView textView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(GONE, textView.getVisibility()); } @@ -301,30 +392,64 @@ public class NotificationInfoTest extends SysuiTestCase { // Package has one channel by default. when(mMockINotificationManager.getNumNotificationChannelsForPackage( eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(10); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mDefaultNotificationChannel, mDefaultNotificationChannelSet, - mSbn, null, null, null, true, - false, IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mDefaultNotificationChannel, + mDefaultNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); final TextView textView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(VISIBLE, textView.getVisibility()); } @Test public void testBindNotification_UnblockablePackageUsesChannelName() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, true, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + true, + IMPORTANCE_DEFAULT, + true); final TextView textView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(VISIBLE, textView.getVisibility()); } @Test public void testBindNotification_BlockLink_BlockingHelper() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, mock( - NotificationInfo.OnSettingsClickListener.class), null, true, false, - true /* isBlockingHelper */, IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + mock(NotificationInfo.OnSettingsClickListener.class), + null, + true, + false, + true /* isBlockingHelper */, + IMPORTANCE_DEFAULT, + true); final View block = mNotificationInfo.findViewById(R.id.blocking_helper_turn_off_notifications); final View interruptivenessSettings = mNotificationInfo.findViewById( @@ -336,12 +461,24 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testBindNotification_SetsOnClickListenerForSettings() throws Exception { final CountDownLatch latch = new CountDownLatch(1); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, (View v, NotificationChannel c, int appUid) -> { assertEquals(mNotificationChannel, c); latch.countDown(); - }, null, true, false, IMPORTANCE_DEFAULT, true); + }, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); final View settingsButton = mNotificationInfo.findViewById(R.id.info); settingsButton.performClick(); @@ -351,10 +488,21 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertTrue(settingsButton.getVisibility() != View.VISIBLE); } @@ -362,36 +510,80 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testBindNotification_SettingsButtonInvisibleWhenDeviceUnprovisioned() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, (View v, NotificationChannel c, int appUid) -> { assertEquals(mNotificationChannel, c); - }, null, false, false, IMPORTANCE_DEFAULT, true); + }, + null, + false, + false, + IMPORTANCE_DEFAULT, + true); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertTrue(settingsButton.getVisibility() != View.VISIBLE); } @Test public void testBindNotification_SettingsButtonReappearsAfterSecondBind() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_DEFAULT, true); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, - (View v, NotificationChannel c, int appUid) -> { - }, null, true, false, IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + (View v, NotificationChannel c, int appUid) -> { }, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertEquals(View.VISIBLE, settingsButton.getVisibility()); } @Test public void testBindNotificationLogging_notBlockingHelper() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, - null, null, null, - true, false, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); verify(mMetricsLogger).write(argThat(logMaker -> logMaker.getCategory() == MetricsEvent.ACTION_NOTE_CONTROLS && logMaker.getType() == MetricsEvent.TYPE_OPEN @@ -401,12 +593,22 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testBindNotificationLogging_BlockingHelper() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, - null, null, null, - false, true, + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + false, true, - IMPORTANCE_DEFAULT, true); + true, + IMPORTANCE_DEFAULT, + true); verify(mMetricsLogger).write(argThat(logMaker -> logMaker.getCategory() == MetricsEvent.ACTION_NOTE_CONTROLS && logMaker.getType() == MetricsEvent.TYPE_OPEN @@ -416,12 +618,22 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, - null, null, null, - false, true, + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + false, true, - IMPORTANCE_DEFAULT, true); + true, + IMPORTANCE_DEFAULT, + true); mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent"); verify(mMetricsLogger).count(eq("HowCanNotifsBeRealIfAppsArent"), eq(1)); } @@ -429,13 +641,23 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testOnClickListenerPassesNullChannelForBundle() throws Exception { final CountDownLatch latch = new CountDownLatch(1); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, TEST_PACKAGE_NAME, mNotificationChannel, - createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), mSbn, null, + createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), + mSbn, + null, (View v, NotificationChannel c, int appUid) -> { assertEquals(null, c); latch.countDown(); - }, null, true, true, IMPORTANCE_DEFAULT, true); + }, + null, + true, + true, + IMPORTANCE_DEFAULT, + true); mNotificationInfo.findViewById(R.id.info).performClick(); // Verify that listener was triggered. @@ -446,10 +668,21 @@ public class NotificationInfoTest extends SysuiTestCase { @UiThreadTest public void testBindNotification_ChannelNameInvisibleWhenBundleFromDifferentChannels() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, - createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), mSbn, null, null, - null, true, false, IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); final TextView channelNameView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(GONE, channelNameView.getVisibility()); @@ -458,10 +691,21 @@ public class NotificationInfoTest extends SysuiTestCase { @Test @UiThreadTest public void testStopInvisibleIfBundleFromDifferentChannels() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, - createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), mSbn, null, null, - null, true, false, IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); assertEquals(GONE, mNotificationInfo.findViewById( R.id.interruptiveness_settings).getVisibility()); assertEquals(VISIBLE, mNotificationInfo.findViewById( @@ -470,10 +714,21 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testBindNotification_whenAppUnblockable() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, true, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + true, + IMPORTANCE_DEFAULT, + true); final TextView view = mNotificationInfo.findViewById(R.id.non_configurable_text); assertEquals(View.VISIBLE, view.getVisibility()); assertEquals(mContext.getString(R.string.notification_unblockable_desc), @@ -484,10 +739,21 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); mTestableLooper.processAllMessages(); verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( anyString(), eq(TEST_UID), any()); @@ -496,10 +762,21 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testDoesNotUpdateNotificationChannelAfterImportanceChanged() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_LOW, false); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_LOW, + false); mNotificationInfo.findViewById(R.id.alert).performClick(); mTestableLooper.processAllMessages(); @@ -511,10 +788,21 @@ public class NotificationInfoTest extends SysuiTestCase { public void testDoesNotUpdateNotificationChannelAfterImportanceChangedSilenced() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); mNotificationInfo.findViewById(R.id.silence).performClick(); mTestableLooper.processAllMessages(); @@ -526,10 +814,21 @@ public class NotificationInfoTest extends SysuiTestCase { public void testHandleCloseControls_DoesNotUpdateNotificationChannelIfUnchanged() throws Exception { int originalImportance = mNotificationChannel.getImportance(); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -542,10 +841,21 @@ public class NotificationInfoTest extends SysuiTestCase { public void testHandleCloseControls_DoesNotUpdateNotificationChannelIfUnspecified() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_UNSPECIFIED, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_UNSPECIFIED, + true); mNotificationInfo.handleCloseControls(true, false); @@ -561,13 +871,22 @@ public class NotificationInfoTest extends SysuiTestCase { NotificationInfo.CheckSaveListener listener = mock(NotificationInfo.CheckSaveListener.class); mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, - createMultipleChannelSet(10) /* numUniqueChannelsInRow */, mSbn, + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel /* notificationChannel */, + createMultipleChannelSet(10) /* numUniqueChannelsInRow */, + mSbn, listener /* checkSaveListener */, - null /* onSettingsClick */, null /* onAppSettingsClick */, true /* provisioned */, - false /* isNonblockable */, true /* isForBlockingHelper */, - IMPORTANCE_DEFAULT, true); + null /* onSettingsClick */, + null /* onAppSettingsClick */, + true /* provisioned */, + false /* isNonblockable */, + true /* isForBlockingHelper */, + IMPORTANCE_DEFAULT, + true); NotificationGuts guts = spy(new NotificationGuts(mContext, null)); when(guts.getWindowToken()).thenReturn(mock(IBinder.class)); @@ -591,13 +910,21 @@ public class NotificationInfoTest extends SysuiTestCase { NotificationInfo.CheckSaveListener listener = mock(NotificationInfo.CheckSaveListener.class); mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, - createMultipleChannelSet(10) /* numUniqueChannelsInRow */, mSbn, + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel /* notificationChannel */, + createMultipleChannelSet(10) /* numUniqueChannelsInRow */, + mSbn, listener /* checkSaveListener */, - null /* onSettingsClick */, null /* onAppSettingsClick */, - false /* isNonblockable */, true /* isForBlockingHelper */, - true, IMPORTANCE_DEFAULT, true); + null /* onSettingsClick */, + null /* onAppSettingsClick */, + false /* isNonblockable */, + true /* isForBlockingHelper */, + true, IMPORTANCE_DEFAULT, + true); mNotificationInfo.handleCloseControls(true /* save */, false /* force */); @@ -611,14 +938,22 @@ public class NotificationInfoTest extends SysuiTestCase { NotificationInfo.CheckSaveListener listener = mock(NotificationInfo.CheckSaveListener.class); mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, - createMultipleChannelSet(10) /* numUniqueChannelsInRow */, mSbn, + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel /* notificationChannel */, + createMultipleChannelSet(10) /* numUniqueChannelsInRow */, + mSbn, listener /* checkSaveListener */, - null /* onSettingsClick */, null /* onAppSettingsClick */, + null /* onSettingsClick */, + null /* onAppSettingsClick */, true /* provisioned */, - false /* isNonblockable */, true /* isForBlockingHelper */, - IMPORTANCE_DEFAULT, true); + false /* isNonblockable */, + true /* isForBlockingHelper */, + IMPORTANCE_DEFAULT, + true); mNotificationInfo.findViewById(R.id.deliver_silently).performClick(); mTestableLooper.processAllMessages(); @@ -631,6 +966,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification( mMockPackageManager, mMockINotificationManager, + mVisualStabilityManager, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet /* numChannels */, @@ -641,7 +977,8 @@ public class NotificationInfoTest extends SysuiTestCase { false /* isNonblockable */, true /* isForBlockingHelper */, true, - IMPORTANCE_DEFAULT, true); + IMPORTANCE_DEFAULT, + true); NotificationGuts guts = mock(NotificationGuts.class); doCallRealMethod().when(guts).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean()); mNotificationInfo.setGutsParent(guts); @@ -658,6 +995,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification( mMockPackageManager, mMockINotificationManager, + mVisualStabilityManager, TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet /* numChannels */, @@ -688,10 +1026,21 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testKeepUpdatesNotificationChannel_blockingHelper() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, true, - IMPORTANCE_LOW, false); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + true, + IMPORTANCE_LOW, + false); mNotificationInfo.findViewById(R.id.keep_showing).performClick(); mNotificationInfo.handleCloseControls(true, false); @@ -708,10 +1057,21 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testNoActionsUpdatesNotificationChannel_blockingHelper() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, true, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + true, + IMPORTANCE_DEFAULT, + true); mNotificationInfo.handleCloseControls(true, false); @@ -727,10 +1087,21 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testSilenceCallsUpdateNotificationChannel() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); mNotificationInfo.findViewById(R.id.silence).performClick(); mNotificationInfo.findViewById(R.id.done).performClick(); @@ -749,10 +1120,21 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testUnSilenceCallsUpdateNotificationChannel() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_LOW, false); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_LOW, + false); mNotificationInfo.findViewById(R.id.alert).performClick(); mNotificationInfo.findViewById(R.id.done).performClick(); @@ -772,10 +1154,21 @@ public class NotificationInfoTest extends SysuiTestCase { public void testSilenceCallsUpdateNotificationChannel_channelImportanceUnspecified() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_UNSPECIFIED, true); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_UNSPECIFIED, + true); mNotificationInfo.findViewById(R.id.silence).performClick(); mNotificationInfo.findViewById(R.id.done).performClick(); @@ -795,10 +1188,21 @@ public class NotificationInfoTest extends SysuiTestCase { public void testSilenceCallsUpdateNotificationChannel_channelImportanceMin() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_MIN); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_MIN, false); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_MIN, + false); assertEquals(mContext.getString(R.string.inline_done_button), ((TextView) mNotificationInfo.findViewById(R.id.done)).getText()); @@ -821,10 +1225,21 @@ public class NotificationInfoTest extends SysuiTestCase { public void testAlertCallsUpdateNotificationChannel_channelImportanceMin() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_MIN); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_MIN, false); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_MIN, + false); assertEquals(mContext.getString(R.string.inline_done_button), ((TextView) mNotificationInfo.findViewById(R.id.done)).getText()); @@ -843,14 +1258,51 @@ public class NotificationInfoTest extends SysuiTestCase { assertEquals(IMPORTANCE_DEFAULT, updated.getValue().getImportance()); } + @Test + public void testAdjustImportanceTemporarilyAllowsReordering() throws Exception { + mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); + + mNotificationInfo.findViewById(R.id.silence).performClick(); + mNotificationInfo.findViewById(R.id.done).performClick(); + mNotificationInfo.handleCloseControls(true, false); + + verify(mVisualStabilityManager).temporarilyAllowReordering(); + } + @Test public void testDoneText() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_LOW, false); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_LOW, + false); assertEquals(mContext.getString(R.string.inline_done_button), ((TextView) mNotificationInfo.findViewById(R.id.done)).getText()); @@ -866,10 +1318,21 @@ public class NotificationInfoTest extends SysuiTestCase { public void testUnSilenceCallsUpdateNotificationChannel_channelImportanceUnspecified() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_LOW, false); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_LOW, + false); mNotificationInfo.findViewById(R.id.alert).performClick(); mNotificationInfo.findViewById(R.id.done).performClick(); @@ -888,10 +1351,21 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null, - null, true, false, - IMPORTANCE_LOW, false); + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, + null, + null, + null, + true, + false, + IMPORTANCE_LOW, + false); mNotificationInfo.findViewById(R.id.alert).performClick(); mNotificationInfo.findViewById(R.id.done).performClick(); @@ -905,11 +1379,23 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testCloseControlsUpdatesWhenCheckSaveListenerUsesCallback() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, (Runnable saveImportance, StatusBarNotification sbn) -> { saveImportance.run(); - }, null, null, true, false, IMPORTANCE_LOW, false + }, + null, + null, + true, + false, + IMPORTANCE_LOW, + false ); mNotificationInfo.findViewById(R.id.alert).performClick(); @@ -928,11 +1414,23 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testCloseControls_withoutHittingApply() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, (Runnable saveImportance, StatusBarNotification sbn) -> { saveImportance.run(); - }, null, null, true, false, IMPORTANCE_LOW, false + }, + null, + null, + true, + false, + IMPORTANCE_LOW, + false ); mNotificationInfo.findViewById(R.id.alert).performClick(); @@ -944,11 +1442,23 @@ public class NotificationInfoTest extends SysuiTestCase { public void testWillBeRemovedReturnsFalse() throws Exception { assertFalse(mNotificationInfo.willBeRemoved()); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mSbn, (Runnable saveImportance, StatusBarNotification sbn) -> { saveImportance.run(); - }, null, null, true, false, IMPORTANCE_LOW, false + }, + null, + null, + true, + false, + IMPORTANCE_LOW, + false ); assertFalse(mNotificationInfo.willBeRemoved());