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

Commit c62846df authored by Lyn's avatar Lyn
Browse files

Show sticky HUN for 60s instead of forever

Bug: 243421660

Test: atest NotificationEntryTest,
      AlertingNotificationManagerTest, HeadsUpManagerTest

Test: send notif with FSI, deny permission via flag
- When locked, HUN shows instead of FSI.
- Pulsing HUN hides after 60s.
- Unlocked HUN hides after 60s.
- If we update with FSI at 30s, HUN still hides at 60s after
creation.
- However if we update with no FSI at 30s, HUN hides at 35s after
initial creation.
- Once a notification is created or updated without FSI, it is
permanently demoted and any updates after that (with or without
FSI) extend HUN lifetime by the usual 5 seconds.

Change-Id: I4add28ba36897326906d81298eb8575ccc14b056
parent 7724c90c
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -120,6 +120,9 @@
    <!-- Minimum display time for a heads up notification, in milliseconds. -->
    <integer name="heads_up_notification_minimum_time">2000</integer>

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

    <!-- Whether to hide the notification header when the HUN is expanded. -->
    <bool name="heads_up_notification_hides_header">false</bool>

+36 −14
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ public abstract class AlertingNotificationManager {
    }

    protected int mMinimumDisplayTime;
    protected int mStickyDisplayTime;
    protected int mAutoDismissNotificationDecay;
    @VisibleForTesting
    public Handler mHandler;
@@ -198,7 +199,7 @@ public abstract class AlertingNotificationManager {
        if (entry != null && entry.isExpandAnimationRunning()) {
            return;
        }

        entry.demoteStickyHun();
        mAlertEntries.remove(key);
        onAlertEntryRemoved(alertEntry);
        entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
@@ -255,6 +256,15 @@ public abstract class AlertingNotificationManager {
        return 0;
    }

    @VisibleForTesting
    public long getCalculatedEarliestRemovalTime(String key) {
        AlertEntry alerting = mAlertEntries.get(key);
        if (alerting != null) {
            return alerting.mEarliestRemovaltime;
        }
        return 0;
    }

    protected class AlertEntry implements Comparable<AlertEntry> {
        @Nullable public NotificationEntry mEntry;
        public long mPostTime;
@@ -275,6 +285,11 @@ public abstract class AlertingNotificationManager {
            updateEntry(true /* updatePostTime */);
        }

        @VisibleForTesting
        long getEarliestRemovaltime() {
            return mEarliestRemovaltime;
        }

        /**
         * Updates an entry's removal time.
         * @param updatePostTime whether or not to refresh the post time
@@ -282,18 +297,22 @@ public abstract class AlertingNotificationManager {
        public void updateEntry(boolean updatePostTime) {
            mLogger.logUpdateEntry(mEntry, updatePostTime);

            long currentTime = mClock.currentTimeMillis();
            mEarliestRemovaltime = currentTime + mMinimumDisplayTime;
            final long now = mClock.currentTimeMillis();
            mEarliestRemovaltime = isSticky()
                    ? mEntry.mCreationElapsedRealTime + mStickyDisplayTime
                    : now + mMinimumDisplayTime;

            if (updatePostTime) {
                mPostTime = Math.max(mPostTime, currentTime);
                mPostTime = Math.max(mPostTime, now);
            }
            removeAutoRemovalCallbacks();

            if (!isSticky()) {
                long finishTime = calculateFinishTime();
                long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime);
                mHandler.postDelayed(mRemoveAlertRunnable, removeDelay);
            }
            final long finishTime = calculateFinishTime();
            final long timeRemaining = isSticky()
                    ? finishTime - mClock.currentTimeMillis()
                    : Math.max(finishTime - now, mMinimumDisplayTime);

            mHandler.postDelayed(mRemoveAlertRunnable, timeRemaining);
        }

        /**
@@ -302,11 +321,13 @@ public abstract class AlertingNotificationManager {
         * @return true if the notification is sticky
         */
        public boolean isSticky() {
            return false;
            // This implementation is overridden by HeadsUpManager HeadsUpEntry #isSticky
            // but we keep this here for use by unit tests.
            return mEntry.isStickyAndNotDemoted();
        }

        /**
         * Whether the notification has been on screen long enough and can be removed.
         * Whether the notification has befen on screen long enough and can be removed.
         * @return true if the notification has been on screen long enough
         */
        public boolean wasShownLongEnough() {
@@ -355,11 +376,12 @@ public abstract class AlertingNotificationManager {
        }

        /**
         * Calculate when the notification should auto-dismiss itself.
         * @return the finish time
         * @return When the notification should auto-dismiss itself, based on
         * {@link SystemClock#elapsedRealTime()}
         */
        protected long calculateFinishTime() {
            return mPostTime + mAutoDismissNotificationDecay;
            // Overridden by HeadsUpManager HeadsUpEntry #calculateFinishTime
            return 0;
        }
    }

+43 −0
Original line number Diff line number Diff line
@@ -180,6 +180,44 @@ public final class NotificationEntry extends ListEntry {
     */
    private boolean mBlockable;

    /**
     * The {@link SystemClock#elapsedRealtime()} when this notification entry was created.
     */
    public long mCreationElapsedRealTime;

    /**
     * Whether this notification has ever been a non-sticky HUN.
     */
    private boolean mIsDemoted = false;

    /**
     * True if both
     *  1) app provided full screen intent but does not have the permission to send it
     *  2) this notification has never been demoted before
     */
    public boolean isStickyAndNotDemoted() {

        final boolean fsiRequestedButDenied =  (getSbn().getNotification().flags
                & Notification.FLAG_FSI_REQUESTED_BUT_DENIED) != 0;

        if (!fsiRequestedButDenied && !mIsDemoted) {
            demoteStickyHun();
        }
        return fsiRequestedButDenied && !mIsDemoted;
    }

    @VisibleForTesting
    public boolean isDemoted() {
        return mIsDemoted;
    }

    /**
     * Make sticky HUN not sticky.
     */
    public void demoteStickyHun() {
        mIsDemoted = true;
    }

    /**
     * @param sbn the StatusBarNotification from system server
     * @param ranking also from system server
@@ -197,8 +235,13 @@ public final class NotificationEntry extends ListEntry {
        mKey = sbn.getKey();
        setSbn(sbn);
        setRanking(ranking);
        mCreationElapsedRealTime = SystemClock.elapsedRealtime();
    }

    @VisibleForTesting
    public void setCreationElapsedRealTime(long time) {
        mCreationElapsedRealTime = time;
    }
    @Override
    public NotificationEntry getRepresentativeEntry() {
        return this;
+4 −0
Original line number Diff line number Diff line
@@ -30,6 +30,10 @@ public interface NotificationInterruptStateProvider {
     * the full screen intent should or shouldn't launch.
     */
    enum FullScreenIntentDecision {
        /**
         * Full screen intents are disabled.
         */
        NO_FSI_SHOW_STICKY_HUN(false),
        /**
         * Full screen intents are disabled.
         */
+8 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.provider.Settings;
import android.service.dreams.IDreamManager;
import android.service.notification.StatusBarNotification;
@@ -246,7 +247,11 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
        if (mFlags.disableFsi()) {
            return FullScreenIntentDecision.NO_FSI_DISABLED;
        }

        if (entry.getSbn().getNotification().fullScreenIntent == null) {
            if (entry.isStickyAndNotDemoted()) {
                return FullScreenIntentDecision.NO_FSI_SHOW_STICKY_HUN;
            }
            return FullScreenIntentDecision.NO_FULL_SCREEN_INTENT;
        }

@@ -335,6 +340,9 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
        final int uid = entry.getSbn().getUid();
        final String packageName = entry.getSbn().getPackageName();
        switch (decision) {
            case NO_FSI_SHOW_STICKY_HUN:
                mLogger.logNoFullscreen(entry, "Permission denied, show sticky HUN");
                return;
            case NO_FSI_DISABLED:
                mLogger.logNoFullscreen(entry, "Disabled");
                return;
Loading