From be3b3cfd3c67512739618a26d7039a996cae18b4 Mon Sep 17 00:00:00 2001 From: Ats Jenk Date: Tue, 31 May 2022 16:22:08 -0700 Subject: [PATCH] Position bubbles from right to left When a RTL language is used, position bubbles from right to left when the stack is expanded. BubblePositioner uses view index to position bubbles on screen. Reverting the index in case of RTL languages so calculations are done with last bubble in the list landing on the left side etc. Bug: 234071989 Test: manual, on phone, set device language to Arabic, expand bubble stack, observe overflow icon on the left, top bubble on the right Test: manual, on tablet, set device language to Arabic, expand bubble stack, obserer top bubble on top, overflow at the bottom Change-Id: I297f1e653046d488e6de9ac81eb6bfb8d3afef1d --- .../wm/shell/bubbles/BubblePositioner.java | 29 ++++++++++++++----- .../ExpandedAnimationController.java | 22 ++++++++++++-- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java index 9770a3f8882cd..dbad5df9cf560 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java @@ -16,6 +16,8 @@ package com.android.wm.shell.bubbles; +import static android.view.View.LAYOUT_DIRECTION_RTL; + import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; @@ -28,7 +30,6 @@ import android.graphics.Rect; import android.graphics.RectF; import android.util.Log; import android.view.Surface; -import android.view.View; import android.view.WindowInsets; import android.view.WindowManager; import android.view.WindowMetrics; @@ -565,16 +566,30 @@ public class BubblePositioner { * @return the position of the bubble on-screen when the stack is expanded. */ public PointF getExpandedBubbleXY(int index, BubbleStackView.StackViewState state) { - final float positionInRow = index * (mBubbleSize + mSpacingBetweenBubbles); + boolean showBubblesVertically = showBubblesVertically(); + boolean isRtl = mContext.getResources().getConfiguration().getLayoutDirection() + == LAYOUT_DIRECTION_RTL; + + int onScreenIndex; + if (showBubblesVertically || !isRtl) { + onScreenIndex = index; + } else { + // If bubbles are shown horizontally, check if RTL language is used. + // If RTL is active, position first bubble on the right and last on the left. + // Last bubble has screen index 0 and first bubble has max screen index value. + onScreenIndex = state.numberOfBubbles - 1 - index; + } + + final float positionInRow = onScreenIndex * (mBubbleSize + mSpacingBetweenBubbles); final float expandedStackSize = getExpandedStackSize(state.numberOfBubbles); - final float centerPosition = showBubblesVertically() + final float centerPosition = showBubblesVertically ? mPositionRect.centerY() : mPositionRect.centerX(); // alignment - centered on the edge final float rowStart = centerPosition - (expandedStackSize / 2f); float x; float y; - if (showBubblesVertically()) { + if (showBubblesVertically) { int inset = mExpandedViewLargeScreenInsetClosestEdge; y = rowStart + positionInRow; int left = mIsLargeScreen @@ -591,8 +606,8 @@ public class BubblePositioner { x = rowStart + positionInRow; } - if (showBubblesVertically() && mImeVisible) { - return new PointF(x, getExpandedBubbleYForIme(index, state)); + if (showBubblesVertically && mImeVisible) { + return new PointF(x, getExpandedBubbleYForIme(onScreenIndex, state)); } return new PointF(x, y); } @@ -701,7 +716,7 @@ public class BubblePositioner { // Start on the left if we're in LTR, right otherwise. final boolean startOnLeft = mContext.getResources().getConfiguration().getLayoutDirection() - != View.LAYOUT_DIRECTION_RTL; + != LAYOUT_DIRECTION_RTL; final float startingVerticalOffset = mContext.getResources().getDimensionPixelOffset( R.dimen.bubble_stack_starting_offset_y); // TODO: placement bug here because mPositionRect doesn't handle the overhanging edge diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java index c24efb9f55348..b521cb6a3d388 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java @@ -16,6 +16,8 @@ package com.android.wm.shell.bubbles.animation; +import static android.view.View.LAYOUT_DIRECTION_RTL; + import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING; import static com.android.wm.shell.bubbles.BubbleStackView.HOME_GESTURE_ENABLED; @@ -243,6 +245,11 @@ public class ExpandedAnimationController }; } + boolean showBubblesVertically = mPositioner.showBubblesVertically(); + final boolean isRtl = + mLayout.getContext().getResources().getConfiguration().getLayoutDirection() + == LAYOUT_DIRECTION_RTL; + // Animate each bubble individually, since each path will end in a different spot. animationsForChildrenFromIndex(0, (index, animation) -> { final View bubble = mLayout.getChildAt(index); @@ -277,9 +284,20 @@ public class ExpandedAnimationController // right side, the first bubble is traveling to the top left, so it leads. During // collapse to the left, the first bubble has the shortest travel time back to the stack // position, so it leads (and vice versa). - final boolean firstBubbleLeads = - (expanding && !mLayout.isFirstChildXLeftOfCenter(bubble.getTranslationX())) + final boolean firstBubbleLeads; + if (showBubblesVertically || !isRtl) { + firstBubbleLeads = + (expanding && !mLayout.isFirstChildXLeftOfCenter(bubble.getTranslationX())) || (!expanding && mLayout.isFirstChildXLeftOfCenter(mCollapsePoint.x)); + } else { + // For RTL languages, when showing bubbles horizontally, it is reversed. The bubbles + // are positioned right to left. This means that when expanding from left, the top + // bubble will lead as it will be positioned on the right. And when expanding from + // right, the top bubble will have the least travel distance. + firstBubbleLeads = + (expanding && mLayout.isFirstChildXLeftOfCenter(bubble.getTranslationX())) + || (!expanding && !mLayout.isFirstChildXLeftOfCenter(mCollapsePoint.x)); + } final int startDelay = firstBubbleLeads ? (index * 10) : ((mLayout.getChildCount() - index) * 10);