Moving TisBinder to its own class

> Using callback patter for various change events instead of routing it
  via  TIS

Bug: 386288280
Test: Presubmit
Flag: EXEMPT refactor
Change-Id: I95577d6a1c17103cb947ef1200c1c22b68fd1d9c
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index f704254..66f19eb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -71,6 +71,7 @@
 import com.android.launcher3.util.SimpleBroadcastReceiver;
 import com.android.quickstep.AllAppsActionManager;
 import com.android.quickstep.RecentsActivity;
+import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.fallback.window.RecentsDisplayModel;
 import com.android.quickstep.fallback.window.RecentsWindowManager;
@@ -84,6 +85,7 @@
 
 import java.io.PrintWriter;
 import java.util.StringJoiner;
+import java.util.function.LongConsumer;
 
 /**
  * Class to manage taskbar lifecycle
@@ -244,6 +246,8 @@
                 }
             };
 
+    private final LongConsumer mSysUiFlagChangeReceiver = this::onSystemUiFlagsChanged;
+
     @SuppressLint("WrongConstant")
     public TaskbarManager(
             Context context,
@@ -278,6 +282,10 @@
                     mPrimaryWindowContext, RECEIVER_NOT_EXPORTED, ACTION_SHOW_TASKBAR);
         });
 
+        RecentsAnimationDeviceState deviceState = RecentsAnimationDeviceState.INSTANCE.get(context);
+        onSystemUiFlagsChanged(deviceState.getSystemUiStateFlags());
+        deviceState.addSysUiFlagChangeCallback(mSysUiFlagChangeReceiver);
+
         debugWhyTaskbarNotDestroyed("TaskbarManager created");
         recreateTaskbar();
     }
@@ -606,7 +614,7 @@
         }
     }
 
-    public void onSystemUiFlagsChanged(@SystemUiStateFlags long systemUiStateFlags) {
+    private void onSystemUiFlagsChanged(@SystemUiStateFlags long systemUiStateFlags) {
         if (DEBUG) {
             Log.d(TAG, "SysUI flags changed: " + formatFlagChange(systemUiStateFlags,
                     mSharedState.sysuiStateFlags, QuickStepContract::getSystemUiStateString));
@@ -804,6 +812,8 @@
                 .unregister(USER_SETUP_COMPLETE_URI, mOnSettingsChangeListener);
         SettingsCache.INSTANCE.get(mPrimaryWindowContext)
                 .unregister(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener);
+        RecentsAnimationDeviceState.INSTANCE.get(getPrimaryWindowContext())
+                .removeSysUiFlagChangeCallback(mSysUiFlagChangeReceiver);
         Log.d(TASKBAR_NOT_DESTROYED_TAG, "unregistering component callbacks from destroy().");
         mPrimaryWindowContext.unregisterComponentCallbacks(mDefaultComponentCallbacks);
         mShutdownReceiver.unregisterReceiverSafely(mPrimaryWindowContext);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 23f4f67..6eec7d5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -172,10 +172,12 @@
 import com.android.quickstep.OverviewCommandHelper;
 import com.android.quickstep.OverviewComponentObserver;
 import com.android.quickstep.OverviewComponentObserver.OverviewChangeListener;
+import com.android.quickstep.RecentsAnimationDeviceState;
+import com.android.quickstep.RecentsAnimationDeviceState.AssistantVisibilityChangeListener;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TISBinder;
 import com.android.quickstep.TaskUtils;
-import com.android.quickstep.TouchInteractionService.TISBinder;
 import com.android.quickstep.util.ActiveGestureProtoLogProxy;
 import com.android.quickstep.util.AsyncClockEventDelegate;
 import com.android.quickstep.util.LauncherUnfoldAnimationController;
@@ -222,7 +224,7 @@
 import java.util.stream.Stream;
 
 public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
-        SystemShortcut.BubbleActivityStarter {
+        SystemShortcut.BubbleActivityStarter, AssistantVisibilityChangeListener {
     private static final boolean TRACE_LAYOUTS =
             SystemProperties.getBoolean("persist.debug.trace_layouts", false);
     private static final String TRACE_RELAYOUT_CLASS =
@@ -593,6 +595,8 @@
         mHotseatPredictionController.destroy();
         if (mViewCapture != null) mViewCapture.close();
         removeBackAnimationCallback(mSplitSelectStateController.getSplitBackHandler());
+        RecentsAnimationDeviceState.INSTANCE.get(this)
+                .removeAssistantVisibilityChangeListener(this);
     }
 
     @Override
@@ -726,6 +730,7 @@
         View.setTracedRequestLayoutClassClass(TRACE_RELAYOUT_CLASS);
         OverviewComponentObserver.INSTANCE.get(this)
                 .addOverviewChangeListener(mOverviewChangeListener);
+        RecentsAnimationDeviceState.INSTANCE.get(this).addAssistantVisibilityChangeListener(this);
     }
 
     @Override
@@ -1085,7 +1090,6 @@
         if (taskbarManager != null) {
             taskbarManager.setActivity(this);
         }
-        mTISBindHelper.setPredictiveBackToHomeInProgress(mIsPredictiveBackToHomeInProgress);
     }
 
     @Override
@@ -1359,7 +1363,8 @@
      */
     public void setPredictiveBackToHomeInProgress(boolean isInProgress) {
         mIsPredictiveBackToHomeInProgress = isInProgress;
-        mTISBindHelper.setPredictiveBackToHomeInProgress(isInProgress);
+        RecentsAnimationDeviceState.INSTANCE.get(this)
+                .setPredictiveBackToHomeInProgress(isInProgress);
     }
 
     public boolean getPredictiveBackToHomeInProgress() {
@@ -1501,6 +1506,11 @@
         return getStateManager().getState().isRecentsViewVisible;
     }
 
+    @Override
+    public void onAssistantVisibilityChanged(float visibility) {
+        mHotseat.getQsb().setAlpha(1f - visibility);
+    }
+
     public boolean isCanShowAllAppsEducationView() {
         return mCanShowAllAppsEducationView;
     }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index ff726e6..865e16b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -28,8 +28,6 @@
 import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
 import static com.android.launcher3.util.NavigationMode.THREE_BUTTONS;
 import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
 
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
@@ -47,7 +45,7 @@
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.VibratorWrapper;
-import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.MotionPauseDetector;
 import com.android.quickstep.util.OverviewToHomeAnim;
@@ -113,8 +111,8 @@
             return false;
         }
         mDidTouchStartInNavBar = (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
-        boolean isOneHandedModeActive = (SystemUiProxy.INSTANCE.get(mLauncher)
-                .getLastSystemUiStateFlags() & SYSUI_STATE_ONE_HANDED_ACTIVE) != 0;
+        boolean isOneHandedModeActive =
+                RecentsAnimationDeviceState.INSTANCE.get(mLauncher).isOneHandedModeActive();
         // Reset touch slop multiplier to default 1.0f if one-handed-mode is not active
         mDetector.setTouchSlopMultiplier(
                 isOneHandedModeActive ? ONE_HANDED_ACTIVATED_SLOP_MULTIPLIER : 1f /* default */);
@@ -250,9 +248,8 @@
     }
 
     private boolean handlingOverviewAnim() {
-        long stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags();
         return mDidTouchStartInNavBar && mStartState == NORMAL
-                && (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0;
+                && !RecentsAnimationDeviceState.INSTANCE.get(mLauncher).isOverviewDisabled();
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 05d12c3..6bca4c7 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -55,7 +55,6 @@
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
 import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
 import static com.android.quickstep.views.RecentsView.TASK_THUMBNAIL_SPLASH_ALPHA;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
 
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
@@ -79,7 +78,7 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.util.VibratorWrapper;
-import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.MotionPauseDetector;
@@ -178,8 +177,7 @@
         if ((ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) == 0) {
             return false;
         }
-        long stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags();
-        if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) {
+        if (RecentsAnimationDeviceState.INSTANCE.get(mLauncher).isOverviewDisabled()) {
             return false;
         }
         if (isTrackpadMultiFingerSwipe(ev)) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index f582324..7547f15 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -34,7 +34,6 @@
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
 import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
 
 import android.view.MotionEvent;
 
@@ -46,7 +45,7 @@
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.NavigationMode;
-import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
@@ -84,8 +83,7 @@
 
     @Override
     protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
-        long stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags();
-        if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) {
+        if (RecentsAnimationDeviceState.INSTANCE.get(mLauncher).isOverviewDisabled()) {
             return NORMAL;
         }
         return isDragTowardPositive ? QUICK_SWITCH_FROM_HOME : NORMAL;
diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
index 6d588d9..82fbaa6 100644
--- a/quickstep/src/com/android/quickstep/BaseContainerInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
@@ -83,8 +83,6 @@
 
     public abstract boolean isInLiveTileMode();
 
-    public abstract void onAssistantVisibilityChanged(float assistantVisibility);
-
     public abstract boolean isResumed();
 
     public abstract boolean isStarted();
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index d8e0296..d122d24 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -69,14 +69,6 @@
         }
     }
 
-    /** 5 */
-    @Override
-    public void onAssistantVisibilityChanged(float visibility) {
-        // This class becomes active when the screen is locked.
-        // Rather than having it handle assistant visibility changes, the assistant visibility is
-        // set to zero prior to this class becoming active.
-    }
-
     /** 6 */
     @Override
     public AnimationFactory prepareRecentsUI(
diff --git a/quickstep/src/com/android/quickstep/FallbackWindowInterface.java b/quickstep/src/com/android/quickstep/FallbackWindowInterface.java
index 35630ef..33fe02e 100644
--- a/quickstep/src/com/android/quickstep/FallbackWindowInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackWindowInterface.java
@@ -70,14 +70,6 @@
         }
     }
 
-    /** 5 */
-    @Override
-    public void onAssistantVisibilityChanged(float visibility) {
-        // This class becomes active when the screen is locked.
-        // Rather than having it handle assistant visibility changes, the assistant visibility is
-        // set to zero prior to this class becoming active.
-    }
-
     /** 6 */
     @Override
     public BaseWindowInterface.AnimationFactory prepareRecentsUI(boolean activityVisible,
diff --git a/quickstep/src/com/android/quickstep/InputConsumerUtils.kt b/quickstep/src/com/android/quickstep/InputConsumerUtils.kt
index c340c92..1a82d3b 100644
--- a/quickstep/src/com/android/quickstep/InputConsumerUtils.kt
+++ b/quickstep/src/com/android/quickstep/InputConsumerUtils.kt
@@ -18,7 +18,6 @@
 import android.content.Context
 import android.view.MotionEvent
 import androidx.annotation.VisibleForTesting
-import com.android.launcher3.anim.AnimatedFloat
 import com.android.launcher3.statemanager.BaseState
 import com.android.launcher3.statemanager.StatefulContainer
 import com.android.launcher3.taskbar.TaskbarManager
@@ -47,7 +46,6 @@
 import com.android.systemui.shared.system.InputMonitorCompat
 import com.android.wm.shell.Flags
 import java.util.function.Consumer
-import java.util.function.Function
 
 /** Utility class for creating input consumers. */
 object InputConsumerUtils {
@@ -68,7 +66,6 @@
         onCompleteCallback: Consumer<OtherActivityInputConsumer>,
         inputEventReceiver: InputChannelCompat.InputEventReceiver,
         taskbarManager: TaskbarManager,
-        swipeUpProxyProvider: Function<GestureState?, AnimatedFloat?>,
         overviewCommandHelper: OverviewCommandHelper,
         event: MotionEvent,
     ): InputConsumer where T : RecentsViewContainer, T : StatefulContainer<S> {
@@ -83,7 +80,7 @@
             )
             return consumer
         }
-        val progressProxy = swipeUpProxyProvider.apply(gestureState)
+        val progressProxy = deviceState.getSwipeUpProxy(gestureState)
         if (progressProxy != null) {
             val consumer: InputConsumer =
                 ProgressDelegateInputConsumer(
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index ac0aa76..2c37470 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -97,15 +97,6 @@
     }
 
     @Override
-    public void onAssistantVisibilityChanged(float visibility) {
-        QuickstepLauncher launcher = getCreatedContainer();
-        if (launcher == null) {
-            return;
-        }
-        launcher.onAssistantVisibilityChanged(visibility);
-    }
-
-    @Override
     public AnimationFactory prepareRecentsUI(
             boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback) {
         notifyRecentsOfOrientation();
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 1f95c41..a34b239 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -57,6 +57,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.LongConsumer;
 
 import javax.inject.Inject;
 
@@ -79,6 +80,7 @@
 
     private final Context mContext;
     private final RecentsDisplayModel mRecentsDisplayModel;
+    private final RecentsAnimationDeviceState mDeviceState;
 
     private final Intent mCurrentHomeIntent;
     private final Intent mMyHomeIntent;
@@ -100,9 +102,11 @@
     public OverviewComponentObserver(
             @ApplicationContext Context context,
             RecentsDisplayModel recentsDisplayModel,
+            RecentsAnimationDeviceState deviceState,
             DaggerSingletonTracker lifecycleTracker) {
         mContext = context;
         mRecentsDisplayModel = recentsDisplayModel;
+        mDeviceState = deviceState;
         mCurrentHomeIntent = createHomeIntent();
         mMyHomeIntent = new Intent(mCurrentHomeIntent).setPackage(mContext.getPackageName());
         ResolveInfo info = context.getPackageManager().resolveActivity(mMyHomeIntent, 0);
@@ -128,6 +132,12 @@
         updateOverviewTargets();
 
         lifecycleTracker.addCloseable(this::onDestroy);
+
+        setHomeDisabled(deviceState.isHomeDisabled());
+        LongConsumer flagChangeCallback = l -> setHomeDisabled(deviceState.isHomeDisabled());
+        deviceState.addSysUiFlagChangeCallback(flagChangeCallback);
+        lifecycleTracker.addCloseable(
+                () -> deviceState.removeSysUiFlagChangeCallback(flagChangeCallback));
     }
 
     /** Adds a listener for changes in {@link #isHomeAndOverviewSame()} */
@@ -140,11 +150,7 @@
         mOverviewChangeListeners.remove(overviewChangeListener);
     }
 
-    /**
-     * Called to set home enabled/disabled state via systemUI
-     * @param isHomeDisabled
-     */
-    public void setHomeDisabled(boolean isHomeDisabled) {
+    private void setHomeDisabled(boolean isHomeDisabled) {
         if (isHomeDisabled != mIsHomeDisabled) {
             mIsHomeDisabled = isHomeDisabled;
             updateOverviewTargets();
@@ -175,9 +181,7 @@
         // Set assistant visibility to 0 from launcher's perspective, ensures any elements that
         // launcher made invisible become visible again before the new activity control helper
         // becomes active.
-        if (mContainerInterface != null) {
-            mContainerInterface.onAssistantVisibilityChanged(0.f);
-        }
+        mDeviceState.setAssistantVisibility(0f);
 
         if (SEPARATE_RECENTS_ACTIVITY.get() || Flags.enableLauncherOverviewInWindow()) {
             mIsDefaultHome = false;
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 9b0e75c..90221f3 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -172,7 +172,7 @@
                 return response;
 
             case TestProtocol.REQUEST_REFRESH_OVERVIEW_TARGET:
-                runOnTISBinder(TouchInteractionService.TISBinder::refreshOverviewTarget);
+                runOnTISBinder(TISBinder::refreshOverviewTarget);
                 return response;
 
             case TestProtocol.REQUEST_RECREATE_TASKBAR:
@@ -220,7 +220,7 @@
     }
 
     private void enableBlockingTimeout(
-            TouchInteractionService.TISBinder tisBinder, boolean enable) {
+            TISBinder tisBinder, boolean enable) {
         TaskbarActivityContext context = tisBinder.getTaskbarManager().getCurrentActivityContext();
         if (context == null) {
             return;
@@ -236,7 +236,7 @@
      * Runs the given command on the UI thread, after ensuring we are connected to
      * TouchInteractionService.
      */
-    protected void runOnTISBinder(Consumer<TouchInteractionService.TISBinder> connectionCallback) {
+    protected void runOnTISBinder(Consumer<TISBinder> connectionCallback) {
         try {
             CountDownLatch countDownLatch = new CountDownLatch(1);
             TISBindHelper helper = MAIN_EXECUTOR.submit(() ->
@@ -252,7 +252,7 @@
     }
 
     private <T> Bundle getTISBinderUIProperty(
-            BundleSetter<T> bundleSetter, Function<TouchInteractionService.TISBinder, T> provider) {
+            BundleSetter<T> bundleSetter, Function<TISBinder, T> provider) {
         Bundle response = new Bundle();
 
         runOnTISBinder(tisBinder -> bundleSetter.set(
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index fca67c3..760130e 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -165,7 +165,7 @@
         mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
     }
 
-    private void onTISConnected(TouchInteractionService.TISBinder binder) {
+    private void onTISConnected(TISBinder binder) {
         TaskbarManager taskbarManager = binder.getTaskbarManager();
         if (taskbarManager != null) {
             taskbarManager.setActivity(this);
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 090ccdc..322e7c4 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -64,6 +64,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.dagger.ApplicationContext;
 import com.android.launcher3.dagger.LauncherAppComponent;
 import com.android.launcher3.dagger.LauncherAppSingleton;
@@ -88,6 +89,10 @@
 import com.android.systemui.shared.system.TaskStackChangeListeners;
 
 import java.io.PrintWriter;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Function;
+import java.util.function.LongConsumer;
 
 import javax.inject.Inject;
 
@@ -118,12 +123,16 @@
     private final boolean mCanImeRenderGesturalNavButtons =
             InputMethodService.canImeRenderGesturalNavButtons();
 
+    private final List<LongConsumer> mFlagChangeCallbacks = new CopyOnWriteArrayList<>();
     private @SystemUiStateFlags long mSystemUiStateFlags = QuickStepContract.SYSUI_STATE_AWAKE;
     private NavigationMode mMode = THREE_BUTTONS;
     private NavBarPosition mNavBarPosition;
 
     private final Region mDeferredGestureRegion = new Region();
     private boolean mAssistantAvailable;
+
+    private final List<AssistantVisibilityChangeListener> mAssistantVisibilityChangeListeners =
+            new CopyOnWriteArrayList<>();
     private float mAssistantVisibility;
     private boolean mIsUserSetupComplete;
     private boolean mIsOneHandedModeEnabled;
@@ -136,6 +145,8 @@
     private @NonNull Region mExclusionRegion = GestureExclusionManager.EMPTY_REGION;
     private boolean mExclusionListenerRegistered;
 
+    private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = null;
+
     @VisibleForTesting
     @Inject
     RecentsAnimationDeviceState(
@@ -355,8 +366,9 @@
     /**
      * Updates the system ui state flags from SystemUI.
      */
-    public void setSystemUiFlags(@SystemUiStateFlags long stateFlags) {
+    public void setSystemUiStateFlags(@SystemUiStateFlags long stateFlags) {
         mSystemUiStateFlags = stateFlags;
+        mFlagChangeCallbacks.forEach(c -> c.accept(stateFlags));
     }
 
     /**
@@ -369,6 +381,20 @@
     }
 
     /**
+     * Adds a callback to receiver sysui flag changes
+     */
+    public void addSysUiFlagChangeCallback(LongConsumer callback) {
+        mFlagChangeCallbacks.add(callback);
+    }
+
+    /**
+     * Removes a previously added sysui flag change callback
+     */
+    public void removeSysUiFlagChangeCallback(LongConsumer callback) {
+        mFlagChangeCallbacks.remove(callback);
+    }
+
+    /**
      * Sets the flag that indicates whether a predictive back-to-home animation is in progress
      */
     public void setPredictiveBackToHomeInProgress(boolean isInProgress) {
@@ -383,6 +409,22 @@
     }
 
     /**
+     * Sets or clears a function to proxy swipe up transition behavior
+     */
+    public void setSwipeUpProxyProvider(
+            @Nullable Function<GestureState, AnimatedFloat> swipeUpProxyProvider) {
+        mSwipeUpProxyProvider = swipeUpProxyProvider;
+    }
+
+    /**
+     * Returns a proxy animation for swipe up transition if a proxy function was previously set
+     */
+    public AnimatedFloat getSwipeUpProxy(GestureState state) {
+        Function<GestureState, AnimatedFloat> provider = mSwipeUpProxyProvider;
+        return provider != null ? provider.apply(state) : null;
+    }
+
+    /**
      * @return whether SystemUI is in a state where we can start a system gesture.
      */
     public boolean canStartSystemGesture() {
@@ -535,6 +577,8 @@
      */
     public void setAssistantVisibility(float visibility) {
         mAssistantVisibility = visibility;
+        mAssistantVisibilityChangeListeners.forEach(
+                l -> l.onAssistantVisibilityChanged(visibility));
     }
 
     /**
@@ -544,6 +588,16 @@
         return mAssistantVisibility;
     }
 
+    /** Add a listener for assistant visibility changes */
+    public void addAssistantVisibilityChangeListener(AssistantVisibilityChangeListener l) {
+        mAssistantVisibilityChangeListeners.add(l);
+    }
+
+    /** Removes a previously added visibility change listener */
+    public void removeAssistantVisibilityChangeListener(AssistantVisibilityChangeListener l) {
+        mAssistantVisibilityChangeListeners.remove(l);
+    }
+
     /**
      * @return whether the Assistant gesture can be used in 3 button navigation mode.
      */
@@ -633,6 +687,13 @@
         return  QuickStepContract.getSystemUiStateString(mSystemUiStateFlags);
     }
 
+    /** Interface for listening assistant visibility change */
+    @FunctionalInterface
+    public interface AssistantVisibilityChangeListener {
+        /** Called when assistant visibility changes */
+        void onAssistantVisibilityChanged(float visibility);
+    }
+
     public void dump(PrintWriter pw) {
         pw.println("DeviceState:");
         pw.println("  canStartSystemGesture=" + canStartSystemGesture());
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.kt b/quickstep/src/com/android/quickstep/SystemUiProxy.kt
index a1ac39e..32bdcdb 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.kt
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.kt
@@ -65,7 +65,6 @@
 import com.android.systemui.shared.recents.ISystemUiProxy
 import com.android.systemui.shared.recents.model.ThumbnailData.Companion.wrap
 import com.android.systemui.shared.system.QuickStepContract
-import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat
 import com.android.systemui.shared.system.RecentsAnimationListener
 import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController
@@ -162,9 +161,6 @@
     private val asyncHandler =
         Handler(Executors.UI_HELPER_EXECUTOR.looper) { handleMessageAsync(it) }
 
-    // TODO(141886704): Find a way to remove this
-    @SystemUiStateFlags var lastSystemUiStateFlags: Long = 0
-
     /**
      * This is a singleton pending intent that is used to start recents via Shell (which is a
      * different process). It is bare-bones, so it's expected that the component and options will be
@@ -194,7 +190,7 @@
     private inline fun executeWithErrorLog(
         errorMsg: () -> String,
         tag: String = TAG,
-        callback: () -> Any?,
+        callback: () -> Unit,
     ) {
         try {
             callback.invoke()
@@ -232,36 +228,30 @@
      * Sets proxy state, including death linkage, various listeners, and other configuration objects
      */
     @MainThread
-    fun setProxy(
-        proxy: ISystemUiProxy?,
-        pip: IPip?,
-        bubbles: IBubbles?,
-        splitScreen: ISplitScreen?,
-        oneHanded: IOneHanded?,
-        shellTransitions: IShellTransitions?,
-        startingWindow: IStartingWindow?,
-        recentTasks: IRecentTasks?,
-        sysuiUnlockAnimationController: ISysuiUnlockAnimationController?,
-        backAnimation: IBackAnimation?,
-        desktopMode: IDesktopMode?,
-        unfoldAnimation: IUnfoldAnimation?,
-        dragAndDrop: IDragAndDrop?,
-    ) {
+    fun setProxy(bundle: Bundle) {
         Preconditions.assertUIThread()
         unlinkToDeath()
-        systemUiProxy = proxy
-        this.pip = pip
-        this.bubbles = bubbles
-        this.splitScreen = splitScreen
-        this.oneHanded = oneHanded
-        this.shellTransitions = shellTransitions
-        this.startingWindow = startingWindow
-        this.sysuiUnlockAnimationController = sysuiUnlockAnimationController
-        this.recentTasks = recentTasks
-        this.backAnimation = backAnimation
-        this.desktopMode = desktopMode
-        this.unfoldAnimation = if (Flags.enableUnfoldStateAnimation()) null else unfoldAnimation
-        this.dragAndDrop = dragAndDrop
+        systemUiProxy = ISystemUiProxy.Stub.asInterface(bundle.getBinder(ISystemUiProxy.DESCRIPTOR))
+        pip = IPip.Stub.asInterface(bundle.getBinder(IPip.DESCRIPTOR))
+        bubbles = IBubbles.Stub.asInterface(bundle.getBinder(IBubbles.DESCRIPTOR))
+        splitScreen = ISplitScreen.Stub.asInterface(bundle.getBinder(ISplitScreen.DESCRIPTOR))
+        oneHanded = IOneHanded.Stub.asInterface(bundle.getBinder(IOneHanded.DESCRIPTOR))
+        shellTransitions =
+            IShellTransitions.Stub.asInterface(bundle.getBinder(IShellTransitions.DESCRIPTOR))
+        startingWindow =
+            IStartingWindow.Stub.asInterface(bundle.getBinder(IStartingWindow.DESCRIPTOR))
+        sysuiUnlockAnimationController =
+            ISysuiUnlockAnimationController.Stub.asInterface(
+                bundle.getBinder(ISysuiUnlockAnimationController.DESCRIPTOR)
+            )
+        recentTasks = IRecentTasks.Stub.asInterface(bundle.getBinder(IRecentTasks.DESCRIPTOR))
+        backAnimation = IBackAnimation.Stub.asInterface(bundle.getBinder(IBackAnimation.DESCRIPTOR))
+        desktopMode = IDesktopMode.Stub.asInterface(bundle.getBinder(IDesktopMode.DESCRIPTOR))
+        unfoldAnimation =
+            if (Flags.enableUnfoldStateAnimation()) null
+            else IUnfoldAnimation.Stub.asInterface(bundle.getBinder(IUnfoldAnimation.DESCRIPTOR))
+        dragAndDrop = IDragAndDrop.Stub.asInterface(bundle.getBinder(IDragAndDrop.DESCRIPTOR))
+
         linkToDeath()
         // re-attach the listeners once missing due to setProxy has not been initialized yet.
         setPipAnimationListener(pipAnimationListener)
@@ -289,15 +279,12 @@
         stateChangeCallbacks.forEach { it.run() }
 
         if (unfoldTransitionProvider != null) {
-            if (unfoldAnimation != null) {
-                try {
-                    unfoldAnimation.setListener(unfoldTransitionProvider)
+            unfoldTransitionProvider.isActive = false
+            executeWithErrorLog({ "Failed to set unfold anim listener" }) {
+                unfoldAnimation?.apply {
+                    setListener(unfoldTransitionProvider)
                     unfoldTransitionProvider.isActive = true
-                } catch (e: RemoteException) {
-                    // Ignore
                 }
-            } else {
-                unfoldTransitionProvider.isActive = false
             }
         }
     }
@@ -305,9 +292,7 @@
     /**
      * Clear the proxy to release held resources and turn the majority of its operations into no-ops
      */
-    @MainThread
-    fun clearProxy() =
-        setProxy(null, null, null, null, null, null, null, null, null, null, null, null, null)
+    @MainThread fun clearProxy() = setProxy(Bundle.EMPTY)
 
     /** Adds a callback to be notified whenever the active state changes */
     fun addOnStateChangeListener(callback: Runnable) = stateChangeCallbacks.add(callback)
diff --git a/quickstep/src/com/android/quickstep/TISBinder.kt b/quickstep/src/com/android/quickstep/TISBinder.kt
new file mode 100644
index 0000000..683012c
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/TISBinder.kt
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2025 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.quickstep
+
+import android.graphics.Region
+import android.os.Bundle
+import android.os.IRemoteCallback
+import android.os.RemoteException
+import android.util.Log
+import androidx.annotation.BinderThread
+import androidx.annotation.VisibleForTesting
+import com.android.launcher3.taskbar.TaskbarManager
+import com.android.launcher3.testing.TestLogging
+import com.android.launcher3.testing.shared.TestProtocol
+import com.android.launcher3.util.Executors
+import com.android.quickstep.OverviewCommandHelper.CommandType.HIDE
+import com.android.quickstep.OverviewCommandHelper.CommandType.KEYBOARD_INPUT
+import com.android.quickstep.OverviewCommandHelper.CommandType.SHOW
+import com.android.quickstep.OverviewCommandHelper.CommandType.TOGGLE
+import com.android.quickstep.util.ActivityPreloadUtil.preloadOverviewForTIS
+import com.android.quickstep.util.ContextualSearchInvoker
+import com.android.systemui.shared.recents.ILauncherProxy
+import com.android.systemui.shared.statusbar.phone.BarTransitions.TransitionMode
+import com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS
+import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags
+import java.lang.ref.WeakReference
+
+/** Local ILauncherProxy implementation with some methods for local components */
+private const val TAG = "TISBinder"
+
+class TISBinder internal constructor(tis: TouchInteractionService) : ILauncherProxy.Stub() {
+
+    private val mTis = WeakReference(tis)
+
+    /** Returns the [TaskbarManager] or `null` if TouchInteractionService is not connected */
+    val taskbarManager: TaskbarManager?
+        get() = mTis.get()?.taskbarManager
+
+    /** Returns the [OverviewCommandHelper] or `null` if TouchInteractionService is not connected */
+    val overviewCommandHelper: OverviewCommandHelper?
+        get() = mTis.get()?.overviewCommandHelper
+
+    private val deviceState: RecentsAnimationDeviceState?
+        get() = mTis.get()?.let { RecentsAnimationDeviceState.INSTANCE[it] }
+
+    private inline fun executeForTaskbarManagerOnMain(
+        crossinline callback: TaskbarManager.() -> Unit
+    ) {
+        Executors.MAIN_EXECUTOR.execute { taskbarManager?.let { callback.invoke(it) } }
+    }
+
+    @BinderThread
+    override fun onInitialize(bundle: Bundle) {
+        Executors.MAIN_EXECUTOR.execute {
+            mTis.get()?.let {
+                SystemUiProxy.INSTANCE[it].setProxy(bundle)
+                preloadOverviewForTIS(it, true /* fromInit */)
+            }
+        }
+    }
+
+    @BinderThread
+    override fun onTaskbarToggled() {
+        executeForTaskbarManagerOnMain { currentActivityContext?.toggleTaskbarStash() }
+    }
+
+    @BinderThread
+    override fun onOverviewToggle() {
+        TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle")
+        mTis.get()?.let { tis ->
+            // If currently screen pinning, do not enter overview
+            if (RecentsAnimationDeviceState.INSTANCE[tis].isScreenPinningActive) {
+                return@let
+            }
+            TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS)
+            tis.overviewCommandHelper.addCommand(TOGGLE)
+        }
+    }
+
+    @BinderThread
+    override fun onOverviewShown(triggeredFromAltTab: Boolean) {
+        overviewCommandHelper?.apply {
+            if (triggeredFromAltTab) {
+                TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS)
+                addCommand(KEYBOARD_INPUT)
+            } else {
+                addCommand(SHOW)
+            }
+        }
+    }
+
+    @BinderThread
+    override fun onOverviewHidden(triggeredFromAltTab: Boolean, triggeredFromHomeKey: Boolean) {
+        overviewCommandHelper?.apply {
+            if (triggeredFromAltTab && !triggeredFromHomeKey) {
+                // onOverviewShownFromAltTab hides the overview and ends at the target app
+                addCommand(HIDE)
+            }
+        }
+    }
+
+    @BinderThread
+    override fun onAssistantAvailable(available: Boolean, longPressHomeEnabled: Boolean) {
+        Executors.MAIN_EXECUTOR.execute {
+            deviceState?.setAssistantAvailable(available)
+            taskbarManager?.onLongPressHomeEnabled(longPressHomeEnabled)
+        }
+    }
+
+    @BinderThread
+    override fun onAssistantVisibilityChanged(visibility: Float) {
+        Executors.MAIN_EXECUTOR.execute { deviceState?.assistantVisibility = visibility }
+    }
+
+    /**
+     * Sent when the assistant has been invoked with the given type (defined in AssistManager) and
+     * should be shown. This method is used if SystemUiProxy#setAssistantOverridesRequested was
+     * previously called including this invocation type.
+     */
+    override fun onAssistantOverrideInvoked(invocationType: Int) {
+        mTis.get()?.let { tis ->
+            if (!ContextualSearchInvoker(tis).tryStartAssistOverride(invocationType)) {
+                Log.w(TAG, "Failed to invoke Assist override")
+            }
+        }
+    }
+
+    @BinderThread
+    override fun onSystemUiStateChanged(@SystemUiStateFlags stateFlags: Long) {
+        Executors.MAIN_EXECUTOR.execute { deviceState?.systemUiStateFlags = stateFlags }
+    }
+
+    @BinderThread
+    override fun onActiveNavBarRegionChanges(region: Region) {
+        Executors.MAIN_EXECUTOR.execute { deviceState?.setDeferredGestureRegion(region) }
+    }
+
+    @BinderThread
+    override fun enterStageSplitFromRunningApp(leftOrTop: Boolean) {
+        mTis.get()?.let { tis ->
+            OverviewComponentObserver.INSTANCE[tis]
+                .containerInterface
+                .createdContainer
+                ?.enterStageSplitFromRunningApp(leftOrTop)
+        }
+    }
+
+    @BinderThread
+    override fun onDisplayAddSystemDecorations(displayId: Int) {
+        executeForTaskbarManagerOnMain { onDisplayAddSystemDecorations(displayId) }
+    }
+
+    @BinderThread
+    override fun onDisplayRemoved(displayId: Int) {
+        executeForTaskbarManagerOnMain { onDisplayRemoved(displayId) }
+    }
+
+    @BinderThread
+    override fun onDisplayRemoveSystemDecorations(displayId: Int) {
+        executeForTaskbarManagerOnMain { onDisplayRemoveSystemDecorations(displayId) }
+    }
+
+    @BinderThread
+    override fun updateWallpaperVisibility(displayId: Int, visible: Boolean) {
+        executeForTaskbarManagerOnMain { setWallpaperVisible(displayId, visible) }
+    }
+
+    @BinderThread
+    override fun checkNavBarModes(displayId: Int) {
+        executeForTaskbarManagerOnMain { checkNavBarModes(displayId) }
+    }
+
+    @BinderThread
+    override fun finishBarAnimations(displayId: Int) {
+        executeForTaskbarManagerOnMain { finishBarAnimations(displayId) }
+    }
+
+    @BinderThread
+    override fun touchAutoDim(displayId: Int, reset: Boolean) {
+        executeForTaskbarManagerOnMain { touchAutoDim(displayId, reset) }
+    }
+
+    @BinderThread
+    override fun transitionTo(displayId: Int, @TransitionMode barMode: Int, animate: Boolean) {
+        executeForTaskbarManagerOnMain { transitionTo(displayId, barMode, animate) }
+    }
+
+    @BinderThread
+    override fun appTransitionPending(pending: Boolean) {
+        executeForTaskbarManagerOnMain { appTransitionPending(pending) }
+    }
+
+    override fun onRotationProposal(rotation: Int, isValid: Boolean) {
+        executeForTaskbarManagerOnMain { onRotationProposal(rotation, isValid) }
+    }
+
+    override fun disable(displayId: Int, state1: Int, state2: Int, animate: Boolean) {
+        executeForTaskbarManagerOnMain { disableNavBarElements(displayId, state1, state2, animate) }
+    }
+
+    override fun onSystemBarAttributesChanged(displayId: Int, behavior: Int) {
+        executeForTaskbarManagerOnMain { onSystemBarAttributesChanged(displayId, behavior) }
+    }
+
+    override fun onTransitionModeUpdated(barMode: Int, checkBarModes: Boolean) {
+        executeForTaskbarManagerOnMain { onTransitionModeUpdated(barMode, checkBarModes) }
+    }
+
+    override fun onNavButtonsDarkIntensityChanged(darkIntensity: Float) {
+        executeForTaskbarManagerOnMain { onNavButtonsDarkIntensityChanged(darkIntensity) }
+    }
+
+    override fun onNavigationBarLumaSamplingEnabled(displayId: Int, enable: Boolean) {
+        executeForTaskbarManagerOnMain { onNavigationBarLumaSamplingEnabled(displayId, enable) }
+    }
+
+    override fun onUnbind(reply: IRemoteCallback) {
+        // Run everything in the same main thread block to ensure the cleanup happens before
+        // sending the reply.
+        Executors.MAIN_EXECUTOR.execute {
+            taskbarManager?.destroy()
+            try {
+                reply.sendResult(null)
+            } catch (e: RemoteException) {
+                Log.w(TAG, "onUnbind: Failed to reply to LauncherProxyService", e)
+            }
+        }
+    }
+
+    @VisibleForTesting
+    fun injectFakeTrackpadForTesting() = mTis.get()?.injectFakeTrackpadForTesting()
+
+    @VisibleForTesting fun ejectFakeTrackpadForTesting() = mTis.get()?.ejectFakeTrackpadForTesting()
+
+    @VisibleForTesting fun refreshOverviewTarget() = mTis.get()?.refreshOverviewTarget()
+}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 63b8aaf..e449048 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -54,22 +54,25 @@
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
 
 import java.io.PrintWriter;
 import java.util.HashMap;
+import java.util.function.LongConsumer;
 
 public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
     public static final boolean SHELL_TRANSITIONS_ROTATION =
             SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
 
     private final Context mCtx;
+    private final RecentsAnimationDeviceState mDeviceState;
+    private final SystemUiProxy mSystemUiProxy;
     private RecentsAnimationController mController;
     private RecentsAnimationCallbacks mCallbacks;
     private RecentsAnimationTargets mTargets;
     private TransitionInfo mTransitionInfo;
-    private RecentsAnimationDeviceState mDeviceState;
 
     // Temporary until we can hook into gesture state events
     private GestureState mLastGestureState;
@@ -102,12 +105,22 @@
         }
     };
 
+
+    private @SystemUiStateFlags long mLastSysuiFlags;
+    private final LongConsumer mSysUiFlagChangeCallback = this::onSystemUiFlagsChanged;
+
     TaskAnimationManager(Context ctx, RecentsAnimationDeviceState deviceState) {
+        this(ctx, deviceState, SystemUiProxy.INSTANCE.get(ctx));
+    }
+
+    TaskAnimationManager(Context ctx, RecentsAnimationDeviceState deviceState,
+            SystemUiProxy systemUiProxy) {
         mCtx = ctx;
         mDeviceState = deviceState;
-    }
-    SystemUiProxy getSystemUiProxy() {
-        return SystemUiProxy.INSTANCE.get(mCtx);
+        mSystemUiProxy = systemUiProxy;
+        mLastSysuiFlags = QuickStepContract.SYSUI_STATE_AWAKE;
+        mDeviceState.addSysUiFlagChangeCallback(mSysUiFlagChangeCallback);
+        onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags());
     }
 
     boolean shouldIgnoreMotionEvents() {
@@ -151,7 +164,7 @@
 
         final BaseContainerInterface containerInterface = gestureState.getContainerInterface();
         mLastGestureState = gestureState;
-        RecentsAnimationCallbacks newCallbacks = new RecentsAnimationCallbacks(getSystemUiProxy());
+        RecentsAnimationCallbacks newCallbacks = new RecentsAnimationCallbacks(mSystemUiProxy);
         mCallbacks = newCallbacks;
         mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
             @Override
@@ -289,7 +302,7 @@
         if(containerInterface.getCreatedContainer() instanceof RecentsWindowManager
                 && (Flags.enableFallbackOverviewInWindow()
                         || Flags.enableLauncherOverviewInWindow())) {
-            mRecentsAnimationStartPending = getSystemUiProxy().startRecentsActivity(intent, options,
+            mRecentsAnimationStartPending = mSystemUiProxy.startRecentsActivity(intent, options,
                     mCallbacks, gestureState.useSyntheticRecentsTransition());
             RecentsDisplayModel.getINSTANCE().get(mCtx)
                     .getRecentsWindowManager(mDeviceState.getDisplayId())
@@ -321,7 +334,7 @@
                 });
             }
 
-            mRecentsAnimationStartPending = getSystemUiProxy().startRecentsActivity(intent,
+            mRecentsAnimationStartPending = mSystemUiProxy.startRecentsActivity(intent,
                     options, mCallbacks, false /* useSyntheticRecentsTransition */);
         }
 
@@ -347,8 +360,13 @@
         return mCallbacks;
     }
 
-    public void onSystemUiFlagsChanged(@QuickStepContract.SystemUiStateFlags long lastSysUIFlags,
-            @QuickStepContract.SystemUiStateFlags long newSysUIFlags) {
+    private void onSystemUiFlagsChanged(@SystemUiStateFlags long newSysUIFlags) {
+        onSystemUiFlagsChanged(mLastSysuiFlags, newSysUIFlags);
+        mLastSysuiFlags = newSysUIFlags;
+    }
+
+    private void onSystemUiFlagsChanged(@SystemUiStateFlags long lastSysUIFlags,
+            @SystemUiStateFlags long newSysUIFlags) {
         long isShadeExpandedFlagMask =
                 SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
         boolean wasExpanded = hasAnyFlag(lastSysUIFlags, isShadeExpandedFlagMask);
@@ -509,4 +527,8 @@
             mLastGestureState.dump(prefix + '\t', pw);
         }
     }
+
+    public void onDestroy() {
+        mDeviceState.removeSysUiFlagChangeCallback(mSysUiFlagChangeCallback);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index ba4c65a..22fc2ea 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -36,7 +36,6 @@
 import static com.android.quickstep.InputConsumer.TYPE_CURSOR_HOVER;
 import static com.android.quickstep.InputConsumerUtils.newConsumer;
 import static com.android.quickstep.InputConsumerUtils.tryCreateAssistantInputConsumer;
-import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 
 import android.app.PendingIntent;
 import android.app.Service;
@@ -44,12 +43,9 @@
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.res.Configuration;
-import android.graphics.Region;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.os.IRemoteCallback;
 import android.os.Looper;
-import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Log;
 import android.view.Choreographer;
@@ -57,7 +53,6 @@
 import android.view.InputEvent;
 import android.view.MotionEvent;
 
-import androidx.annotation.BinderThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
@@ -67,7 +62,6 @@
 import com.android.launcher3.EncryptionType;
 import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherPrefs;
-import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.desktop.DesktopAppLaunchTransitionManager;
 import com.android.launcher3.statehandlers.DesktopVisibilityController;
 import com.android.launcher3.statemanager.StatefulActivity;
@@ -98,34 +92,14 @@
 import com.android.quickstep.util.ActiveGestureProtoLogProxy;
 import com.android.quickstep.util.ActiveTrackpadList;
 import com.android.quickstep.util.ActivityPreloadUtil;
-import com.android.quickstep.util.ContextualSearchInvoker;
 import com.android.quickstep.util.ContextualSearchStateManager;
 import com.android.quickstep.views.RecentsViewContainer;
-import com.android.systemui.shared.recents.ILauncherProxy;
-import com.android.systemui.shared.recents.ISystemUiProxy;
-import com.android.systemui.shared.statusbar.phone.BarTransitions;
 import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
 import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.shared.system.InputMonitorCompat;
-import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
-import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController;
-import com.android.systemui.unfold.progress.IUnfoldAnimation;
-import com.android.wm.shell.back.IBackAnimation;
-import com.android.wm.shell.bubbles.IBubbles;
-import com.android.wm.shell.common.pip.IPip;
-import com.android.wm.shell.desktopmode.IDesktopMode;
-import com.android.wm.shell.draganddrop.IDragAndDrop;
-import com.android.wm.shell.onehanded.IOneHanded;
-import com.android.wm.shell.recents.IRecentTasks;
-import com.android.wm.shell.shared.IShellTransitions;
-import com.android.wm.shell.splitscreen.ISplitScreen;
-import com.android.wm.shell.startingsurface.IStartingWindow;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-import java.util.function.Consumer;
-import java.util.function.Function;
 
 /**
  * Service connected by system-UI for handling touch interaction.
@@ -141,371 +115,6 @@
 
     private final TISBinder mTISBinder = new TISBinder(this);
 
-    /**
-     * Local ILauncherProxy implementation with some methods for local components
-     */
-    public static class TISBinder extends ILauncherProxy.Stub {
-
-        private final WeakReference<TouchInteractionService> mTis;
-
-        private TISBinder(TouchInteractionService tis) {
-            mTis = new WeakReference<>(tis);
-        }
-
-        @BinderThread
-        public void onInitialize(Bundle bundle) {
-            ISystemUiProxy proxy = ISystemUiProxy.Stub.asInterface(
-                    bundle.getBinder(ISystemUiProxy.DESCRIPTOR));
-            IPip pip = IPip.Stub.asInterface(bundle.getBinder(IPip.DESCRIPTOR));
-            IBubbles bubbles = IBubbles.Stub.asInterface(bundle.getBinder(IBubbles.DESCRIPTOR));
-            ISplitScreen splitscreen = ISplitScreen.Stub.asInterface(bundle.getBinder(
-                    ISplitScreen.DESCRIPTOR));
-            IOneHanded onehanded = IOneHanded.Stub.asInterface(
-                    bundle.getBinder(IOneHanded.DESCRIPTOR));
-            IShellTransitions shellTransitions = IShellTransitions.Stub.asInterface(
-                    bundle.getBinder(IShellTransitions.DESCRIPTOR));
-            IStartingWindow startingWindow = IStartingWindow.Stub.asInterface(
-                    bundle.getBinder(IStartingWindow.DESCRIPTOR));
-            ISysuiUnlockAnimationController launcherUnlockAnimationController =
-                    ISysuiUnlockAnimationController.Stub.asInterface(
-                            bundle.getBinder(ISysuiUnlockAnimationController.DESCRIPTOR));
-            IRecentTasks recentTasks = IRecentTasks.Stub.asInterface(
-                    bundle.getBinder(IRecentTasks.DESCRIPTOR));
-            IBackAnimation backAnimation = IBackAnimation.Stub.asInterface(
-                    bundle.getBinder(IBackAnimation.DESCRIPTOR));
-            IDesktopMode desktopMode = IDesktopMode.Stub.asInterface(
-                    bundle.getBinder(IDesktopMode.DESCRIPTOR));
-            IUnfoldAnimation unfoldTransition = IUnfoldAnimation.Stub.asInterface(
-                    bundle.getBinder(IUnfoldAnimation.DESCRIPTOR));
-            IDragAndDrop dragAndDrop = IDragAndDrop.Stub.asInterface(
-                    bundle.getBinder(IDragAndDrop.DESCRIPTOR));
-            MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> {
-                SystemUiProxy.INSTANCE.get(tis).setProxy(proxy, pip,
-                        bubbles, splitscreen, onehanded, shellTransitions, startingWindow,
-                        recentTasks, launcherUnlockAnimationController, backAnimation, desktopMode,
-                        unfoldTransition, dragAndDrop);
-                tis.initInputMonitor("TISBinder#onInitialize()");
-                ActivityPreloadUtil.preloadOverviewForTIS(tis, true /* fromInit */);
-            }));
-        }
-
-        @BinderThread
-        @Override
-        public void onTaskbarToggled() {
-            MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> {
-                TaskbarActivityContext activityContext =
-                        tis.mTaskbarManager.getCurrentActivityContext();
-
-                if (activityContext != null) {
-                    activityContext.toggleTaskbarStash();
-                }
-            }));
-        }
-
-        @BinderThread
-        public void onOverviewToggle() {
-            TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle");
-            executeForTouchInteractionService(tis -> {
-                // If currently screen pinning, do not enter overview
-                if (tis.mDeviceState.isScreenPinningActive()) {
-                    return;
-                }
-                TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
-                tis.mOverviewCommandHelper.addCommand(CommandType.TOGGLE);
-            });
-        }
-
-        @BinderThread
-        @Override
-        public void onOverviewShown(boolean triggeredFromAltTab) {
-            executeForTouchInteractionService(tis -> {
-                if (triggeredFromAltTab) {
-                    TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
-                    tis.mOverviewCommandHelper.addCommand(CommandType.KEYBOARD_INPUT);
-                } else {
-                    tis.mOverviewCommandHelper.addCommand(CommandType.SHOW);
-                }
-            });
-        }
-
-        @BinderThread
-        @Override
-        public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
-            executeForTouchInteractionService(tis -> {
-                if (triggeredFromAltTab && !triggeredFromHomeKey) {
-                    // onOverviewShownFromAltTab hides the overview and ends at the target app
-                    tis.mOverviewCommandHelper.addCommand(CommandType.HIDE);
-                }
-            });
-        }
-
-        @BinderThread
-        @Override
-        public void onAssistantAvailable(boolean available, boolean longPressHomeEnabled) {
-            MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> {
-                tis.mDeviceState.setAssistantAvailable(available);
-                tis.onAssistantVisibilityChanged();
-                executeForTaskbarManager(taskbarManager -> taskbarManager
-                        .onLongPressHomeEnabled(longPressHomeEnabled));
-            }));
-        }
-
-        @BinderThread
-        @Override
-        public void onAssistantVisibilityChanged(float visibility) {
-            MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> {
-                tis.mDeviceState.setAssistantVisibility(visibility);
-                tis.onAssistantVisibilityChanged();
-            }));
-        }
-
-        /**
-         * Sent when the assistant has been invoked with the given type (defined in AssistManager)
-         * and should be shown. This method is used if SystemUiProxy#setAssistantOverridesRequested
-         * was previously called including this invocation type.
-         */
-        @Override
-        public void onAssistantOverrideInvoked(int invocationType) {
-            executeForTouchInteractionService(tis -> {
-                if (!new ContextualSearchInvoker(tis).tryStartAssistOverride(invocationType)) {
-                    Log.w(TAG, "Failed to invoke Assist override");
-                }
-            });
-        }
-
-        @BinderThread
-        public void onSystemUiStateChanged(@SystemUiStateFlags long stateFlags) {
-            MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> {
-                long lastFlags = tis.mDeviceState.getSystemUiStateFlags();
-                tis.mDeviceState.setSystemUiFlags(stateFlags);
-                tis.onSystemUiFlagsChanged(lastFlags);
-            }));
-        }
-
-        @BinderThread
-        public void onActiveNavBarRegionChanges(Region region) {
-            MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(
-                    tis -> tis.mDeviceState.setDeferredGestureRegion(region)));
-        }
-
-        @BinderThread
-        @Override
-        public void enterStageSplitFromRunningApp(boolean leftOrTop) {
-            executeForTouchInteractionService(tis -> {
-                RecentsViewContainer container = tis.mOverviewComponentObserver
-                        .getContainerInterface().getCreatedContainer();
-                if (container != null) {
-                    container.enterStageSplitFromRunningApp(leftOrTop);
-                }
-            });
-        }
-
-        @BinderThread
-        @Override
-        public void onDisplayAddSystemDecorations(int displayId) {
-            executeForTaskbarManager(taskbarManager ->
-                            taskbarManager.onDisplayAddSystemDecorations(displayId));
-        }
-
-        @BinderThread
-        @Override
-        public void onDisplayRemoved(int displayId) {
-            executeForTaskbarManager(taskbarManager ->
-                    taskbarManager.onDisplayRemoved(displayId));
-        }
-
-        @BinderThread
-        @Override
-        public void onDisplayRemoveSystemDecorations(int displayId) {
-            executeForTaskbarManager(taskbarManager ->
-                    taskbarManager.onDisplayRemoveSystemDecorations(displayId));
-        }
-
-        @BinderThread
-        @Override
-        public void updateWallpaperVisibility(int displayId, boolean visible) {
-            executeForTaskbarManager(taskbarManager ->
-                    taskbarManager.setWallpaperVisible(displayId, visible));
-        }
-
-        @BinderThread
-        @Override
-        public void checkNavBarModes(int displayId) {
-            executeForTaskbarManager(taskbarManager ->
-                    taskbarManager.checkNavBarModes(displayId));
-        }
-
-        @BinderThread
-        @Override
-        public void finishBarAnimations(int displayId) {
-            executeForTaskbarManager(taskbarManager ->
-                    taskbarManager.finishBarAnimations(displayId));
-        }
-
-        @BinderThread
-        @Override
-        public void touchAutoDim(int displayId, boolean reset) {
-            executeForTaskbarManager(taskbarManager ->
-                    taskbarManager.touchAutoDim(displayId, reset));
-        }
-
-        @BinderThread
-        @Override
-        public void transitionTo(int displayId, @BarTransitions.TransitionMode int barMode,
-                boolean animate) {
-            executeForTaskbarManager(taskbarManager ->
-                    taskbarManager.transitionTo(displayId, barMode, animate));
-        }
-
-        @BinderThread
-        @Override
-        public void appTransitionPending(boolean pending) {
-            executeForTaskbarManager(taskbarManager ->
-                    taskbarManager.appTransitionPending(pending));
-        }
-
-        @Override
-        public void onRotationProposal(int rotation, boolean isValid) {
-            executeForTaskbarManager(taskbarManager ->
-                    taskbarManager.onRotationProposal(rotation, isValid));
-        }
-
-        @Override
-        public void disable(int displayId, int state1, int state2, boolean animate) {
-            executeForTaskbarManager(taskbarManager ->
-                    taskbarManager.disableNavBarElements(displayId, state1, state2, animate));
-        }
-
-        @Override
-        public void onSystemBarAttributesChanged(int displayId, int behavior) {
-            executeForTaskbarManager(taskbarManager ->
-                    taskbarManager.onSystemBarAttributesChanged(displayId, behavior));
-        }
-
-        @Override
-        public void onTransitionModeUpdated(int barMode, boolean checkBarModes) {
-            executeForTaskbarManager(taskbarManager ->
-                    taskbarManager.onTransitionModeUpdated(barMode, checkBarModes));
-        }
-
-        @Override
-        public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
-            executeForTaskbarManager(taskbarManager ->
-                    taskbarManager.onNavButtonsDarkIntensityChanged(darkIntensity));
-        }
-
-        @Override
-        public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
-            executeForTaskbarManager(taskbarManager ->
-                    taskbarManager.onNavigationBarLumaSamplingEnabled(displayId, enable));
-        }
-
-        @Override
-        public void onUnbind(IRemoteCallback reply) {
-            // Run everything in the same main thread block to ensure the cleanup happens before
-            // sending the reply.
-            MAIN_EXECUTOR.execute(() -> {
-                executeForTaskbarManager(TaskbarManager::destroy);
-                try {
-                    reply.sendResult(null);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "onUnbind: Failed to reply to LauncherProxyService", e);
-                }
-            });
-        }
-
-        private void executeForTouchInteractionService(
-                @NonNull Consumer<TouchInteractionService> tisConsumer) {
-            TouchInteractionService tis = mTis.get();
-            if (tis == null) return;
-            tisConsumer.accept(tis);
-        }
-
-        private void executeForTaskbarManager(
-                @NonNull Consumer<TaskbarManager> taskbarManagerConsumer) {
-            MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> {
-                TaskbarManager taskbarManager = tis.mTaskbarManager;
-                if (taskbarManager == null) return;
-                taskbarManagerConsumer.accept(taskbarManager);
-            }));
-        }
-
-        /**
-         * Returns the {@link TaskbarManager}.
-         * <p>
-         * Returns {@code null} if TouchInteractionService is not connected
-         */
-        @Nullable
-        public TaskbarManager getTaskbarManager() {
-            TouchInteractionService tis = mTis.get();
-            if (tis == null) return null;
-            return tis.mTaskbarManager;
-        }
-
-        @VisibleForTesting
-        public void injectFakeTrackpadForTesting() {
-            TouchInteractionService tis = mTis.get();
-            if (tis == null) return;
-            tis.mTrackpadsConnected.add(1000);
-            tis.initInputMonitor("tapl testing");
-        }
-
-        @VisibleForTesting
-        public void ejectFakeTrackpadForTesting() {
-            TouchInteractionService tis = mTis.get();
-            if (tis == null) return;
-            tis.mTrackpadsConnected.clear();
-            // This method destroys the current input monitor if set up, and only init a new one
-            // in 3-button mode if {@code mTrackpadsConnected} is not empty. So in other words,
-            // it will destroy the input monitor.
-            tis.initInputMonitor("tapl testing");
-        }
-
-        /**
-         * Sets whether a predictive back-to-home animation is in progress in the device state
-         */
-        public void setPredictiveBackToHomeInProgress(boolean isInProgress) {
-            executeForTouchInteractionService(tis ->
-                    tis.mDeviceState.setPredictiveBackToHomeInProgress(isInProgress));
-        }
-
-        /**
-         * Returns the {@link OverviewCommandHelper}.
-         * <p>
-         * Returns {@code null} if TouchInteractionService is not connected
-         */
-        @Nullable
-        public OverviewCommandHelper getOverviewCommandHelper() {
-            TouchInteractionService tis = mTis.get();
-            if (tis == null) return null;
-            return tis.mOverviewCommandHelper;
-        }
-
-        /**
-         * Sets a proxy to bypass swipe up behavior
-         */
-        public void setSwipeUpProxy(Function<GestureState, AnimatedFloat> proxy) {
-            executeForTouchInteractionService(
-                    tis -> tis.mSwipeUpProxyProvider = proxy != null ? proxy : (i -> null));
-        }
-
-        /**
-         * Sets the task id where gestures should be blocked
-         */
-        public void setGestureBlockedTaskId(int taskId) {
-            executeForTouchInteractionService(
-                    tis -> tis.mDeviceState.setGestureBlockingTaskId(taskId));
-        }
-
-        /** Refreshes the current overview target. */
-        public void refreshOverviewTarget() {
-            executeForTouchInteractionService(tis -> {
-                tis.mAllAppsActionManager.onDestroy();
-                tis.onOverviewTargetChanged(tis.mOverviewComponentObserver.isHomeAndOverviewSame());
-            });
-        }
-    }
-
     private RotationTouchHelper mRotationTouchHelper;
 
     private final AbsSwipeUpHandler.Factory mLauncherSwipeHandlerFactory =
@@ -521,6 +130,13 @@
     private final ScreenOnTracker.ScreenOnListener mScreenOnListener = this::onScreenOnChanged;
     private final OverviewChangeListener mOverviewChangeListener = this::onOverviewTargetChanged;
 
+    private final Runnable mSysUiProxyStateChangeCallback =
+            () -> {
+                if (SystemUiProxy.INSTANCE.get(this).isActive()) {
+                    initInputMonitor("TISBinder#onInitialize()");
+                }
+            };
+
     private final TaskbarNavButtonCallbacks mNavCallbacks = new TaskbarNavButtonCallbacks() {
         @Override
         public void onNavigateHome() {
@@ -554,7 +170,6 @@
     private InputEventReceiver mInputEventReceiver;
 
     private TaskbarManager mTaskbarManager;
-    private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = i -> null;
     private AllAppsActionManager mAllAppsActionManager;
     private ActiveTrackpadList mTrackpadsConnected;
 
@@ -597,6 +212,7 @@
         mDisplayInfoChangeListener =
                 mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
         ScreenOnTracker.INSTANCE.get(this).addListener(mScreenOnListener);
+        SystemUiProxy.INSTANCE.get(this).addOnStateChangeListener(mSysUiProxyStateChangeCallback);
     }
 
     private void disposeEventHandlers(String reason) {
@@ -649,8 +265,6 @@
         mResetGestureInputConsumer = new ResetGestureInputConsumer(
                 mTaskAnimationManager, mTaskbarManager::getCurrentActivityContext);
         mInputConsumer.registerInputConsumer();
-        onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags());
-        onAssistantVisibilityChanged();
 
         // Initialize the task tracker
         TopTaskTracker.INSTANCE.get(this);
@@ -669,6 +283,10 @@
         return mOverviewCommandHelper;
     }
 
+    public TaskbarManager getTaskbarManager() {
+        return mTaskbarManager;
+    }
+
     private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
         if (!LockedUserState.get(this).isUserUnlocked() || mDeviceState.isButtonNavMode()) {
             // Skip if not yet unlocked (can't read user shared prefs) or if the current navigation
@@ -710,34 +328,18 @@
         });
     }
 
-    @UiThread
-    private void onSystemUiFlagsChanged(@SystemUiStateFlags long lastSysUIFlags) {
-        if (LockedUserState.get(this).isUserUnlocked()) {
-            long systemUiStateFlags = mDeviceState.getSystemUiStateFlags();
-            SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags);
-            mOverviewComponentObserver.setHomeDisabled(mDeviceState.isHomeDisabled());
-            mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags);
-            mTaskAnimationManager.onSystemUiFlagsChanged(lastSysUIFlags, systemUiStateFlags);
-        }
-    }
-
-    @UiThread
-    private void onAssistantVisibilityChanged() {
-        if (LockedUserState.get(this).isUserUnlocked()) {
-            mOverviewComponentObserver.getContainerInterface().onAssistantVisibilityChanged(
-                    mDeviceState.getAssistantVisibility());
-        }
-    }
-
     @Override
     public void onDestroy() {
         Log.d(TAG, "onDestroy: user=" + getUserId()
                 + " instance=" + System.identityHashCode(this));
         if (LockedUserState.get(this).isUserUnlocked()) {
             mInputConsumer.unregisterInputConsumer();
-            mOverviewComponentObserver.setHomeDisabled(false);
             mOverviewComponentObserver.removeOverviewChangeListener(mOverviewChangeListener);
         }
+        if (mTaskAnimationManager != null) {
+            mTaskAnimationManager.onDestroy();
+        }
+
         disposeEventHandlers("TouchInteractionService onDestroy()");
         SystemUiProxy.INSTANCE.get(this).clearProxy();
 
@@ -752,6 +354,8 @@
         mDeviceState.removeDisplayInfoChangeListener(mDisplayInfoChangeListener);
         LockedUserState.get(this).removeOnUserUnlockedRunnable(mUserUnlockedRunnable);
         ScreenOnTracker.INSTANCE.get(this).removeListener(mScreenOnListener);
+        SystemUiProxy.INSTANCE.get(this)
+                .removeOnStateChangeListener(mSysUiProxyStateChangeCallback);
         super.onDestroy();
     }
 
@@ -879,7 +483,6 @@
                         this::onConsumerInactive,
                         mInputEventReceiver,
                         mTaskbarManager,
-                        mSwipeUpProxyProvider,
                         mOverviewCommandHelper,
                         event);
                 mUncheckedConsumer = mConsumer;
@@ -1158,4 +761,26 @@
                 gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(),
                 mInputConsumer, MSDLPlayerWrapper.INSTANCE.get(this));
     }
+
+    @VisibleForTesting
+    public void injectFakeTrackpadForTesting() {
+        mTrackpadsConnected.add(1000);
+        initInputMonitor("tapl testing");
+    }
+
+    @VisibleForTesting
+    public void ejectFakeTrackpadForTesting() {
+        mTrackpadsConnected.clear();
+        // This method destroys the current input monitor if set up, and only init a new one
+        // in 3-button mode if {@code mTrackpadsConnected} is not empty. So in other words,
+        // it will destroy the input monitor.
+        initInputMonitor("tapl testing");
+    }
+
+    /** Refreshes the current overview target. */
+    @VisibleForTesting
+    public void refreshOverviewTarget() {
+        mAllAppsActionManager.onDestroy();
+        onOverviewTargetChanged(mOverviewComponentObserver.isHomeAndOverviewSame());
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index c986b88..39a9dff 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -72,7 +72,8 @@
 import com.android.quickstep.GestureState;
 import com.android.quickstep.OverviewComponentObserver;
 import com.android.quickstep.OverviewComponentObserver.OverviewChangeListener;
-import com.android.quickstep.TouchInteractionService.TISBinder;
+import com.android.quickstep.RecentsAnimationDeviceState;
+import com.android.quickstep.TISBinder;
 import com.android.quickstep.util.ActivityPreloadUtil;
 import com.android.quickstep.util.LottieAnimationColorUtils;
 import com.android.quickstep.util.TISBindHelper;
@@ -283,16 +284,13 @@
     protected void onResume() {
         super.onResume();
         maybeResumeOrPauseBackgroundAnimation();
-        TISBinder binder = mTISBindHelper.getBinder();
-        if (binder != null) {
-            setSetupUIVisible(true);
-            binder.setSwipeUpProxy(this::createSwipeUpProxy);
-        }
+        RecentsAnimationDeviceState.INSTANCE.get(this)
+                .setSwipeUpProxyProvider(this::createSwipeUpProxy);
+        setSetupUIVisible(true);
     }
 
     private void onTISConnected(TISBinder binder) {
         setSetupUIVisible(isResumed());
-        binder.setSwipeUpProxy(isResumed() ? this::createSwipeUpProxy : null);
         TaskbarManager taskbarManager = binder.getTaskbarManager();
         if (taskbarManager != null) {
             mLauncherStartAnim = taskbarManager.createLauncherStartFromSuwAnim(MAX_SWIPE_DURATION);
@@ -306,7 +304,8 @@
     @Override
     protected void onPause() {
         super.onPause();
-        clearBinderOverride();
+        setSetupUIVisible(false);
+        RecentsAnimationDeviceState.INSTANCE.get(this).setSwipeUpProxyProvider(null);
         maybeResumeOrPauseBackgroundAnimation();
         if (mSwipeProgress.value >= 1) {
             finishAndRemoveTask();
@@ -314,14 +313,6 @@
         }
     }
 
-    private void clearBinderOverride() {
-        TISBinder binder = mTISBindHelper.getBinder();
-        if (binder != null) {
-            setSetupUIVisible(false);
-            binder.setSwipeUpProxy(null);
-        }
-    }
-
     /**
      * Should be called when we have successfully reached Launcher, so we dispatch to animation
      * listeners to ensure the state matches the visual animation that just occurred.
@@ -338,8 +329,9 @@
     protected void onDestroy() {
         super.onDestroy();
         getIDP().removeOnChangeListener(mOnIDPChangeListener);
+        // In case bindHelper was not connected during onPause, clear UIVisible flag again
+        setSetupUIVisible(false);
         mTISBindHelper.onDestroy();
-        clearBinderOverride();
         if (mBackgroundAnimatorListener != null) {
             mAnimatedBackground.removeAnimatorListener(mBackgroundAnimatorListener);
         }
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index 0365f89..2114c30 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -38,10 +38,9 @@
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.R;
 import com.android.launcher3.logging.StatsLogManager;
-import com.android.quickstep.TouchInteractionService.TISBinder;
+import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.interaction.TutorialController.TutorialType;
 import com.android.quickstep.util.LayoutUtils;
-import com.android.quickstep.util.TISBindHelper;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -64,7 +63,6 @@
 
     private SharedPreferences mSharedPrefs;
     private StatsLogManager mStatsLogManager;
-    private TISBindHelper mTISBindHelper;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -99,7 +97,6 @@
                 .commit();
 
         correctUserOrientation();
-        mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
 
         initWindowInsets();
     }
@@ -349,10 +346,6 @@
         updateServiceState(true);
     }
 
-    private void onTISConnected(TISBinder binder) {
-        updateServiceState(isResumed());
-    }
-
     @Override
     protected void onPause() {
         super.onPause();
@@ -360,16 +353,13 @@
     }
 
     private void updateServiceState(boolean isEnabled) {
-        TISBinder binder = mTISBindHelper.getBinder();
-        if (binder != null) {
-            binder.setGestureBlockedTaskId(isEnabled ? getTaskId() : -1);
-        }
+        RecentsAnimationDeviceState.INSTANCE.get(this)
+                .setGestureBlockingTaskId(isEnabled ? getTaskId() : -1);
     }
 
     @Override
     protected void onDestroy() {
         super.onDestroy();
-        mTISBindHelper.onDestroy();
         updateServiceState(false);
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/ContextualSearchInvoker.kt b/quickstep/src/com/android/quickstep/util/ContextualSearchInvoker.kt
index d00a39c..969aa0f 100644
--- a/quickstep/src/com/android/quickstep/util/ContextualSearchInvoker.kt
+++ b/quickstep/src/com/android/quickstep/util/ContextualSearchInvoker.kt
@@ -21,7 +21,6 @@
 import android.app.contextualsearch.ContextualSearchManager.FEATURE_CONTEXTUAL_SEARCH
 import android.content.Context
 import android.util.Log
-import androidx.annotation.VisibleForTesting
 import com.android.internal.app.AssistUtils
 import com.android.launcher3.logging.StatsLogManager
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_LAUNCH_ASSISTANT_FAILED_SERVICE_ERROR
@@ -34,7 +33,7 @@
 import com.android.quickstep.BaseContainerInterface
 import com.android.quickstep.DeviceConfigWrapper
 import com.android.quickstep.OverviewComponentObserver
-import com.android.quickstep.SystemUiProxy
+import com.android.quickstep.RecentsAnimationDeviceState
 import com.android.quickstep.TopTaskTracker
 import com.android.quickstep.views.RecentsView
 import com.android.systemui.shared.system.QuickStepContract
@@ -45,9 +44,10 @@
     private val context: Context,
     private val contextualSearchStateManager: ContextualSearchStateManager,
     private val topTaskTracker: TopTaskTracker,
-    private val systemUiProxy: SystemUiProxy,
+    private val deviceState: RecentsAnimationDeviceState,
     private val statsLogManager: StatsLogManager,
     private val contextualSearchHapticManager: ContextualSearchHapticManager,
+    private val overviewComponentObserver: OverviewComponentObserver,
     private val contextualSearchManager: ContextualSearchManager?,
 ) {
     constructor(
@@ -56,9 +56,10 @@
         context,
         ContextualSearchStateManager.INSTANCE[context],
         TopTaskTracker.INSTANCE[context],
-        SystemUiProxy.INSTANCE[context],
+        RecentsAnimationDeviceState.INSTANCE[context],
         StatsLogManager.newInstance(context),
         ContextualSearchHapticManager.INSTANCE[context],
+        OverviewComponentObserver.INSTANCE[context],
         context.getSystemService(ContextualSearchManager::class.java),
     )
 
@@ -189,7 +190,7 @@
         if (contextualSearchManager == null) {
             return false
         }
-        val recentsContainerInterface = getRecentsContainerInterface()
+        val recentsContainerInterface = overviewComponentObserver.containerInterface
         if (recentsContainerInterface?.isInLiveTileMode() == true) {
             Log.i(TAG, "Contextual Search invocation attempted: live tile")
             endLiveTileMode(recentsContainerInterface) {
@@ -202,27 +203,20 @@
     }
 
     private fun isFakeLandscape(): Boolean =
-        getRecentsContainerInterface()
-            ?.getCreatedContainer()
+        overviewComponentObserver.containerInterface
+            ?.createdContainer
             ?.getOverviewPanel<RecentsView<*, *>>()
-            ?.getPagedOrientationHandler()
+            ?.pagedOrientationHandler
             ?.isLayoutNaturalToLauncher == false
 
-    private fun isInSplitscreen(): Boolean {
-        return topTaskTracker.getRunningSplitTaskIds().isNotEmpty()
-    }
+    private fun isInSplitscreen(): Boolean = topTaskTracker.runningSplitTaskIds.isNotEmpty()
 
     private fun isNotificationShadeShowing(): Boolean {
-        return systemUiProxy.lastSystemUiStateFlags and SHADE_EXPANDED_SYSUI_FLAGS != 0L
+        return deviceState.systemUiStateFlags and SHADE_EXPANDED_SYSUI_FLAGS != 0L
     }
 
     private fun isKeyguardShowing(): Boolean {
-        return systemUiProxy.lastSystemUiStateFlags and KEYGUARD_SHOWING_SYSUI_FLAGS != 0L
-    }
-
-    @VisibleForTesting
-    fun getRecentsContainerInterface(): BaseContainerInterface<*, *>? {
-        return OverviewComponentObserver.INSTANCE.get(context).containerInterface
+        return deviceState.systemUiStateFlags and KEYGUARD_SHOWING_SYSUI_FLAGS != 0L
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/util/TISBindHelper.java b/quickstep/src/com/android/quickstep/util/TISBindHelper.java
index 027dc08..3716efa 100644
--- a/quickstep/src/com/android/quickstep/util/TISBindHelper.java
+++ b/quickstep/src/com/android/quickstep/util/TISBindHelper.java
@@ -28,8 +28,8 @@
 
 import com.android.launcher3.taskbar.TaskbarManager;
 import com.android.quickstep.OverviewCommandHelper;
+import com.android.quickstep.TISBinder;
 import com.android.quickstep.TouchInteractionService;
-import com.android.quickstep.TouchInteractionService.TISBinder;
 
 import java.util.ArrayList;
 import java.util.function.Consumer;
@@ -109,15 +109,6 @@
         return mBinder == null ? null : mBinder.getTaskbarManager();
     }
 
-    /**
-     * Sets flag whether a predictive back-to-home animation is in progress
-     */
-    public void setPredictiveBackToHomeInProgress(boolean isInProgress) {
-        if (mBinder != null) {
-            mBinder.setPredictiveBackToHomeInProgress(isInProgress);
-        }
-    }
-
     @Nullable
     public OverviewCommandHelper getOverviewCommandHelper() {
         return mBinder == null ? null : mBinder.getOverviewCommandHelper();
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarStashControllerTest.kt
index 021e1e4..8395d79 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarStashControllerTest.kt
@@ -50,8 +50,11 @@
 import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
 import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.UserSetupMode
 import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
 import com.android.launcher3.util.LauncherMultivalentJUnit
 import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.android.launcher3.util.TestUtil
+import com.android.quickstep.RecentsAnimationDeviceState
 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED
 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_VISIBLE
 import com.android.wm.shell.Flags.FLAG_ENABLE_BUBBLE_BAR
@@ -60,6 +63,8 @@
 import org.junit.After
 import org.junit.Rule
 import org.junit.Test
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
 import org.junit.runner.RunWith
 
 @RunWith(LauncherMultivalentJUnit::class)
@@ -68,7 +73,16 @@
 class TaskbarStashControllerTest {
     @get:Rule(order = 0) val setFlagsRule = SetFlagsRule()
     @get:Rule(order = 1) val context = TaskbarWindowSandboxContext.create()
-    @get:Rule(order = 2) val taskbarModeRule = TaskbarModeRule(context)
+    @get:Rule(order = 2)
+    val initSingleton =
+        object : TestWatcher() {
+            override fun starting(description: Description?) {
+                TestUtil.runOnExecutorSync(MAIN_EXECUTOR) {
+                    RecentsAnimationDeviceState.INSTANCE[context].systemUiStateFlags = 0
+                }
+            }
+        }
+    @get:Rule(order = 3) val taskbarModeRule = TaskbarModeRule(context)
     @get:Rule(order = 4) val animatorTestRule = AnimatorTestRule(this)
     @get:Rule(order = 5) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
 
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
index b652ee8..63115bf 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
@@ -150,7 +150,7 @@
 
         allSysUiStates().forEach { state ->
             val canStartGesture = !disablingStates.contains(state)
-            underTest.setSystemUiFlags(state)
+            underTest.systemUiStateFlags = state
             assertThat(underTest.canStartTrackpadGesture()).isEqualTo(canStartGesture)
         }
     }
@@ -166,7 +166,7 @@
             )
 
         stateToExpectedResult.forEach { (state, allowed) ->
-            underTest.setSystemUiFlags(state)
+            underTest.systemUiStateFlags = state
             assertThat(underTest.canStartTrackpadGesture()).isEqualTo(allowed)
         }
     }
@@ -177,7 +177,7 @@
 
         allSysUiStates().forEach { state ->
             val canStartGesture = !disablingStates.contains(state)
-            underTest.setSystemUiFlags(state)
+            underTest.systemUiStateFlags = state
             assertThat(underTest.canStartSystemGesture()).isEqualTo(canStartGesture)
         }
     }
@@ -197,7 +197,7 @@
             )
 
         stateToExpectedResult.forEach { (state, gestureAllowed) ->
-            underTest.setSystemUiFlags(state)
+            underTest.systemUiStateFlags = state
             assertThat(underTest.canStartSystemGesture()).isEqualTo(gestureAllowed)
         }
     }
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java
index 6e9885a..b730f5b 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java
@@ -54,12 +54,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mTaskAnimationManager = new TaskAnimationManager(mContext,
-                RecentsAnimationDeviceState.INSTANCE.get(mContext)) {
-            @Override
-            SystemUiProxy getSystemUiProxy() {
-                return mSystemUiProxy;
-            }
-        };
+                RecentsAnimationDeviceState.INSTANCE.get(mContext), mSystemUiProxy);
     }
 
     @Test
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/ContextualSearchInvokerTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/ContextualSearchInvokerTest.java
index 61971b1..4e49aec 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/ContextualSearchInvokerTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/ContextualSearchInvokerTest.java
@@ -50,7 +50,8 @@
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.quickstep.BaseContainerInterface;
 import com.android.quickstep.DeviceConfigWrapper;
-import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.OverviewComponentObserver;
+import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.TopTaskTracker;
 import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.views.RecentsView;
@@ -75,7 +76,7 @@
     private @Mock PackageManager mMockPackageManager;
     private @Mock ContextualSearchStateManager mMockStateManager;
     private @Mock TopTaskTracker mMockTopTaskTracker;
-    private @Mock SystemUiProxy mMockSystemUiProxy;
+    private @Mock RecentsAnimationDeviceState mMockDeviceState;
     private @Mock StatsLogManager mMockStatsLogManager;
     private @Mock StatsLogManager.StatsLogger mMockStatsLogger;
     private @Mock ContextualSearchHapticManager mMockContextualSearchHapticManager;
@@ -84,6 +85,7 @@
     private @Mock RecentsViewContainer mMockRecentsViewContainer;
     private @Mock RecentsView mMockRecentsView;
     private @Mock RecentsPagedOrientationHandler mMockOrientationHandler;
+    private @Mock OverviewComponentObserver mMockOverviewComponentObserver;
     private ContextualSearchInvoker mContextualSearchInvoker;
 
     @Before
@@ -92,20 +94,21 @@
         when(mMockPackageManager.hasSystemFeature(FEATURE_CONTEXTUAL_SEARCH)).thenReturn(true);
         Context context = spy(getApplicationContext());
         doReturn(mMockPackageManager).when(context).getPackageManager();
-        when(mMockSystemUiProxy.getLastSystemUiStateFlags()).thenReturn(0L);
+        when(mMockDeviceState.getSystemUiStateFlags()).thenReturn(0L);
         when(mMockTopTaskTracker.getRunningSplitTaskIds()).thenReturn(new int[]{});
         when(mMockStateManager.isContextualSearchIntentAvailable()).thenReturn(true);
         when(mMockStateManager.isContextualSearchSettingEnabled()).thenReturn(true);
         when(mMockStatsLogManager.logger()).thenReturn(mMockStatsLogger);
+
+        doReturn(mMockContainerInterface).when(mMockOverviewComponentObserver)
+                .getContainerInterface();
         when(mMockContainerInterface.getCreatedContainer()).thenReturn(mMockRecentsViewContainer);
         when(mMockRecentsViewContainer.getOverviewPanel()).thenReturn(mMockRecentsView);
 
-        mContextualSearchInvoker = spy(new ContextualSearchInvoker(context, mMockStateManager,
-                mMockTopTaskTracker, mMockSystemUiProxy, mMockStatsLogManager,
-                mMockContextualSearchHapticManager, mMockContextualSearchManager
-        ));
-        doReturn(mMockContainerInterface).when(mContextualSearchInvoker)
-                .getRecentsContainerInterface();
+        mContextualSearchInvoker = new ContextualSearchInvoker(context, mMockStateManager,
+                mMockTopTaskTracker, mMockDeviceState, mMockStatsLogManager,
+                mMockContextualSearchHapticManager, mMockOverviewComponentObserver,
+                mMockContextualSearchManager);
     }
 
     @Test
@@ -148,7 +151,7 @@
 
     @Test
     public void runContextualSearchInvocationChecksAndLogFailures_notificationShadeIsShowing() {
-        when(mMockSystemUiProxy.getLastSystemUiStateFlags()).thenReturn(SHADE_EXPANDED_SYSUI_FLAGS);
+        when(mMockDeviceState.getSystemUiStateFlags()).thenReturn(SHADE_EXPANDED_SYSUI_FLAGS);
 
         assertFalse("Expected invocation checks to fail when notification shade is showing",
                 mContextualSearchInvoker.runContextualSearchInvocationChecksAndLogFailures());
@@ -158,7 +161,7 @@
 
     @Test
     public void runContextualSearchInvocationChecksAndLogFailures_keyguardIsShowing() {
-        when(mMockSystemUiProxy.getLastSystemUiStateFlags()).thenReturn(
+        when(mMockDeviceState.getSystemUiStateFlags()).thenReturn(
                 KEYGUARD_SHOWING_SYSUI_FLAGS);
 
         assertFalse("Expected invocation checks to fail when keyguard is showing",
diff --git a/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
index e2ca91a..a164dad 100644
--- a/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
@@ -89,7 +89,6 @@
 import org.mockito.junit.MockitoRule;
 
 import java.util.Optional;
-import java.util.function.Function;
 
 import javax.inject.Provider;
 
@@ -104,7 +103,6 @@
     private TaskAnimationManager mTaskAnimationManager;
     private InputChannelCompat.InputEventReceiver mInputEventReceiver;
     @Nullable private ResetGestureInputConsumer mResetGestureInputConsumer;
-    @NonNull private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = (state) -> null;
 
     @NonNull @Mock private TaskbarActivityContext mTaskbarActivityContext;
     @NonNull @Mock private OverviewComponentObserver mOverviewComponentObserver;
@@ -446,7 +444,7 @@
 
     @Test
     public void testNewConsumer_withSwipeUpProxyProvider_returnsProgressDelegateInputConsumer() {
-        mSwipeUpProxyProvider = (state) -> new AnimatedFloat();
+        doReturn(new AnimatedFloat()).when(mDeviceState).getSwipeUpProxy(any());
 
         assertCorrectInputConsumer(
                 this::createInputConsumer,
@@ -496,7 +494,6 @@
                 otherActivityInputConsumer -> {},
                 mInputEventReceiver,
                 mTaskbarManager,
-                mSwipeUpProxyProvider,
                 mOverviewCommandHelper,
                 event);
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 315301a..04e699c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -349,8 +349,7 @@
 
     private final int[] mTmpAddItemCellCoordinates = new int[2];
 
-    @Thunk
-    Hotseat mHotseat;
+    protected Hotseat mHotseat;
 
     private DropTargetBar mDropTargetBar;
 
@@ -807,10 +806,6 @@
         );
     }
 
-    public void onAssistantVisibilityChanged(float visibility) {
-        mHotseat.getQsb().setAlpha(1f - visibility);
-    }
-
     /**
      * Returns {@code true} if a new DeviceProfile is initialized, and {@code false} otherwise.
      */