Center bubbles in landscape

BubbleController - listen for orientation change
BubbleStackView, on change - update effective row width; if expanded,
redraw bubble row and pointer

Fixes: 135472021
Bug: 135487618
Test: manual (bubbles remain centered going between portrait and landscape)
Test: manual (bubbles expand to correct positions in portrait and landscape)
Test: atest SystemUITests
Change-Id: I815cd426e26b84b8bd8736dcf16f2119584ecf30
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 5d61179..72d45c7 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -287,8 +287,8 @@
     @Override
     public void onConfigChanged(Configuration newConfig) {
         if (mStackView != null && newConfig != null && newConfig.orientation != mOrientation) {
-            mStackView.onOrientationChanged();
             mOrientation = newConfig.orientation;
+            mStackView.onOrientationChanged(newConfig.orientation);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index ec220e5..78af89a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -29,6 +29,7 @@
 import android.annotation.NonNull;
 import android.app.Notification;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
@@ -163,7 +164,7 @@
     private Runnable mHideFlyout = () -> animateFlyoutCollapsed(true, 0 /* velX */);
 
     /** Layout change listener that moves the stack to the nearest valid position on rotation. */
-    private OnLayoutChangeListener mMoveStackToValidPositionOnLayoutListener;
+    private OnLayoutChangeListener mOrientationChangedListener;
     /** Whether the stack was on the left side of the screen prior to rotation. */
     private boolean mWasOnLeftBeforeRotation = false;
     /**
@@ -291,6 +292,8 @@
     private boolean mSuppressNewDot = false;
     private boolean mSuppressFlyout = false;
 
+    private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
+
     public BubbleStackView(Context context, BubbleData data,
             @Nullable SurfaceSynchronizer synchronizer) {
         super(context);
@@ -326,8 +329,9 @@
         int elevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
 
         mStackAnimationController = new StackAnimationController();
+
         mExpandedAnimationController = new ExpandedAnimationController(
-                mDisplaySize, mExpandedViewPadding);
+                mDisplaySize, mExpandedViewPadding, res.getConfiguration().orientation);
         mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER;
 
         mBubbleContainer = new PhysicsAnimationLayout(context);
@@ -417,13 +421,20 @@
             return view.onApplyWindowInsets(insets);
         });
 
-        mMoveStackToValidPositionOnLayoutListener =
+        mOrientationChangedListener =
                 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                    mExpandedAnimationController.updateOrientation(mOrientation);
+                    if (mIsExpanded) {
+                        // Re-draw bubble row and pointer for new orientation.
+                        mExpandedAnimationController.expandFromStack(() -> {
+                            updatePointerPosition();
+                        } /* after */);
+                    }
                     if (mVerticalPosPercentBeforeRotation >= 0) {
                         mStackAnimationController.moveStackToSimilarPositionAfterRotation(
                                 mWasOnLeftBeforeRotation, mVerticalPosPercentBeforeRotation);
                     }
-                    removeOnLayoutChangeListener(mMoveStackToValidPositionOnLayoutListener);
+                    removeOnLayoutChangeListener(mOrientationChangedListener);
                 };
 
         // This must be a separate OnDrawListener since it should be called for every draw.
@@ -464,14 +475,15 @@
     }
 
     /** Respond to the phone being rotated by repositioning the stack and hiding any flyouts. */
-    public void onOrientationChanged() {
+    public void onOrientationChanged(int orientation) {
+        mOrientation = orientation;
+
         final RectF allowablePos = mStackAnimationController.getAllowableStackPositionRegion();
         mWasOnLeftBeforeRotation = mStackAnimationController.isStackOnLeftSide();
         mVerticalPosPercentBeforeRotation =
                 (mStackAnimationController.getStackPosition().y - allowablePos.top)
                         / (allowablePos.bottom - allowablePos.top);
-        addOnLayoutChangeListener(mMoveStackToValidPositionOnLayoutListener);
-
+        addOnLayoutChangeListener(mOrientationChangedListener);
         hideFlyoutImmediate();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index b69b94c..c1671aa 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.bubbles.animation;
 
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -64,6 +65,8 @@
     private Point mDisplaySize;
     /** Max number of bubbles shown in row above expanded view.*/
     private int mBubblesMaxRendered;
+    /** Width of current screen orientation. */
+    private float mScreenWidth;
 
     /** Whether the dragged-out bubble is in the dismiss target. */
     private boolean mIndividualBubbleWithinDismissTarget = false;
@@ -88,8 +91,10 @@
     private int mExpandedViewPadding;
     private float mLauncherGridDiff;
 
-    public ExpandedAnimationController(Point displaySize, int expandedViewPadding) {
+    public ExpandedAnimationController(Point displaySize, int expandedViewPadding,
+            int orientation) {
         mDisplaySize = displaySize;
+        updateOrientation(orientation);
         mExpandedViewPadding = expandedViewPadding;
         mLauncherGridDiff = 30f;
     }
@@ -124,6 +129,18 @@
         startOrUpdateCollapseAnimation();
     }
 
+    /**
+     * Update effective screen width based on current orientation.
+     * @param orientation Landscape or portrait.
+     */
+    public void updateOrientation(int orientation) {
+        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            mScreenWidth = mDisplaySize.y;
+            return;
+        }
+        mScreenWidth = mDisplaySize.x;
+    }
+
     private void startOrUpdateExpandAnimation() {
         animationsForChildrenFromIndex(
                 0, /* startIndex */
@@ -421,7 +438,7 @@
         final float totalGapWidth = (bubbleCount - 1) * getSpaceBetweenBubbles();
         final float rowWidth = totalGapWidth + totalBubbleWidth;
 
-        final float centerScreen = mDisplaySize.x / 2f;
+        final float centerScreen = mScreenWidth / 2f;
         final float halfRow = rowWidth / 2f;
         final float rowLeft = centerScreen - halfRow;
 
@@ -441,7 +458,7 @@
          *  Launcher's app icon grid edge that we must match
          */
         final float rowMargins = (mExpandedViewPadding + mLauncherGridDiff) * 2;
-        final float maxRowWidth = mDisplaySize.x - rowMargins;
+        final float maxRowWidth = mScreenWidth - rowMargins;
 
         final float totalBubbleWidth = mBubblesMaxRendered * mBubbleSizePx;
         final float totalGapWidth = maxRowWidth - totalBubbleWidth;