From feb3a68db721182af7e8ba6a59f0e77a7ecbf5e6 Mon Sep 17 00:00:00 2001 From: Ats Jenk Date: Fri, 12 Jan 2024 17:03:19 -0800 Subject: [PATCH] Bubble bar expland/collapse animation when on left Fix bubble bar collapse and expand animations when bubble bar is pinned to the left. When system language is set to an RTL language, bubble bar gets pinned to the left edge of the screen. Bubble bar should expand to the right and collapse to the left. Bubbles in the bubble bar should be ordered from right to left. The most recent bubble should be at the right in the bubble bar. Known issue: - when the most recent bubble is removed, the arrow animates to a new position, but the background is not animated, resulting in arrow getting detached from the container. Will be fixed by animating the background. Flag: LEGACY persist.wm.debug.bubble_bar DEVELOPMENT Bug: 273310265 Test: with LTR language set as the system language - expand bubble bar with 1 bubble - expand bubble bar with multiple bubbles - select second bubble, observe after collapse it is set as first - dismiss a bubble from bubble bar by dragging Test: with RTL language set as the system language - expand bubble bar with 1 bubble - expand bubble bar with multiple bubbles - select second bubble, observe after collapse it is set as first - dismiss a bubble from bubble bar by dragging Change-Id: Ic46a5b1a6e45ad225ba509a61147cc6a8cdd0397 --- .../taskbar/bubbles/BubbleBarBackground.kt | 28 ++++--- .../taskbar/bubbles/BubbleBarView.java | 79 ++++++++++++++----- .../bubbles/BubbleBarViewController.java | 4 +- 3 files changed, 83 insertions(+), 28 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt index 1e3f4f13f2..aa2b29de39 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt @@ -50,6 +50,22 @@ class BubbleBarBackground(context: TaskbarActivityContext, private val backgroun var width: Float = 0f + /** + * Set whether the drawable is anchored to the left or right edge of the container. + * + * When `anchorLeft` is set to `true`, drawable left edge aligns up with the container left + * edge. Drawable can be drawn outside container bounds on the right edge. When it is set to + * `false` (the default), drawable right edge aligns up with the container right edge. Drawable + * can be drawn outside container bounds on the left edge. + */ + var anchorLeft: Boolean = false + set(value) { + if (field != value) { + field = value + invalidateSelf() + } + } + init { paint.color = context.getColor(R.color.taskbar_background) paint.flags = Paint.ANTI_ALIAS_FLAG @@ -106,15 +122,9 @@ class BubbleBarBackground(context: TaskbarActivityContext, private val backgroun // Draw background. val radius = backgroundHeight / 2f - canvas.drawRoundRect( - canvas.width.toFloat() - width, - 0f, - canvas.width.toFloat(), - canvas.height.toFloat(), - radius, - radius, - paint - ) + val left = if (anchorLeft) 0f else canvas.width.toFloat() - width + val right = if (anchorLeft) width else canvas.width.toFloat() + canvas.drawRoundRect(left, 0f, right, canvas.height.toFloat(), radius, radius, paint) if (showingArrow) { // Draw arrow. diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java index ec9f4e5567..5ca2991d6b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java @@ -197,6 +197,16 @@ public class BubbleBarView extends FrameLayout { updateChildrenRenderNodeProperties(); } + @Override + public void onRtlPropertiesChanged(int layoutDirection) { + // TODO(b/273310265): set this based on bubble bar position and not LTR or RTL + mBubbleBarBackground.setAnchorLeft(layoutDirection == LAYOUT_DIRECTION_RTL); + } + + private boolean isOnLeft() { + return getLayoutDirection() == LAYOUT_DIRECTION_RTL; + } + /** * Updates the bounds with translation that may have been applied and returns the result. */ @@ -275,18 +285,31 @@ public class BubbleBarView extends FrameLayout { int bubbleCount = getChildCount(); final float ty = (mBubbleBarBounds.height() - mIconSize) / 2f; final boolean animate = getVisibility() == VISIBLE; + final boolean onLeft = isOnLeft(); for (int i = 0; i < bubbleCount; i++) { BubbleView bv = (BubbleView) getChildAt(i); bv.setTranslationY(ty); // the position of the bubble when the bar is fully expanded - final float expandedX = i * (mIconSize + mIconSpacing); + final float expandedX; // the position of the bubble when the bar is fully collapsed - final float collapsedX = i == 0 ? 0 : mIconOverlapAmount; + final float collapsedX; + if (onLeft) { + // If bar is on the left, bubbles are ordered right to left + expandedX = (bubbleCount - i - 1) * (mIconSize + mIconSpacing); + // Shift the first bubble only if there are more bubbles in addition to overflow + collapsedX = i == 0 && bubbleCount > 2 ? mIconOverlapAmount : 0; + } else { + // Bubbles ordered left to right, don't move the first bubble + expandedX = i * (mIconSize + mIconSpacing); + collapsedX = i == 0 ? 0 : mIconOverlapAmount; + } if (mIsBarExpanded) { + // If bar is on the right, account for bubble bar expanding and shifting left + final float expandedBarShift = onLeft ? 0 : currentWidth - expandedWidth; // where the bubble will end up when the animation ends - final float targetX = currentWidth - expandedWidth + expandedX; + final float targetX = expandedX + expandedBarShift; bv.setTranslationX(widthState * (targetX - collapsedX) + collapsedX); // if we're fully expanded, set the z level to 0 or to bubble elevation if dragged if (widthState == 1f) { @@ -296,7 +319,9 @@ public class BubbleBarView extends FrameLayout { bv.setBehindStack(false, animate); bv.setAlpha(1); } else { - final float targetX = currentWidth - collapsedWidth + collapsedX; + // If bar is on the right, account for bubble bar expanding and shifting left + final float collapsedBarShift = onLeft ? 0 : currentWidth - collapsedWidth; + final float targetX = collapsedX + collapsedBarShift; bv.setTranslationX(widthState * (expandedX - targetX) + targetX); bv.setZ((MAX_BUBBLES * mBubbleElevation) - i); // If we're not the first bubble we're behind the stack @@ -318,18 +343,22 @@ public class BubbleBarView extends FrameLayout { final float expandedArrowPosition = arrowPositionForSelectedWhenExpanded(); final float interpolatedWidth = widthState * (expandedWidth - collapsedWidth) + collapsedWidth; - if (mIsBarExpanded) { - // when the bar is expanding, the selected bubble is always the first, so the arrow - // always shifts with the interpolated width. - final float arrowPosition = currentWidth - interpolatedWidth + collapsedArrowPosition; - mBubbleBarBackground.setArrowPosition(arrowPosition); + final float arrowPosition; + if (onLeft) { + float interpolatedShift = (expandedArrowPosition - collapsedArrowPosition) * widthState; + arrowPosition = collapsedArrowPosition + interpolatedShift; } else { - final float targetPosition = currentWidth - collapsedWidth + collapsedArrowPosition; - final float arrowPosition = - targetPosition + widthState * (expandedArrowPosition - targetPosition); - mBubbleBarBackground.setArrowPosition(arrowPosition); + if (mIsBarExpanded) { + // when the bar is expanding, the selected bubble is always the first, so the arrow + // always shifts with the interpolated width. + arrowPosition = currentWidth - interpolatedWidth + collapsedArrowPosition; + } else { + final float targetPosition = currentWidth - collapsedWidth + collapsedArrowPosition; + arrowPosition = + targetPosition + widthState * (expandedArrowPosition - targetPosition); + } } - + mBubbleBarBackground.setArrowPosition(arrowPosition); mBubbleBarBackground.setArrowAlpha((int) (255 * widthState)); mBubbleBarBackground.setWidth(interpolatedWidth); } @@ -394,9 +423,8 @@ public class BubbleBarView extends FrameLayout { Log.w(TAG, "trying to update selection arrow without a selected view!"); return; } - final int index = indexOfChild(mSelectedBubbleView); // Find the center of the bubble when it's expanded, set the arrow position to it. - final float tx = getPaddingStart() + index * (mIconSize + mIconSpacing) + mIconSize / 2f; + final float tx = arrowPositionForSelectedWhenExpanded(); if (shouldAnimate) { final float currentArrowPosition = mBubbleBarBackground.getArrowPositionX(); @@ -416,12 +444,27 @@ public class BubbleBarView extends FrameLayout { private float arrowPositionForSelectedWhenExpanded() { final int index = indexOfChild(mSelectedBubbleView); - return getPaddingStart() + index * (mIconSize + mIconSpacing) + mIconSize / 2f; + final int bubblePosition; + if (isOnLeft()) { + // Bubble positions are reversed. First bubble is on the right. + bubblePosition = getChildCount() - index - 1; + } else { + bubblePosition = index; + } + return getPaddingStart() + bubblePosition * (mIconSize + mIconSpacing) + mIconSize / 2f; } private float arrowPositionForSelectedWhenCollapsed() { final int index = indexOfChild(mSelectedBubbleView); - return getPaddingStart() + index * (mIconOverlapAmount) + mIconSize / 2f; + final int bubblePosition; + if (isOnLeft()) { + // Bubble positions are reversed. First bubble may be shifted, if there are more + // bubbles than the current bubble and overflow. + bubblePosition = index == 0 && getChildCount() > 2 ? 1 : 0; + } else { + bubblePosition = index; + } + return getPaddingStart() + bubblePosition * (mIconOverlapAmount) + mIconSize / 2f; } @Override diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java index 065dd58f16..6bb7b04c98 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java @@ -21,6 +21,7 @@ import static android.view.View.VISIBLE; import android.graphics.Point; import android.graphics.Rect; import android.util.Log; +import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; @@ -289,7 +290,8 @@ public class BubbleBarViewController { */ public void addBubble(BubbleBarItem b) { if (b != null) { - mBarView.addView(b.getView(), 0, new FrameLayout.LayoutParams(mIconSize, mIconSize)); + mBarView.addView(b.getView(), 0, + new FrameLayout.LayoutParams(mIconSize, mIconSize, Gravity.LEFT)); b.getView().setOnClickListener(mBubbleClickListener); mBubbleDragController.setupBubbleView(b.getView()); } else {