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

Commit aae1ce18 authored by Lyn Han's avatar Lyn Han Committed by Android (Google) Code Review
Browse files

Merge "Fix HUNs re-showing after shade closes" into main

parents 9bc11c03 097ac3c5
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -13,12 +13,18 @@ class VisualStabilityProvider @Inject constructor() {
    /** The subset of active listeners which are temporary (will be removed after called) */
    private val temporaryListeners = ArraySet<OnReorderingAllowedListener>()

    private val banListeners = ListenerSet<OnReorderingBannedListener>()

    var isReorderingAllowed = true
        set(value) {
            if (field != value) {
                field = value
                if (value) {
                    notifyReorderingAllowed()
                } else {
                    banListeners.forEach { listener ->
                        listener.onReorderingBanned()
                    }
                }
            }
        }
@@ -38,6 +44,10 @@ class VisualStabilityProvider @Inject constructor() {
        allListeners.addIfAbsent(listener)
    }

    fun addPersistentReorderingBannedListener(listener: OnReorderingBannedListener) {
        banListeners.addIfAbsent(listener)
    }

    /** Add a listener which will be removed when it is called. */
    fun addTemporaryReorderingAllowedListener(listener: OnReorderingAllowedListener) {
        // Only add to the temporary set if it was added to the global set
@@ -57,3 +67,8 @@ class VisualStabilityProvider @Inject constructor() {
fun interface OnReorderingAllowedListener {
    fun onReorderingAllowed()
}

fun interface OnReorderingBannedListener {
    fun onReorderingBanned()
}
+27 −1
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener;
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingBannedListener;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository;
@@ -86,7 +87,7 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
    private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>();
    private final VisualStabilityProvider mVisualStabilityProvider;

    private final AvalancheController mAvalancheController;
    private AvalancheController mAvalancheController;

    // TODO(b/328393698) move the topHeadsUpRow logic to an interactor
    private final MutableStateFlow<HeadsUpRowRepository> mTopHeadsUpRow =
@@ -175,6 +176,7 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
            javaAdapter.alwaysCollectFlow(shadeInteractor.isAnyExpanded(),
                    this::onShadeOrQsExpanded);
        }
        mVisualStabilityProvider.addPersistentReorderingBannedListener(mOnReorderingBannedListener);
    }

    public void setAnimationStateHandler(AnimationStateHandler handler) {
@@ -382,6 +384,8 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements

    private final OnReorderingAllowedListener mOnReorderingAllowedListener = () -> {
        mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
        mAvalancheController.setEnableAtRuntime(true);

        for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
            if (isHeadsUpEntry(entry.getKey())) {
                // Maybe the heads-up was removed already
@@ -392,6 +396,28 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
        mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true);
    };

    private final OnReorderingBannedListener mOnReorderingBannedListener = () -> {
        if (mAvalancheController != null) {
            // Waiting HUNs in AvalancheController are still promoted to the HUN section and thus
            // seen in open shade; clear them so we don't show them again when the shade closes and
            // reordering is allowed again.
            mAvalancheController.logDroppedHuns(mAvalancheController.getWaitingKeys().size());
            mAvalancheController.clearNext();

            // In open shade the first HUN is pinned, and visual stability logic prevents us from
            // unpinning this first HUN as long as the shade remains open. AvalancheController only
            // shows the next HUN when the currently showing HUN is unpinned, so we must disable
            // throttling here so that the incoming HUN stream is not forever paused. This is reset
            // when reorder becomes allowed.
            mAvalancheController.setEnableAtRuntime(false);

            // Note that we cannot do the above when
            // 1) the remove runnable runs because its delay means it may not run before shade close
            // 2) reordering is allowed again (when shade closes) because the HUN appear animation
            // will have started by then
        }
    };

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //  HeadsUpManager utility (protected) methods overrides:

+19 −12
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger)

    private val tag = "AvalancheController"
    private val debug = Compile.IS_DEBUG && Log.isLoggable(tag, Log.DEBUG)
    var enableAtRuntime = true

    // HUN showing right now, in the floating state where full shade is hidden, on launcher or AOD
    @VisibleForTesting var headsUpEntryShowing: HeadsUpEntry? = null
@@ -81,13 +82,17 @@ constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger)
        dumpManager.registerNormalDumpable(tag, /* module */ this)
    }

    fun isEnabled() : Boolean {
        return NotificationThrottleHun.isEnabled && enableAtRuntime
    }

    fun getShowingHunKey(): String {
        return getKey(headsUpEntryShowing)
    }

    /** Run or delay Runnable for given HeadsUpEntry */
    fun update(entry: HeadsUpEntry?, runnable: Runnable, label: String) {
        if (!NotificationThrottleHun.isEnabled) {
        if (!isEnabled()) {
            runnable.run()
            return
        }
@@ -143,7 +148,7 @@ constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger)
     * all Runnables associated with that entry.
     */
    fun delete(entry: HeadsUpEntry?, runnable: Runnable, label: String) {
        if (!NotificationThrottleHun.isEnabled) {
        if (!isEnabled()) {
            runnable.run()
            return
        }
@@ -184,7 +189,7 @@ constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger)
     *    BaseHeadsUpManager.HeadsUpEntry.calculateFinishTime to shorten display duration.
     */
    fun getDurationMs(entry: HeadsUpEntry, autoDismissMs: Int): Int {
        if (!NotificationThrottleHun.isEnabled) {
        if (!isEnabled()) {
            // Use default duration, like we did before AvalancheController existed
            return autoDismissMs
        }
@@ -233,7 +238,7 @@ constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger)

    /** Return true if entry is waiting to show. */
    fun isWaiting(key: String): Boolean {
        if (!NotificationThrottleHun.isEnabled) {
        if (!isEnabled()) {
            return false
        }
        for (entry in nextMap.keys) {
@@ -246,7 +251,7 @@ constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger)

    /** Return list of keys for huns waiting */
    fun getWaitingKeys(): MutableList<String> {
        if (!NotificationThrottleHun.isEnabled) {
        if (!isEnabled()) {
            return mutableListOf()
        }
        val keyList = mutableListOf<String>()
@@ -257,7 +262,7 @@ constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger)
    }

    fun getWaitingEntry(key: String): HeadsUpEntry? {
        if (!NotificationThrottleHun.isEnabled) {
        if (!isEnabled()) {
            return null
        }
        for (headsUpEntry in nextMap.keys) {
@@ -269,7 +274,7 @@ constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger)
    }

    fun getWaitingEntryList(): List<HeadsUpEntry> {
        if (!NotificationThrottleHun.isEnabled) {
        if (!isEnabled()) {
            return mutableListOf()
        }
        return nextMap.keys.toList()
@@ -310,11 +315,7 @@ constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger)

        // Remove runnable labels for dropped huns
        val listToDrop = nextList.subList(1, nextList.size)

        // Log dropped HUNs
        for (e in listToDrop) {
            uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_DROPPED)
        }
        logDroppedHuns(listToDrop.size)

        if (debug) {
            // Clear runnable labels
@@ -331,6 +332,12 @@ constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger)
        showNow(headsUpEntryShowing!!, headsUpEntryShowingRunnableList)
    }

    fun logDroppedHuns(numDropped: Int) {
        for (n in 1..numDropped) {
            uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_DROPPED)
        }
    }

    fun clearNext() {
        nextList.clear()
        nextMap.clear()