Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit de70cf1a authored by Caitlin Shkuratov's avatar Caitlin Shkuratov
Browse files

[Notif] Implement a min display time of 3sec for pinned-by-user HUNs.

Pinned-by-user HUNs show up when a user taps the status bar notification
chip. Since that's clear user intent, keep that HUN around for at least
3 seconds before showing a new HUN.

Fixes: 388540989
Bug: 364653005
Flag: com.android.systemui.status_bar_notification_chips

Test: Tap promoted notification chip then immediately send a HUNing
notif -> verify promoted notification stays visible for 3 seconds before
new HUN shows up
Test: Spam normal notifications -> verify they still use the old 0.5
second minimum display time
Test: atest HeadsUpManagerImplTest

Change-Id: I2d2c73fd212da636f511bef023e73e7def075154
parent a4050465
Loading
Loading
Loading
Loading
+77 −13
Original line number Diff line number Diff line
@@ -106,11 +106,15 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
            this.addOverride(R.integer.touch_acceptance_delay, TEST_TOUCH_ACCEPTANCE_TIME)
            this.addOverride(
                R.integer.heads_up_notification_minimum_time,
                TEST_MINIMUM_DISPLAY_TIME,
                TEST_MINIMUM_DISPLAY_TIME_DEFAULT,
            )
            this.addOverride(
                R.integer.heads_up_notification_minimum_time_with_throttling,
                TEST_MINIMUM_DISPLAY_TIME,
                TEST_MINIMUM_DISPLAY_TIME_DEFAULT,
            )
            this.addOverride(
                R.integer.heads_up_notification_minimum_time_for_user_initiated,
                TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED,
            )
            this.addOverride(R.integer.heads_up_notification_decay, TEST_AUTO_DISMISS_TIME)
            this.addOverride(
@@ -414,7 +418,7 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
    }

    @Test
    fun testRemoveNotification_beforeMinimumDisplayTime() {
    fun testRemoveNotification_beforeMinimumDisplayTime_notUserInitiatedHun() {
        val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
        useAccessibilityTimeout(false)

@@ -429,18 +433,22 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
        assertThat(removedImmediately).isFalse()
        assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue()

        systemClock.advanceTime(((TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2).toLong())
        systemClock.advanceTime(
            ((TEST_MINIMUM_DISPLAY_TIME_DEFAULT + TEST_AUTO_DISMISS_TIME) / 2).toLong()
        )

        assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse()
    }

    @Test
    fun testRemoveNotification_afterMinimumDisplayTime() {
    fun testRemoveNotification_afterMinimumDisplayTime_notUserInitiatedHun() {
        val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
        useAccessibilityTimeout(false)

        underTest.showNotification(entry)
        systemClock.advanceTime(((TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2).toLong())
        systemClock.advanceTime(
            ((TEST_MINIMUM_DISPLAY_TIME_DEFAULT + TEST_AUTO_DISMISS_TIME) / 2).toLong()
        )

        assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue()

@@ -454,6 +462,57 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
        assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse()
    }

    @Test
    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
    fun testRemoveNotification_beforeMinimumDisplayTime_forUserInitiatedHun() {
        useAccessibilityTimeout(false)

        val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
        entry.row = testHelper.createRow()
        underTest.showNotification(entry, isPinnedByUser = true)

        val removedImmediately =
            underTest.removeNotification(
                entry.key,
                /* releaseImmediately = */ false,
                "beforeMinimumDisplayTime",
            )
        assertThat(removedImmediately).isFalse()
        assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue()

        systemClock.advanceTime(
            ((TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED + TEST_AUTO_DISMISS_TIME) / 2).toLong()
        )

        assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse()
    }

    @Test
    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
    fun testRemoveNotification_afterMinimumDisplayTime_forUserInitiatedHun() {
        useAccessibilityTimeout(false)

        val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
        entry.row = testHelper.createRow()
        underTest.showNotification(entry, isPinnedByUser = true)

        systemClock.advanceTime(
            ((TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED + TEST_AUTO_DISMISS_TIME) / 2).toLong()
        )

        assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue()

        val removedImmediately =
            underTest.removeNotification(
                entry.key,
                /* releaseImmediately = */ false,
                "afterMinimumDisplayTime",
            )

        assertThat(removedImmediately).isTrue()
        assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse()
    }

    @Test
    fun testRemoveNotification_releaseImmediately() {
        val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
@@ -1047,16 +1106,21 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
    }

    companion object {
        const val TEST_TOUCH_ACCEPTANCE_TIME = 200
        const val TEST_A11Y_AUTO_DISMISS_TIME = 1000
        const val TEST_EXTENSION_TIME = 500
        private const val TEST_TOUCH_ACCEPTANCE_TIME = 200
        private const val TEST_A11Y_AUTO_DISMISS_TIME = 1000
        private const val TEST_EXTENSION_TIME = 500

        const val TEST_MINIMUM_DISPLAY_TIME = 400
        const val TEST_AUTO_DISMISS_TIME = 600
        const val TEST_STICKY_AUTO_DISMISS_TIME = 800
        private const val TEST_MINIMUM_DISPLAY_TIME_DEFAULT = 400
        private const val TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED = 500
        private const val TEST_AUTO_DISMISS_TIME = 600
        private const val TEST_STICKY_AUTO_DISMISS_TIME = 800

        init {
            assertThat(TEST_MINIMUM_DISPLAY_TIME).isLessThan(TEST_AUTO_DISMISS_TIME)
            assertThat(TEST_MINIMUM_DISPLAY_TIME_DEFAULT)
                .isLessThan(TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED)
            assertThat(TEST_MINIMUM_DISPLAY_TIME_DEFAULT).isLessThan(TEST_AUTO_DISMISS_TIME)
            assertThat(TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED)
                .isLessThan(TEST_AUTO_DISMISS_TIME)
            assertThat(TEST_AUTO_DISMISS_TIME).isLessThan(TEST_STICKY_AUTO_DISMISS_TIME)
            assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME)
        }
+3 −0
Original line number Diff line number Diff line
@@ -175,6 +175,9 @@
    <!-- Minimum display time for a heads up notification if throttling is enabled, in milliseconds. -->
    <integer name="heads_up_notification_minimum_time_with_throttling">500</integer>

    <!-- Minimum display time for a heads up notification that was shown from a user action (like tapping on a different part of the UI), in milliseconds. -->
    <integer name="heads_up_notification_minimum_time_for_user_initiated">3000</integer>

    <!-- Display time for a sticky heads up notification, in milliseconds. -->
    <integer name="sticky_heads_up_notification_time">60000</integer>

+12 −4
Original line number Diff line number Diff line
@@ -118,7 +118,8 @@ public class HeadsUpManagerImpl
    @VisibleForTesting
    final ArrayMap<String, HeadsUpEntry> mHeadsUpEntryMap = new ArrayMap<>();
    private final HeadsUpManagerLogger mLogger;
    private final int mMinimumDisplayTime;
    private final int mMinimumDisplayTimeDefault;
    private final int mMinimumDisplayTimeForUserInitiated;
    private final int mStickyForSomeTimeAutoDismissTime;
    private final int mAutoDismissTime;
    private final DelayableExecutor mExecutor;
@@ -215,9 +216,11 @@ public class HeadsUpManagerImpl
        mGroupMembershipManager = groupMembershipManager;
        mVisualStabilityProvider = visualStabilityProvider;
        Resources resources = context.getResources();
        mMinimumDisplayTime = NotificationThrottleHun.isEnabled()
        mMinimumDisplayTimeDefault = NotificationThrottleHun.isEnabled()
                ? resources.getInteger(R.integer.heads_up_notification_minimum_time_with_throttling)
                : resources.getInteger(R.integer.heads_up_notification_minimum_time);
        mMinimumDisplayTimeForUserInitiated = resources.getInteger(
                R.integer.heads_up_notification_minimum_time_for_user_initiated);
        mStickyForSomeTimeAutoDismissTime = resources.getInteger(
                R.integer.sticky_heads_up_notification_time);
        mAutoDismissTime = resources.getInteger(R.integer.heads_up_notification_decay);
@@ -1358,7 +1361,12 @@ public class HeadsUpManagerImpl

                final long now = mSystemClock.elapsedRealtime();
                if (updateEarliestRemovalTime) {
                    mEarliestRemovalTime = now + mMinimumDisplayTime;
                    if (StatusBarNotifChips.isEnabled()
                            && mPinnedStatus.getValue() == PinnedStatus.PinnedByUser) {
                        mEarliestRemovalTime = now + mMinimumDisplayTimeForUserInitiated;
                    } else {
                        mEarliestRemovalTime = now + mMinimumDisplayTimeDefault;
                    }
                }

                if (updatePostTime) {
@@ -1377,7 +1385,7 @@ public class HeadsUpManagerImpl
                final long now = mSystemClock.elapsedRealtime();
                return NotificationThrottleHun.isEnabled()
                        ? Math.max(finishTime, mEarliestRemovalTime) - now
                        : Math.max(finishTime - now, mMinimumDisplayTime);
                        : Math.max(finishTime - now, mMinimumDisplayTimeDefault);
            };
            scheduleAutoRemovalCallback(finishTimeCalculator, "updateEntry (not sticky)");