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

Commit 77fb9ee0 authored by Caitlin Shkuratov's avatar Caitlin Shkuratov
Browse files

[SB][Notif] Ensure promoted notifications are never sticky.

This is done by making sure `isSticky()` returns false if the
notification is promoted. This means promoted notifications won't be
sticky if you tap the status bar chip to show the HUN, or if an app
posting a promoted notification makes it alert.

Note: In practice, I think this case isn't possible because `mExpanded`
should only be set to true when the expansion caret is tapped and RONs
shouldn't show the expansion caret. But this adds protection just in
case.

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

Test: Post two RONs, tap on one status bar chip to show HUN, then tap
expansion caret on the HUN. Then, tap the other status bar chip ->
verify HUN for the other chip shows
Test: atest HeadsUpManagerImplTest

Change-Id: Ibce9cb64125deeb00fff532033ea73c31c5a8654
parent f3bc47b0
Loading
Loading
Loading
Loading
+24 −4
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.headsup

import android.app.Notification
import android.app.Notification.FLAG_PROMOTED_ONGOING
import android.app.PendingIntent
import android.app.Person
import android.os.Handler
@@ -677,10 +678,12 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
    }

    @Test
    fun testIsSticky_rowPinnedAndExpanded_true() {
        val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
        val row = testHelper.createRow()
        row.setPinnedStatus(PinnedStatus.PinnedBySystem)
    @DisableFlags(StatusBarNotifChips.FLAG_NAME)
    fun testIsSticky_promotedAndExpanded_notifChipsFlagOff_true() {
        val notif = Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
        notif.flags = FLAG_PROMOTED_ONGOING
        val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, notif)
        val row = testHelper.createRow().apply { setPinnedStatus(PinnedStatus.PinnedBySystem) }
        notifEntry.row = row

        underTest.showNotification(notifEntry)
@@ -691,6 +694,23 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
        assertThat(underTest.isSticky(notifEntry.key)).isTrue()
    }

    @Test
    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
    fun testIsSticky_promotedAndExpanded_notifChipsFlagOn_false() {
        val notif = Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
        notif.flags = FLAG_PROMOTED_ONGOING
        val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, notif)
        val row = testHelper.createRow().apply { setPinnedStatus(PinnedStatus.PinnedBySystem) }
        notifEntry.row = row

        underTest.showNotification(notifEntry)

        val headsUpEntry = underTest.getHeadsUpEntry(notifEntry.key)
        headsUpEntry!!.setExpanded(true)

        assertThat(underTest.isSticky(notifEntry.key)).isFalse()
    }

    @Test
    fun testIsSticky_remoteInputActive_true() {
        val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
+10 −0
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ import static com.android.systemui.statusbar.notification.stack.NotificationPrio

import static java.util.Objects.requireNonNull;

import android.annotation.FlaggedApi;
import android.app.Flags;
import android.app.Notification;
import android.app.Notification.MessagingStyle.Message;
import android.app.NotificationChannel;
@@ -1090,6 +1092,14 @@ public final class NotificationEntry extends ListEntry {
        }
    }

    /**
     * Returns whether the NotificationEntry is promoted ongoing.
     */
    @FlaggedApi(Flags.FLAG_API_RICH_ONGOING)
    public boolean isPromotedOngoing() {
        return PromotedNotificationContentModel.isPromotedForStatusBarChip(mSbn.getNotification());
    }

    /**
     * Sets the content needed to render this notification as a promoted notification on various
     * surfaces (like status bar chips and AOD).
+6 −1
Original line number Diff line number Diff line
@@ -1425,7 +1425,12 @@ public class HeadsUpManagerImpl
                }
            }

            return (mEntry.isRowPinned() && mExpanded)
            // Promoted notifications are always shown as expanded, and we don't want them to ever
            // be sticky.
            boolean isStickyDueToExpansion =
                    mEntry.isRowPinned() && mExpanded && !mEntry.isPromotedOngoing();

            return isStickyDueToExpansion
                    || mRemoteInputActive
                    || hasFullScreenIntent(mEntry);
        }
+1 −0
Original line number Diff line number Diff line
@@ -147,6 +147,7 @@ data class PromotedNotificationContentModel(
         * Returns true if the given notification should be considered promoted when deciding
         * whether or not to show the status bar chip UI.
         */
        @JvmStatic
        fun isPromotedForStatusBarChip(notification: Notification): Boolean {
            // Notification.isPromotedOngoing checks the ui_rich_ongoing flag, but we want the
            // status bar chip to be ready before all the features behind the ui_rich_ongoing flag
+39 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.app.Notification.CATEGORY_EVENT;
import static android.app.Notification.CATEGORY_MESSAGE;
import static android.app.Notification.CATEGORY_REMINDER;
import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
import static android.app.Notification.FLAG_PROMOTED_ONGOING;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;

import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
@@ -43,6 +44,8 @@ import android.graphics.drawable.Icon;
import android.media.session.MediaSession;
import android.os.Bundle;
import android.os.UserHandle;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
@@ -54,6 +57,8 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
import com.android.systemui.util.time.FakeSystemClock;

import org.junit.Before;
@@ -279,6 +284,40 @@ public class NotificationEntryTest extends SysuiTestCase {
        assertTrue(mEntry.isStickyAndNotDemoted());
    }

    @Test
    @EnableFlags({PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME})
    public void isPromotedOngoing_noFlagOnNotif_false() {
        mEntry.getSbn().getNotification().flags &= ~FLAG_PROMOTED_ONGOING;

        assertFalse(mEntry.isPromotedOngoing());
    }

    @Test
    @DisableFlags({PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME})
    public void isPromotedOngoing_statusBarNotifChipsFlagAndUiFlagOff_false() {
        mEntry.getSbn().getNotification().flags |= FLAG_PROMOTED_ONGOING;

        assertFalse(mEntry.isPromotedOngoing());
    }

    @Test
    @EnableFlags(PromotedNotificationUi.FLAG_NAME)
    @DisableFlags(StatusBarNotifChips.FLAG_NAME)
    public void isPromotedOngoing_uiFlagOnAndNotifHasFlag_true() {
        mEntry.getSbn().getNotification().flags |= FLAG_PROMOTED_ONGOING;

        assertTrue(mEntry.isPromotedOngoing());
    }

    @Test
    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
    @DisableFlags(PromotedNotificationUi.FLAG_NAME)
    public void isPromotedOngoing_statusBarNotifChipsFlagOnAndNotifHasFlag_true() {
        mEntry.getSbn().getNotification().flags |= FLAG_PROMOTED_ONGOING;

        assertTrue(mEntry.isPromotedOngoing());
    }

    @Test
    public void testIsNotificationVisibilityPrivate_true() {
        assertTrue(mEntry.isNotificationVisibilityPrivate());