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

Commit 81d34866 authored by Steve Elliott's avatar Steve Elliott Committed by Android (Google) Code Review
Browse files

Merge "New pipeline: defer visual updates when collapse"

parents cbf73321 83476cd3
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -359,6 +359,13 @@ public class ShadeListBuilder implements Dumpable {
    private void buildList() {
        Trace.beginSection("ShadeListBuilder.buildList");
        mPipelineState.requireIsBefore(STATE_BUILD_STARTED);

        if (!mNotifStabilityManager.isPipelineRunAllowed()) {
            mLogger.logPipelineRunSuppressed();
            Trace.endSection();
            return;
        }

        mPipelineState.setState(STATE_BUILD_STARTED);

        // Step 1: Reset notification states
+43 −8
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.render.NotifPanelEventSource;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.concurrency.DelayableExecutor;

@@ -56,17 +57,23 @@ import javax.inject.Inject;
 */
// TODO(b/204468557): Move to @CoordinatorScope
@SysUISingleton
public class VisualStabilityCoordinator implements Coordinator, Dumpable {
public class VisualStabilityCoordinator implements Coordinator, Dumpable,
        NotifPanelEventSource.Callbacks {
    private final DelayableExecutor mDelayableExecutor;
    private final WakefulnessLifecycle mWakefulnessLifecycle;
    private final StatusBarStateController mStatusBarStateController;
    private final HeadsUpManager mHeadsUpManager;
    private final NotifPanelEventSource mNotifPanelEventSource;
    private final StatusBarStateController mStatusBarStateController;
    private final WakefulnessLifecycle mWakefulnessLifecycle;

    private boolean mScreenOn;
    private boolean mPanelExpanded;
    private boolean mPulsing;
    private boolean mNotifPanelCollapsing;
    private boolean mNotifPanelLaunchingActivity;

    private boolean mPipelineRunAllowed;
    private boolean mReorderingAllowed;
    private boolean mIsSuppressingPipelineRun = false;
    private boolean mIsSuppressingGroupChange = false;
    private final Set<String> mEntriesWithSuppressedSectionChange = new HashSet<>();
    private boolean mIsSuppressingEntryReorder = false;
@@ -81,16 +88,17 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {

    @Inject
    public VisualStabilityCoordinator(
            DelayableExecutor delayableExecutor,
            DumpManager dumpManager,
            HeadsUpManager headsUpManager,
            WakefulnessLifecycle wakefulnessLifecycle,
            NotifPanelEventSource notifPanelEventSource,
            StatusBarStateController statusBarStateController,
            DelayableExecutor delayableExecutor
    ) {
            WakefulnessLifecycle wakefulnessLifecycle) {
        mHeadsUpManager = headsUpManager;
        mWakefulnessLifecycle = wakefulnessLifecycle;
        mStatusBarStateController = statusBarStateController;
        mDelayableExecutor = delayableExecutor;
        mNotifPanelEventSource = notifPanelEventSource;

        dumpManager.registerDumpable(this);
    }
@@ -103,6 +111,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {

        mStatusBarStateController.addCallback(mStatusBarStateControllerListener);
        mPulsing = mStatusBarStateController.isPulsing();
        mNotifPanelEventSource.registerCallbacks(this);

        pipeline.setVisualStabilityManager(mNotifStabilityManager);
    }
@@ -112,11 +121,18 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
            new NotifStabilityManager("VisualStabilityCoordinator") {
                @Override
                public void onBeginRun() {
                    mIsSuppressingPipelineRun = false;
                    mIsSuppressingGroupChange = false;
                    mEntriesWithSuppressedSectionChange.clear();
                    mIsSuppressingEntryReorder = false;
                }

                @Override
                public boolean isPipelineRunAllowed() {
                    mIsSuppressingPipelineRun |= !mPipelineRunAllowed;
                    return mPipelineRunAllowed;
                }

                @Override
                public boolean isGroupChangeAllowed(@NonNull NotificationEntry entry) {
                    final boolean isGroupChangeAllowedForEntry =
@@ -154,9 +170,12 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
            };

    private void updateAllowedStates() {
        mPipelineRunAllowed = !isPanelCollapsingOrLaunchingActivity();
        mReorderingAllowed = isReorderingAllowed();
        if (mReorderingAllowed && (mIsSuppressingGroupChange || isSuppressingSectionChange()
                || mIsSuppressingEntryReorder)) {
        if ((mPipelineRunAllowed && mIsSuppressingPipelineRun)
                || (mReorderingAllowed && (mIsSuppressingGroupChange
                        || isSuppressingSectionChange()
                        || mIsSuppressingEntryReorder))) {
            mNotifStabilityManager.invalidateList();
        }
    }
@@ -165,6 +184,10 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
        return !mEntriesWithSuppressedSectionChange.isEmpty();
    }

    private boolean isPanelCollapsingOrLaunchingActivity() {
        return mNotifPanelCollapsing || mNotifPanelLaunchingActivity;
    }

    private boolean isReorderingAllowed() {
        return (!mScreenOn || !mPanelExpanded) && !mPulsing;
    }
@@ -248,4 +271,16 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable {
            pw.println("  " + key);
        }
    }

    @Override
    public void onPanelCollapsingChanged(boolean isCollapsing) {
        mNotifPanelCollapsing = isCollapsing;
        updateAllowedStates();
    }

    @Override
    public void onLaunchingActivityChanged(boolean isLaunchingActivity) {
        mNotifPanelLaunchingActivity = isLaunchingActivity;
        updateAllowedStates();
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -306,6 +306,9 @@ class ShadeListBuilderLogger @Inject constructor(
            }
        }
    }

    fun logPipelineRunSuppressed() =
            buffer.log(TAG, INFO, {}) { "Suppressing pipeline run during animation." }
}

private const val TAG = "ShadeListBuilder"
 No newline at end of file
+11 −0
Original line number Diff line number Diff line
@@ -27,6 +27,16 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry
 */
abstract class NotifStabilityManager protected constructor(name: String) :
    Pluggable<NotifStabilityManager>(name) {

    /**
     * Called prior to running the pipeline to suppress any visual changes. Ex: collapse animation
     * is playing, moving stuff around simultaneously will look janky.
     *
     * Note: this is invoked *before* [onBeginRun], so that implementors can reference state
     * maintained from a previous run.
     */
    abstract fun isPipelineRunAllowed(): Boolean

    /**
     * Called at the beginning of every pipeline run to perform any necessary cleanup from the
     * previous run.
@@ -76,6 +86,7 @@ abstract class NotifStabilityManager protected constructor(name: String) :

/** The default, no-op instance of the stability manager which always allows all changes */
object DefaultNotifStabilityManager : NotifStabilityManager("DefaultNotifStabilityManager") {
    override fun isPipelineRunAllowed(): Boolean = true
    override fun onBeginRun() {}
    override fun isGroupChangeAllowed(entry: NotificationEntry): Boolean = true
    override fun isSectionChangeAllowed(entry: NotificationEntry): Boolean = true
+128 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.systemui.statusbar.notification.collection.render

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.phone.NotificationPanelViewController
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope
import com.android.systemui.util.ListenerSet
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.multibindings.IntoSet

/** Provides certain notification panel events.  */
interface NotifPanelEventSource {

    /** Registers callbacks to be invoked when notification panel events occur.  */
    fun registerCallbacks(callbacks: Callbacks)

    /** Unregisters callbacks previously registered via [.registerCallbacks]  */
    fun unregisterCallbacks(callbacks: Callbacks)

    /** Callbacks for certain notification panel events. */
    interface Callbacks {

        /** Invoked when the notification panel starts or stops collapsing. */
        fun onPanelCollapsingChanged(isCollapsing: Boolean)

        /**
         * Invoked when the notification panel starts or stops launching an [android.app.Activity].
         */
        fun onLaunchingActivityChanged(isLaunchingActivity: Boolean)
    }
}

@Module
abstract class NotifPanelEventSourceModule {

    @Binds
    @SysUISingleton
    abstract fun bindEventSource(manager: NotifPanelEventSourceManager): NotifPanelEventSource

    @Module
    companion object {
        @JvmStatic
        @Provides
        fun provideManager(): NotifPanelEventSourceManager = NotifPanelEventSourceManagerImpl()
    }
}

@Module
object StatusBarNotifPanelEventSourceModule {
    @JvmStatic
    @Provides
    @IntoSet
    @StatusBarScope
    fun bindStartable(
        manager: NotifPanelEventSourceManager,
        notifPanelController: NotificationPanelViewController
    ): StatusBarComponent.Startable =
            EventSourceStatusBarStartableImpl(manager, notifPanelController)
}

/**
 * Management layer that bridges [SysUiSingleton] and [StatusBarScope]. Necessary because code that
 * wants to listen to [NotifPanelEventSource] lives in [SysUiSingleton], but the events themselves
 * come from [NotificationPanelViewController] in [StatusBarScope].
 */
interface NotifPanelEventSourceManager : NotifPanelEventSource {
    var eventSource: NotifPanelEventSource?
}

private class NotifPanelEventSourceManagerImpl
    : NotifPanelEventSourceManager, NotifPanelEventSource.Callbacks {

    private val callbackSet = ListenerSet<NotifPanelEventSource.Callbacks>()

    override var eventSource: NotifPanelEventSource? = null
        set(value) {
            field?.unregisterCallbacks(this)
            value?.registerCallbacks(this)
            field = value
        }

    override fun registerCallbacks(callbacks: NotifPanelEventSource.Callbacks) {
        callbackSet.addIfAbsent(callbacks)
    }

    override fun unregisterCallbacks(callbacks: NotifPanelEventSource.Callbacks) {
        callbackSet.remove(callbacks)
    }

    override fun onPanelCollapsingChanged(isCollapsing: Boolean) {
        callbackSet.forEach { it.onPanelCollapsingChanged(isCollapsing) }
    }

    override fun onLaunchingActivityChanged(isLaunchingActivity: Boolean) {
        callbackSet.forEach { it.onLaunchingActivityChanged(isLaunchingActivity) }
    }
}

private class EventSourceStatusBarStartableImpl(
    private val manager: NotifPanelEventSourceManager,
    private val notifPanelController: NotificationPanelViewController
) : StatusBarComponent.Startable {

    override fun start() {
        manager.eventSource = notifPanelController
    }

    override fun stop() {
        manager.eventSource = null
    }
}
Loading