Merge changes I239f9357,I57a32ac5 into main

* changes:
  Update setting taskbar window height
  Set bubble bar aligned to QSB
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index f082728..70c61ff 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -301,7 +301,8 @@
             BubbleStashController bubbleStashController = isTransientTaskbar
                     ? new TransientBubbleStashController(dimensionsProvider, this)
                     : new PersistentBubbleStashController(dimensionsProvider);
-            bubbleStashController.setHotseatVerticalCenter(launcherDp.getHotseatVerticalCenter());
+            bubbleStashController.setBubbleBarVerticalCenterForHome(
+                    launcherDp.getBubbleBarVerticalCenterForHome());
             bubbleControllersOptional = Optional.of(new BubbleControllers(
                     new BubbleBarController(this, bubbleBarView),
                     new BubbleBarViewController(this, bubbleBarView, bubbleBarContainer),
@@ -369,8 +370,9 @@
         applyDeviceProfile(launcherDp);
         mControllers.taskbarOverlayController.updateLauncherDeviceProfile(launcherDp);
         mControllers.bubbleControllers.ifPresent(bubbleControllers -> {
-            int hotseatVertCenter = launcherDp.getHotseatVerticalCenter();
-            bubbleControllers.bubbleStashController.setHotseatVerticalCenter(hotseatVertCenter);
+            int bubbleBarVerticalCenter = launcherDp.getBubbleBarVerticalCenterForHome();
+            bubbleControllers.bubbleStashController
+                    .setBubbleBarVerticalCenterForHome(bubbleBarVerticalCenter);
         });
         AbstractFloatingView.closeAllOpenViewsExcept(this, false, TYPE_REBIND_SAFE);
         // Reapply fullscreen to take potential new screen size into account.
@@ -1136,6 +1138,10 @@
             return getSetupWindowSize();
         }
 
+        int bubbleBarTop = mControllers.bubbleControllers.map(bubbleControllers ->
+                bubbleControllers.bubbleBarViewController.getBubbleBarWithFlyoutMaximumHeight()
+        ).orElse(0);
+        int taskbarWindowSize;
         boolean shouldTreatAsTransient = DisplayController.isTransientTaskbar(this)
                 || (enableTaskbarPinning() && !isThreeButtonNav());
 
@@ -1152,16 +1158,18 @@
             DeviceProfile transientTaskbarDp = mDeviceProfile.toBuilder(this)
                     .setIsTransientTaskbar(true).build();
 
-            return transientTaskbarDp.taskbarHeight
+            taskbarWindowSize = transientTaskbarDp.taskbarHeight
                     + (2 * transientTaskbarDp.taskbarBottomMargin)
                     + Math.max(extraHeightForTaskbarTooltips, resources.getDimensionPixelSize(
                     R.dimen.transient_taskbar_shadow_blur));
+            return Math.max(taskbarWindowSize, bubbleBarTop);
         }
 
 
-        return mDeviceProfile.taskbarHeight
+        taskbarWindowSize =  mDeviceProfile.taskbarHeight
                 + getCornerRadius()
                 + extraHeightForTaskbarTooltips;
+        return Math.max(taskbarWindowSize, bubbleBarTop);
     }
 
     public int getSetupWindowSize() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarParentViewHeightUpdateNotifier.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarParentViewHeightUpdateNotifier.kt
new file mode 100644
index 0000000..f69ad74
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarParentViewHeightUpdateNotifier.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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.launcher3.taskbar.bubbles
+
+/** Controls the parent view height. */
+interface BubbleBarParentViewHeightUpdateNotifier {
+
+    /** Notify parent that top boundary should be updated. */
+    fun updateTopBoundary()
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 378776d..219a2b3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -1306,6 +1306,10 @@
         return getBubbleBarCollapsedHeight() + mPointerSize;
     }
 
+    float getArrowHeight() {
+        return mPointerSize;
+    }
+
     float getBubbleBarCollapsedHeight() {
         // the pointer is invisible when collapsed
         return getScaledIconSize() + mBubbleBarPadding * 2;
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index f6c04b1..1e0a778 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -170,7 +170,7 @@
                 mBubbleBarContainer, createFlyoutPositioner(), createFlyoutCallbacks());
         mBubbleBarViewAnimator = new BubbleBarViewAnimator(
                 mBarView, mBubbleStashController, mBubbleBarFlyoutController,
-                mBubbleBarController::showExpandedView);
+                createBubbleBarParentViewController(), mBubbleBarController::showExpandedView);
         mTaskbarViewPropertiesProvider = taskbarViewPropertiesProvider;
         onBubbleBarConfigurationChanged(/* animate= */ false);
         mActivity.addOnDeviceProfileChangeListener(
@@ -317,17 +317,6 @@
     private FlyoutCallbacks createFlyoutCallbacks() {
         return new FlyoutCallbacks() {
             @Override
-            public void extendTopBoundary(int space) {
-                int defaultSize = mActivity.getDefaultTaskbarWindowSize();
-                mActivity.setTaskbarWindowSize(defaultSize + space);
-            }
-
-            @Override
-            public void resetTopBoundary() {
-                mActivity.setTaskbarWindowSize(mActivity.getDefaultTaskbarWindowSize());
-            }
-
-            @Override
             public void flyoutClicked() {
                 interruptAnimationForTouch();
                 setExpanded(/* isExpanded= */ true, /* maybeShowEdu*/ true);
@@ -335,6 +324,15 @@
         };
     }
 
+    private BubbleBarParentViewHeightUpdateNotifier createBubbleBarParentViewController() {
+        return new BubbleBarParentViewHeightUpdateNotifier() {
+            @Override
+            public void updateTopBoundary() {
+                mActivity.setTaskbarWindowSize(mActivity.getDefaultTaskbarWindowSize());
+            }
+        };
+    }
+
     private void onBubbleClicked(BubbleView bubbleView) {
         if (mBubbleBarPinning.isAnimating()) return;
         bubbleView.markSeen();
@@ -442,6 +440,11 @@
         return mBarView.getBubbleBarCollapsedHeight();
     }
 
+    /** Returns the bubble bar arrow height.*/
+    public float getBubbleBarArrowHeight() {
+        return mBarView.getArrowHeight();
+    }
+
     /**
      * @see BubbleBarView#getRelativePivotX()
      */
@@ -575,6 +578,19 @@
         return mHiddenForNoBubbles;
     }
 
+    /** Returns maximum height of the bubble bar with the flyout view. */
+    public int getBubbleBarWithFlyoutMaximumHeight() {
+        if (!isBubbleBarVisible()) return 0;
+        int bubbleBarTopOnHome = (int) (mBubbleStashController.getBubbleBarVerticalCenterForHome()
+                + mBarView.getBubbleBarCollapsedHeight() / 2);
+        int result = (int) (bubbleBarTopOnHome + mBarView.getArrowHeight());
+        if (isAnimatingNewBubble()) {
+            // when animating new bubble add the maximum height of the flyout view
+            result += mBubbleBarFlyoutController.getMaximumFlyoutHeight();
+        }
+        return result;
+    }
+
     /**
      * Sets whether the bubble bar should be hidden because there are no bubbles.
      */
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
index 447dad1..f5a6655 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -25,6 +25,7 @@
 import androidx.dynamicanimation.animation.SpringForce
 import com.android.launcher3.R
 import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
+import com.android.launcher3.taskbar.bubbles.BubbleBarParentViewHeightUpdateNotifier
 import com.android.launcher3.taskbar.bubbles.BubbleBarView
 import com.android.launcher3.taskbar.bubbles.BubbleView
 import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutController
@@ -39,6 +40,7 @@
     private val bubbleBarView: BubbleBarView,
     private val bubbleStashController: BubbleStashController,
     private val bubbleBarFlyoutController: BubbleBarFlyoutController,
+    private val bubbleBarParentViewHeightUpdateNotifier: BubbleBarParentViewHeightUpdateNotifier,
     private val onExpanded: Runnable,
     private val scheduler: Scheduler = HandlerScheduler(bubbleBarView),
 ) {
@@ -342,7 +344,7 @@
                 scheduler.post(buildHandleToBubbleBarAnimation(initialVelocity = finalVelocity))
                 return@addEndListener
             }
-            animatingBubble = null
+            clearAnimatingBubble()
             if (!canceled) bubbleStashController.stashBubbleBarImmediate()
             bubbleBarView.relativePivotY = 1f
             bubbleBarView.scaleY = 1f
@@ -378,7 +380,7 @@
                     moveToState(AnimatingBubble.State.ANIMATING_OUT)
                     bubbleBarFlyoutController.collapseFlyout {
                         onFlyoutRemoved()
-                        animatingBubble = null
+                        clearAnimatingBubble()
                     }
                     bubbleStashController.showBubbleBarImmediate()
                     bubbleStashController.updateTaskbarTouchRegion()
@@ -437,7 +439,7 @@
             moveToState(AnimatingBubble.State.ANIMATING_OUT)
             bubbleBarFlyoutController.collapseFlyout {
                 onFlyoutRemoved()
-                animatingBubble = null
+                clearAnimatingBubble()
             }
             bubbleStashController.showBubbleBarImmediate()
             bubbleStashController.updateTaskbarTouchRegion()
@@ -515,7 +517,7 @@
         val hideAnimation = animatingBubble?.hideAnimation ?: return
         scheduler.cancel(hideAnimation)
         bubbleBarView.relativePivotY = 1f
-        animatingBubble = null
+        clearAnimatingBubble()
     }
 
     /** Notifies the animator that the taskbar area was touched during an animation. */
@@ -523,7 +525,7 @@
         cancelFlyout()
         val hideAnimation = animatingBubble?.hideAnimation ?: return
         scheduler.cancel(hideAnimation)
-        animatingBubble = null
+        clearAnimatingBubble()
         bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning()
         bubbleBarView.relativePivotY = 1f
         bubbleStashController.onNewBubbleAnimationInterrupted(
@@ -672,7 +674,7 @@
     private fun cancelHideAnimation() {
         val hideAnimation = animatingBubble?.hideAnimation ?: return
         scheduler.cancel(hideAnimation)
-        animatingBubble = null
+        clearAnimatingBubble()
         bubbleBarView.relativePivotY = 1f
         bubbleStashController.showBubbleBarImmediate()
     }
@@ -700,6 +702,14 @@
     private fun moveToState(state: AnimatingBubble.State) {
         val animatingBubble = this.animatingBubble ?: return
         this.animatingBubble = animatingBubble.copy(state = state)
+        if (state == AnimatingBubble.State.ANIMATING_IN) {
+            bubbleBarParentViewHeightUpdateNotifier.updateTopBoundary()
+        }
+    }
+
+    private fun clearAnimatingBubble() {
+        animatingBubble = null
+        bubbleBarParentViewHeightUpdateNotifier.updateTopBoundary()
     }
 
     private fun expandBubbleBar() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
index 908e97c..63db012 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
@@ -35,6 +35,8 @@
     private val flyoutScheduler: FlyoutScheduler = HandlerScheduler(container),
 ) {
 
+    val maximumFlyoutHeight: Int = BubbleBarFlyoutView.getMaximumViewHeight(container.context)
+
     private companion object {
         const val EXPAND_ANIMATION_DURATION_MS = 400L
         const val COLLAPSE_ANIMATION_DURATION_MS = 350L
@@ -61,6 +63,8 @@
             return rect
         }
 
+    fun getFlyoutMaxHeight(): Int = BubbleBarFlyoutView.getMaximumViewHeight(container.context)
+
     fun setUpAndShowFlyout(message: BubbleBarFlyoutMessage, onInit: () -> Unit, onEnd: () -> Unit) {
         flyout?.let(container::removeView)
         val flyout = BubbleBarFlyoutView(container.context, positioner, flyoutScheduler)
@@ -102,11 +106,10 @@
                 }
         }
         animator.addListener(
-            onStart = { extendTopBoundary() },
             onEnd = {
                 endAction()
                 flyout.setOnClickListener { callbacks.flyoutClicked() }
-            },
+            }
         )
         animator.start()
     }
@@ -114,14 +117,13 @@
     fun updateFlyoutFullyExpanded(message: BubbleBarFlyoutMessage, onEnd: () -> Unit) {
         val flyout = flyout ?: return
         hideFlyout(AnimationType.FADE) {
-            callbacks.resetTopBoundary()
             flyout.updateData(message) { showFlyout(AnimationType.FADE, onEnd) }
         }
     }
 
     fun updateFlyoutWhileExpanding(message: BubbleBarFlyoutMessage) {
         val flyout = flyout ?: return
-        flyout.updateData(message) { extendTopBoundary() }
+        flyout.updateData(message) {}
     }
 
     fun updateFlyoutWhileCollapsing(message: BubbleBarFlyoutMessage, onEnd: () -> Unit) {
@@ -131,14 +133,6 @@
         flyout.updateData(message) { showFlyout(AnimationType.MORPH, onEnd) }
     }
 
-    private fun extendTopBoundary() {
-        val flyout = flyout ?: return
-        val flyoutTop = flyout.top + flyout.translationY
-        // If the top position of the flyout is negative, then it's bleeding over the
-        // top boundary of its parent view
-        if (flyoutTop < 0) callbacks.extendTopBoundary(space = -flyoutTop.toInt())
-    }
-
     fun cancelFlyout(endAction: () -> Unit) {
         hideFlyout(AnimationType.FADE) {
             cleanupFlyoutView()
@@ -184,7 +178,6 @@
     private fun cleanupFlyoutView() {
         container.removeView(flyout)
         this@BubbleBarFlyoutController.flyout = null
-        callbacks.resetTopBoundary()
     }
 
     fun hasFlyout() = flyout != null
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
index 216f5e3..75bf937 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.content.res.Configuration
+import android.content.res.Resources
 import android.graphics.Canvas
 import android.graphics.Color
 import android.graphics.Outline
@@ -44,11 +45,27 @@
     scheduler: FlyoutScheduler? = null,
 ) : ConstraintLayout(context) {
 
-    private companion object {
-        // the minimum progress of the expansion animation before the content starts fading in.
-        const val MIN_EXPANSION_PROGRESS_FOR_CONTENT_ALPHA = 0.75f
+    companion object {
         // the rate multiple for the background color animation relative to the morph animation.
         const val BACKGROUND_COLOR_CHANGE_RATE = 5
+        // the minimum progress of the expansion animation before the content starts fading in.
+        private const val MIN_EXPANSION_PROGRESS_FOR_CONTENT_ALPHA = 0.75f
+
+        private const val TEXT_ROW_HEIGHT_SP = 20
+        private const val MAX_ROWS_COUNT = 3
+
+        /** Returns the maximum possible height of the flyout view. */
+        fun getMaximumViewHeight(context: Context): Int {
+            val verticalPaddings = getFlyoutPadding(context) * 2
+            val textSizeSp = TEXT_ROW_HEIGHT_SP * MAX_ROWS_COUNT
+            val textSizePx = textSizeSp * Resources.getSystem().displayMetrics.scaledDensity
+            val triangleHeight =
+                context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_triangle_height)
+            return verticalPaddings + textSizePx.toInt() + triangleHeight
+        }
+
+        private fun getFlyoutPadding(context: Context) =
+            context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding)
     }
 
     private val scheduler: FlyoutScheduler = scheduler ?: HandlerScheduler(this)
@@ -61,10 +78,7 @@
     private val message: TextView by
         lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.bubble_flyout_text) }
 
-    private val flyoutPadding by
-        lazy(LazyThreadSafetyMode.NONE) {
-            context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding)
-        }
+    private val flyoutPadding by lazy(LazyThreadSafetyMode.NONE) { getFlyoutPadding(context) }
 
     private val triangleHeight by
         lazy(LazyThreadSafetyMode.NONE) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/FlyoutCallbacks.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/FlyoutCallbacks.kt
index e2f010a..0804a62 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/FlyoutCallbacks.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/FlyoutCallbacks.kt
@@ -18,11 +18,6 @@
 
 /** Callbacks that the flyout uses to notify of events. */
 interface FlyoutCallbacks {
-    /** Requests to extend the top boundary of the parent to fully include the flyout. */
-    fun extendTopBoundary(space: Int)
-
-    /** Resets the top boundary of the parent. */
-    fun resetTopBoundary()
 
     /** The flyout was clicked. */
     fun flyoutClicked()
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
index 7c41d1d..595dac3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
@@ -74,6 +74,9 @@
     val isBubblesShowingOnOverview: Boolean
         get() = launcherState == BubbleLauncherState.OVERVIEW
 
+    /** Bubble bar vertical center for launcher home. */
+    var bubbleBarVerticalCenterForHome: Int
+
     /** Updated when sysui locked state changes, when locked, bubble bar is not shown. */
     var isSysuiLocked: Boolean
 
@@ -121,9 +124,6 @@
     /** Set a bubble bar location */
     fun setBubbleBarLocation(bubbleBarLocation: BubbleBarLocation)
 
-    /** Set the hotseat vertical center that bubble bar will align with. */
-    fun setHotseatVerticalCenter(hotseatVerticalCenter: Int)
-
     /**
      * Stashes the bubble bar (transform to the handle view), or just shrink width of the expanded
      * bubble bar based on the controller implementation.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
index 6a460ab..9d8c0ed 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
@@ -47,7 +47,7 @@
     private lateinit var bubbleBarAlphaAnimator: MultiPropertyFactory<View>.MultiProperty
     private lateinit var bubbleBarScaleAnimator: AnimatedFloat
     private lateinit var controllersAfterInitAction: ControllersAfterInitAction
-    private var hotseatVerticalCenter: Int = 0
+    override var bubbleBarVerticalCenterForHome: Int = 0
 
     override var launcherState: BubbleLauncherState = BubbleLauncherState.IN_APP
         set(state) {
@@ -97,7 +97,7 @@
     override val bubbleBarTranslationYForHotseat: Float
         get() {
             val bubbleBarHeight = bubbleBarViewController.bubbleBarCollapsedHeight
-            return -hotseatVerticalCenter + bubbleBarHeight / 2
+            return -bubbleBarVerticalCenterForHome + bubbleBarHeight / 2
         }
 
     override val bubbleBarTranslationY: Float
@@ -159,10 +159,6 @@
         animatorSet.setDuration(BAR_STASH_DURATION).start()
     }
 
-    override fun setHotseatVerticalCenter(hotseatVerticalCenter: Int) {
-        this.hotseatVerticalCenter = hotseatVerticalCenter
-    }
-
     override fun showBubbleBarImmediate() = showBubbleBarImmediate(bubbleBarTranslationY)
 
     override fun showBubbleBarImmediate(bubbleBarTranslationY: Float) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index 37c4ef5..df00696 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -78,7 +78,7 @@
         context.resources.getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f
 
     private var animator: AnimatorSet? = null
-    private var hotseatVerticalCenter: Int = 0
+    override var bubbleBarVerticalCenterForHome: Int = 0
 
     override var isStashed: Boolean = false
         @VisibleForTesting set
@@ -124,7 +124,7 @@
     override val bubbleBarTranslationYForHotseat: Float
         get() {
             val bubbleBarHeight = bubbleBarViewController.bubbleBarCollapsedHeight
-            return -hotseatVerticalCenter + bubbleBarHeight / 2
+            return -bubbleBarVerticalCenterForHome + bubbleBarHeight / 2
         }
 
     override val bubbleBarTranslationYForTaskbar: Float =
@@ -182,10 +182,6 @@
             .start()
     }
 
-    override fun setHotseatVerticalCenter(hotseatVerticalCenter: Int) {
-        this.hotseatVerticalCenter = hotseatVerticalCenter
-    }
-
     override fun showBubbleBarImmediate() {
         showBubbleBarImmediate(bubbleBarTranslationY)
     }
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
index 8beceb0..29d142f 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
@@ -36,6 +36,7 @@
 import com.android.launcher3.R
 import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
 import com.android.launcher3.taskbar.bubbles.BubbleBarOverflow
+import com.android.launcher3.taskbar.bubbles.BubbleBarParentViewHeightUpdateNotifier
 import com.android.launcher3.taskbar.bubbles.BubbleBarView
 import com.android.launcher3.taskbar.bubbles.BubbleView
 import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutController
@@ -69,6 +70,7 @@
 
     private val context = ApplicationProvider.getApplicationContext<Context>()
     private lateinit var animatorScheduler: TestBubbleBarViewAnimatorScheduler
+    private lateinit var bubbleBarParentViewController: TestBubbleBarParentViewHeightUpdateNotifier
     private lateinit var overflowView: BubbleView
     private lateinit var bubbleView: BubbleView
     private lateinit var bubble: BubbleBarBubble
@@ -84,6 +86,7 @@
     @Before
     fun setUp() {
         animatorScheduler = TestBubbleBarViewAnimatorScheduler()
+        bubbleBarParentViewController = TestBubbleBarParentViewHeightUpdateNotifier()
         PhysicsAnimatorTestUtils.prepareForTest()
         setupFlyoutController()
     }
@@ -102,6 +105,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -122,7 +126,7 @@
         assertThat(bubbleBarView.scaleY).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
         assertThat(animator.isAnimating).isTrue()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         // execute the hide bubble animation
@@ -135,6 +139,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(handle.alpha).isEqualTo(1)
         assertThat(handle.translationY).isEqualTo(0)
         assertThat(bubbleBarView.alpha).isEqualTo(0)
@@ -156,6 +161,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -178,7 +184,7 @@
         assertThat(animator.isAnimating).isTrue()
 
         verify(bubbleStashController, atLeastOnce()).updateTaskbarTouchRegion()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         // verify the hide bubble animation is pending
@@ -188,6 +194,7 @@
 
         waitForFlyoutToHide()
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(animatorScheduler.delayedBlock).isNull()
         assertThat(bubbleBarView.alpha).isEqualTo(1)
         assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
@@ -209,6 +216,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -255,6 +263,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -266,7 +275,7 @@
         // let the animation start and wait for it to complete
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         // execute the hide bubble animation
@@ -282,7 +291,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.onStashStateChangingWhileAnimating()
         }
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(animator.isAnimating).isFalse()
         verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any())
 
@@ -306,6 +315,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -344,6 +354,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -389,6 +400,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -440,6 +452,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -454,7 +467,7 @@
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
         assertThat(animator.isAnimating).isTrue()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         // verify the hide bubble animation is pending
@@ -469,6 +482,7 @@
 
         waitForFlyoutToHide()
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(handle.alpha).isEqualTo(0)
         assertThat(handle.translationY)
             .isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
@@ -495,6 +509,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -510,7 +525,7 @@
         assertThat(animator.isAnimating).isTrue()
         assertThat(bubbleBarView.alpha).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         assertThat(animatorScheduler.delayedBlock).isNotNull()
@@ -522,6 +537,7 @@
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
         InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(animator.isAnimating).isFalse()
         assertThat(bubbleBarView.alpha).isEqualTo(0)
         assertThat(handle.translationY).isEqualTo(0)
@@ -550,6 +566,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -585,6 +602,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -600,7 +618,7 @@
         assertThat(animator.isAnimating).isTrue()
         assertThat(bubbleBarView.alpha).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         assertThat(animatorScheduler.delayedBlock).isNotNull()
@@ -608,6 +626,7 @@
 
         waitForFlyoutToHide()
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(animator.isAnimating).isFalse()
         assertThat(bubbleBarView.alpha).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
@@ -629,6 +648,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -678,6 +698,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -689,7 +710,7 @@
         // wait for the animation to start
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         assertThat(animator.isAnimating).isTrue()
@@ -704,6 +725,7 @@
 
         // verify that the hide animation was canceled
         assertThat(animatorScheduler.delayedBlock).isNull()
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
 
         verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_HOTSEAT)
         assertThat(animator.isAnimating).isFalse()
@@ -724,6 +746,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -745,7 +768,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         barAnimator.assertIsRunning()
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         assertThat(animatorScheduler.delayedBlock).isNotNull()
@@ -754,6 +777,7 @@
         waitForFlyoutToHide()
 
         assertThat(animator.isAnimating).isFalse()
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         // the bubble bar translation y should be back to its initial value
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
 
@@ -778,6 +802,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -832,6 +857,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -896,6 +922,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -921,7 +948,7 @@
         // verify there is a pending hide animation
         assertThat(animatorScheduler.delayedBlock).isNotNull()
         assertThat(animator.isAnimating).isTrue()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
@@ -933,6 +960,7 @@
 
         waitForFlyoutToHide()
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(animator.isAnimating).isFalse()
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
         assertThat(bubbleBarView.isExpanded).isTrue()
@@ -954,6 +982,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -986,7 +1015,7 @@
         assertThat(bubbleBarView.scaleY).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
         assertThat(animator.isAnimating).isTrue()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
         assertThat(flyoutView!!.findViewById<TextView>(R.id.bubble_flyout_text).text)
             .isEqualTo("updated message")
@@ -1001,6 +1030,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(handle.alpha).isEqualTo(1)
         assertThat(handle.translationY).isEqualTo(0)
         assertThat(bubbleBarView.alpha).isEqualTo(0)
@@ -1022,6 +1052,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -1042,7 +1073,7 @@
         assertThat(bubbleBarView.scaleY).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
         assertThat(animator.isAnimating).isTrue()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         assertThat(flyoutView!!.findViewById<TextView>(R.id.bubble_flyout_text).text)
@@ -1075,6 +1106,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(handle.alpha).isEqualTo(1)
         assertThat(handle.translationY).isEqualTo(0)
         assertThat(bubbleBarView.alpha).isEqualTo(0)
@@ -1096,6 +1128,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -1116,7 +1149,7 @@
         assertThat(bubbleBarView.scaleY).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
         assertThat(animator.isAnimating).isTrue()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         assertThat(flyoutView!!.findViewById<TextView>(R.id.bubble_flyout_text).text)
@@ -1137,6 +1170,7 @@
             // the flyout should now reverse and expand
             animatorTestRule.advanceTimeBy(400)
         }
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
 
         assertThat(flyoutView!!.findViewById<TextView>(R.id.bubble_flyout_text).text)
             .isEqualTo("updated message")
@@ -1159,6 +1193,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(3)
         assertThat(handle.alpha).isEqualTo(1)
         assertThat(handle.translationY).isEqualTo(0)
         assertThat(bubbleBarView.alpha).isEqualTo(0)
@@ -1180,6 +1215,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -1200,7 +1236,7 @@
         assertThat(bubbleBarView.scaleY).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
         assertThat(animator.isAnimating).isTrue()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         assertThat(flyoutView!!.findViewById<TextView>(R.id.bubble_flyout_text).text)
@@ -1216,7 +1252,6 @@
         PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) {
             bubbleBarView.alpha < 0.5
         }
-
         // we're about to interrupt the animation which will cancel the current animation and start
         // a new one. pause the scheduler to delay starting the new animation. this allows us to run
         // the test deterministically
@@ -1229,9 +1264,11 @@
             animator.animateBubbleInForStashed(updatedBubble, isExpanding = false)
         }
 
+        // since animation was interrupted there shouldn`t be additional calls to adjust window
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
+
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
-
         // verify there's a new job scheduled and start it. this is starting the animation from the
         // handle back to the bar
         assertThat(animatorScheduler.pausedBlock).isNotNull()
@@ -1240,9 +1277,9 @@
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
-
         waitForFlyoutToShow()
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(flyoutView!!.findViewById<TextView>(R.id.bubble_flyout_text).text)
             .isEqualTo("updated message")
         assertThat(handle.alpha).isEqualTo(0)
@@ -1258,7 +1295,6 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
 
         waitForFlyoutToHide()
-
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
         // verify the hide animation was rescheduled and run it
@@ -1271,6 +1307,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(3)
         assertThat(handle.alpha).isEqualTo(1)
         assertThat(handle.translationY).isEqualTo(0)
         assertThat(bubbleBarView.alpha).isEqualTo(0)
@@ -1292,6 +1329,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -1392,10 +1430,6 @@
             }
         val flyoutCallbacks =
             object : FlyoutCallbacks {
-                override fun extendTopBoundary(space: Int) {}
-
-                override fun resetTopBoundary() {}
-
                 override fun flyoutClicked() {}
             }
         val flyoutScheduler = FlyoutScheduler { block -> block.invoke() }
@@ -1478,6 +1512,16 @@
             delayedBlock = null
         }
     }
+
+    private class TestBubbleBarParentViewHeightUpdateNotifier :
+        BubbleBarParentViewHeightUpdateNotifier {
+
+        var timesInvoked: Int = 0
+
+        override fun updateTopBoundary() {
+            timesInvoked++
+        }
+    }
 }
 
 private const val DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS = -20f
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
index 103c769..91fe6a6 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
@@ -128,46 +128,6 @@
     }
 
     @Test
-    fun showFlyout_extendsTopBoundary() {
-        // set negative translation for the flyout so that it will request to extend the top
-        // boundary
-        flyoutTy = -50f
-        InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            setupAndShowFlyout()
-            assertThat(flyoutContainer.childCount).isEqualTo(1)
-        }
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
-        InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            animatorTestRule.advanceTimeBy(showAnimationDuration)
-        }
-        assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(50)
-    }
-
-    @Test
-    fun showFlyout_withinBoundary() {
-        InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            setupAndShowFlyout()
-            assertThat(flyoutContainer.childCount).isEqualTo(1)
-        }
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
-        InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            animatorTestRule.advanceTimeBy(showAnimationDuration)
-        }
-        assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(0)
-    }
-
-    @Test
-    fun collapseFlyout_resetsTopBoundary() {
-        InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            setupAndShowFlyout()
-            assertThat(flyoutContainer.childCount).isEqualTo(1)
-            flyoutController.collapseFlyout {}
-            animatorTestRule.advanceTimeBy(hideAnimationDuration)
-        }
-        assertThat(flyoutCallbacks.topBoundaryReset).isTrue()
-    }
-
-    @Test
     fun cancelFlyout_fadesOutFlyout() {
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             setupAndShowFlyout()
@@ -178,7 +138,6 @@
             animatorTestRule.advanceTimeBy(hideAnimationDuration)
             assertThat(flyoutView.alpha).isEqualTo(0f)
         }
-        assertThat(flyoutCallbacks.topBoundaryReset).isTrue()
     }
 
     @Test
@@ -217,7 +176,6 @@
             assertThat(flyout.findViewById<TextView>(R.id.bubble_flyout_text).text)
                 .isEqualTo("new message")
         }
-        assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(50)
     }
 
     @Test
@@ -246,7 +204,6 @@
             animatorTestRule.advanceTimeBy(showAnimationDuration)
             assertThat(flyout.alpha).isEqualTo(1)
         }
-        assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(50)
     }
 
     @Test
@@ -290,18 +247,8 @@
 
     class FakeFlyoutCallbacks : FlyoutCallbacks {
 
-        var topBoundaryExtendedSpace = 0
-        var topBoundaryReset = false
         var flyoutClicked = false
 
-        override fun extendTopBoundary(space: Int) {
-            topBoundaryExtendedSpace = space
-        }
-
-        override fun resetTopBoundary() {
-            topBoundaryReset = true
-        }
-
         override fun flyoutClicked() {
             flyoutClicked = true
         }
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
index 5f3d7de..88b39d3 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
@@ -77,7 +77,7 @@
             PersistentBubbleStashController(DefaultDimensionsProvider())
         setUpBubbleBarView()
         setUpBubbleBarController()
-        persistentTaskBarStashController.setHotseatVerticalCenter(HOTSEAT_VERTICAL_CENTER)
+        persistentTaskBarStashController.bubbleBarVerticalCenterForHome = HOTSEAT_VERTICAL_CENTER
         persistentTaskBarStashController.init(
             taskbarInsetsController,
             bubbleBarViewController,
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
index bd5426d..f642345 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
@@ -109,7 +109,7 @@
         setUpStashedHandleView()
         setUpBubbleStashedHandleViewController()
         PhysicsAnimatorTestUtils.prepareForTest()
-        mTransientBubbleStashController.setHotseatVerticalCenter(HOTSEAT_VERTICAL_CENTER)
+        mTransientBubbleStashController.bubbleBarVerticalCenterForHome = HOTSEAT_VERTICAL_CENTER
         mTransientBubbleStashController.init(
             taskbarInsetsController,
             bubbleBarViewController,
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 09225e7..9b6fe4e 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -1861,13 +1861,15 @@
      * the bubble bar.
      *
      * <p>Does not check for visible bubbles persistence, so caller should call
-     * {@link #shouldAdjustHotseatForBubbleBar} first.
+     * {@link #shouldAdjustHotseatOrQsbForBubbleBar} first.
      *
      * <p>If there's no adjustment needed, this method returns {@code 0}.
-     * @see #shouldAdjustHotseatForBubbleBar(Context, boolean)
+     * @see #shouldAdjustHotseatOrQsbForBubbleBar(Context, boolean)
      */
     public float getHotseatAdjustedBorderSpaceForBubbleBar(Context context) {
-        if (!shouldAdjustHotseatForBubbleBar(context)) return 0;
+        if (shouldAlignBubbleBarWithQSB() || !shouldAdjustHotseatOrQsbForBubbleBar(context)) {
+            return 0;
+        }
         // The adjustment is shrinking the hotseat's width by 1 icon on either side.
         int iconsWidth =
                 iconSizePx * numShownHotseatIcons + hotseatBorderSpace * (numShownHotseatIcons - 1);
@@ -1880,27 +1882,37 @@
      * Returns the hotseat icon translation X for the cellX index.
      *
      * <p>Does not check for visible bubbles persistence, so caller should call
-     * {@link #shouldAdjustHotseatForBubbleBar} first.
+     * {@link #shouldAdjustHotseatOrQsbForBubbleBar} first.
      *
      * <p>If there's no adjustment needed, this method returns {@code 0}.
-     * @see #shouldAdjustHotseatForBubbleBar(Context, boolean)
+     * @see #shouldAdjustHotseatOrQsbForBubbleBar(Context, boolean)
      */
     public float getHotseatAdjustedTranslation(Context context, int cellX) {
-        if (!shouldAdjustHotseatForBubbleBar(context)) return 0;
         float borderSpace = getHotseatAdjustedBorderSpaceForBubbleBar(context);
+        if (borderSpace == 0) return borderSpace;
         float borderSpaceDelta = borderSpace - hotseatBorderSpace;
         return iconSizePx + cellX * borderSpaceDelta;
     }
 
-    /** Returns whether hotseat should be adjusted for the bubble bar. */
-    public boolean shouldAdjustHotseatForBubbleBar(Context context, boolean hasBubbles) {
-        return hasBubbles && shouldAdjustHotseatForBubbleBar(context);
+    /** Returns whether hotseat or QSB should be adjusted for the bubble bar. */
+    public boolean shouldAdjustHotseatOrQsbForBubbleBar(Context context, boolean hasBubbles) {
+        return hasBubbles && shouldAdjustHotseatOrQsbForBubbleBar(context);
     }
 
-    private boolean shouldAdjustHotseatForBubbleBar(Context context) {
-        // only need to adjust if bubble bar is enabled, when QSB is on top of the hotseat and
-        // there's not enough space for the bubble bar to the right of the hotseat.
-        return !isQsbInline && getHotseatLayoutPadding(context).right <= mBubbleBarSpaceThresholdPx;
+    /** Returns whether hotseat should be adjusted for the bubble bar. */
+    public boolean shouldAdjustHotseatForBubbleBar(Context context, boolean hasBubbles) {
+        return shouldAlignBubbleBarWithHotseat()
+                && shouldAdjustHotseatOrQsbForBubbleBar(context, hasBubbles);
+    }
+
+    /** Returns whether hotseat or QSB should be adjusted for the bubble bar. */
+    public boolean shouldAdjustHotseatOrQsbForBubbleBar(Context context) {
+        // only need to adjust if QSB is on top of the hotseat and there's not enough space for the
+        // bubble bar to either side of the hotseat.
+        if (isQsbInline) return false;
+        Rect hotseatPadding = getHotseatLayoutPadding(context);
+        int hotseatMinHorizontalPadding = Math.min(hotseatPadding.left, hotseatPadding.right);
+        return hotseatMinHorizontalPadding <= mBubbleBarSpaceThresholdPx;
     }
 
     /**
@@ -2055,15 +2067,29 @@
     }
 
     /**
-     * Returns the number of pixels the hotseat icons vertical center is translated from the bottom
-     * of the screen.
+     * Returns the number of pixels the hotseat icons or QSB vertical center is translated from the
+     * bottom of the screen.
      */
-    public int getHotseatVerticalCenter() {
-        return hotseatBarSizePx
-                - (isQsbInline ? 0 : hotseatQsbVisualHeight)
-                - hotseatQsbSpace
-                - (hotseatCellHeightPx / 2)
-                + ((hotseatCellHeightPx - iconSizePx) / 2);
+    public int getBubbleBarVerticalCenterForHome() {
+        if (shouldAlignBubbleBarWithHotseat()) {
+            return hotseatBarSizePx
+                    - (isQsbInline ? 0 : hotseatQsbVisualHeight)
+                    - hotseatQsbSpace
+                    - (hotseatCellHeightPx / 2)
+                    + ((hotseatCellHeightPx - iconSizePx) / 2);
+        } else {
+            return hotseatBarSizePx - (hotseatQsbVisualHeight / 2);
+        }
+    }
+
+    /** Returns whether bubble bar should be aligned with the hotseat. */
+    public boolean shouldAlignBubbleBarWithQSB() {
+        return !shouldAlignBubbleBarWithHotseat();
+    }
+
+    /** Returns whether bubble bar should be aligned with the hotseat. */
+    public boolean shouldAlignBubbleBarWithHotseat() {
+        return isQsbInline || isGestureMode;
     }
 
     /**
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index b2ccba4..6be8098 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -186,9 +186,10 @@
      */
     public void adjustForBubbleBar(boolean isBubbleBarVisible) {
         DeviceProfile dp = mActivity.getDeviceProfile();
-        float adjustedBorderSpace = dp.getHotseatAdjustedBorderSpaceForBubbleBar(getContext());
-        boolean shouldAdjustHotseat = isBubbleBarVisible
-                && Float.compare(adjustedBorderSpace, 0f) != 0;
+        boolean shouldAdjust = isBubbleBarVisible
+                && dp.shouldAdjustHotseatOrQsbForBubbleBar(getContext());
+        boolean shouldAdjustHotseat = shouldAdjust
+                && dp.shouldAlignBubbleBarWithHotseat();
         ShortcutAndWidgetContainer icons = getShortcutsAndWidgets();
         // update the translation provider for future layout passes of hotseat icons.
         if (shouldAdjustHotseat) {
@@ -209,9 +210,12 @@
                 animatorSet.play(ObjectAnimator.ofFloat(child, VIEW_TRANSLATE_X, tx));
             }
         }
+        //TODO(b/381109832) refactor & simplify adjustment logic
+        boolean shouldAdjustQsb =
+                shouldAdjustHotseat || (shouldAdjust && dp.shouldAlignBubbleBarWithQSB());
         if (mQsb instanceof HorizontalInsettableView horizontalInsettableQsb) {
             final float currentInsetFraction = horizontalInsettableQsb.getHorizontalInsets();
-            final float targetInsetFraction = shouldAdjustHotseat
+            final float targetInsetFraction = shouldAdjustQsb
                     ? (float) dp.iconSizePx / dp.hotseatQsbWidth : 0;
             ValueAnimator qsbAnimator =
                     ValueAnimator.ofFloat(currentInsetFraction, targetInsetFraction);