Merge "Ensure the bubble expanded view aligns with the pointer" into sc-v2-dev am: cc312e1054

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15144071

Change-Id: I69abce0f9bcd5e7ffecdc2943b82834dbe3e1c93
This commit is contained in:
Mady Mellor
2021-06-29 19:04:05 +00:00
committed by Automerger Merge Worker
4 changed files with 151 additions and 74 deletions

View File

@@ -25,6 +25,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
@@ -60,7 +61,6 @@ import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.launcher3.icons.IconNormalizer;
import com.android.wm.shell.R;
import com.android.wm.shell.TaskView;
import com.android.wm.shell.common.AlphaOptimizedButton;
@@ -77,7 +77,6 @@ public class BubbleExpandedView extends LinearLayout {
// The triangle pointing to the expanded view
private View mPointerView;
private int mPointerMargin;
@Nullable private int[] mExpandedViewContainerLocation;
private AlphaOptimizedButton mManageButton;
@@ -102,9 +101,6 @@ public class BubbleExpandedView extends LinearLayout {
*/
private boolean mIsAlphaAnimating = false;
private int mMinHeight;
private int mOverflowHeight;
private int mManageButtonHeight;
private int mPointerWidth;
private int mPointerHeight;
private float mPointerRadius;
@@ -348,12 +344,8 @@ public class BubbleExpandedView extends LinearLayout {
void updateDimensions() {
Resources res = getResources();
mMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
updateFontSize();
mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
mPointerRadius = getResources().getDimensionPixelSize(R.dimen.bubble_pointer_radius);
@@ -369,7 +361,6 @@ public class BubbleExpandedView extends LinearLayout {
updatePointerView();
}
mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_height);
if (mManageButton != null) {
int visibility = mManageButton.getVisibility();
removeView(mManageButton);
@@ -633,12 +624,11 @@ public class BubbleExpandedView extends LinearLayout {
}
if ((mBubble != null && mTaskView != null) || mIsOverflow) {
float desiredHeight = mIsOverflow
? mPositioner.isLargeScreen() ? getMaxExpandedHeight() : mOverflowHeight
: mBubble.getDesiredHeight(mContext);
desiredHeight = Math.max(desiredHeight, mMinHeight);
float height = Math.min(desiredHeight, getMaxExpandedHeight());
height = Math.max(height, mMinHeight);
float desiredHeight = mPositioner.getExpandedViewHeight(mBubble);
int maxHeight = mPositioner.getMaxExpandedViewHeight(mIsOverflow);
float height = desiredHeight == MAX_HEIGHT
? maxHeight
: Math.min(desiredHeight, maxHeight);
FrameLayout.LayoutParams lp = mIsOverflow
? (FrameLayout.LayoutParams) mOverflowView.getLayoutParams()
: (FrameLayout.LayoutParams) mTaskView.getLayoutParams();
@@ -662,23 +652,6 @@ public class BubbleExpandedView extends LinearLayout {
}
}
private int getMaxExpandedHeight() {
int expandedContainerY = mExpandedViewContainerLocation != null
// Remove top insets back here because availableRect.height would account for that
? mExpandedViewContainerLocation[1] - mPositioner.getInsets().top
: 0;
int settingsHeight = mIsOverflow ? 0 : mManageButtonHeight;
int pointerHeight = mPositioner.showBubblesVertically()
? mPointerWidth
: (int) (mPointerHeight - mPointerOverlap + mPointerMargin);
return mPositioner.getAvailableRect().height()
- expandedContainerY
- getPaddingTop()
- getPaddingBottom()
- settingsHeight
- pointerHeight;
}
/**
* Update appearance of the expanded view being displayed.
*
@@ -728,14 +701,11 @@ public class BubbleExpandedView extends LinearLayout {
: mPointerHeight - mPointerOverlap;
setPadding((int) paddingLeft, (int) paddingTop, (int) paddingRight, 0);
final float expandedViewY = mPositioner.getExpandedViewY();
// TODO: I don't understand why it works but it does - why normalized in portrait
// & not in landscape? Am I missing ~2dp in the portrait expandedViewY calculation?
final float normalizedSize = IconNormalizer.getNormalizedCircleSize(
mPositioner.getBubbleSize());
final float bubbleCenter = showVertically
? bubblePosition + (mPositioner.getBubbleSize() / 2f) - expandedViewY
: bubblePosition + (normalizedSize / 2f) - mPointerWidth;
// Subtract the expandedViewY here because the pointer is placed within the expandedView.
float pointerPosition = mPositioner.getPointerPosition(bubblePosition);
final float bubbleCenter = mPositioner.showBubblesVertically()
? pointerPosition - mPositioner.getExpandedViewY(mBubble, bubblePosition)
: pointerPosition;
// Post because we need the width of the view
post(() -> {
float pointerY;

View File

@@ -34,6 +34,7 @@ import android.view.WindowMetrics;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.icons.IconNormalizer;
import com.android.wm.shell.R;
import java.lang.annotation.Retention;
@@ -58,6 +59,8 @@ public class BubblePositioner {
/** When the bubbles are collapsed in a stack only some of them are shown, this is how many. **/
public static final int NUM_VISIBLE_WHEN_RESTING = 2;
/** Indicates a bubble's height should be the maximum available space. **/
public static final int MAX_HEIGHT = -1;
private Context mContext;
private WindowManager mWindowManager;
@@ -68,13 +71,16 @@ public class BubblePositioner {
private int mMaxBubbles;
private int mBubbleSize;
private int mBubbleBadgeSize;
private int mSpacingBetweenBubbles;
private int mExpandedViewLargeScreenWidth;
private int mExpandedViewPadding;
private int mPointerMargin;
private float mPointerWidth;
private float mPointerHeight;
private int mPointerWidth;
private int mPointerHeight;
private int mPointerOverlap;
private int mManageButtonHeight;
private int mExpandedViewMinHeight;
private int mOverflowHeight;
private PointF mPinLocation;
private PointF mRestingStackPosition;
@@ -151,7 +157,6 @@ public class BubblePositioner {
Resources res = mContext.getResources();
mBubbleSize = res.getDimensionPixelSize(R.dimen.bubble_size);
mBubbleBadgeSize = res.getDimensionPixelSize(R.dimen.bubble_badge_size);
mSpacingBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing);
mDefaultMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
@@ -161,6 +166,10 @@ public class BubblePositioner {
mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
mPointerOverlap = res.getDimensionPixelSize(R.dimen.bubble_pointer_overlap);
mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_height);
mExpandedViewMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
mMaxBubbles = calculateMaxBubbles();
@@ -296,8 +305,8 @@ public class BubblePositioner {
return mPaddings;
}
/** Calculates the y position of the expanded view when it is expanded. */
public float getExpandedViewY() {
/** Gets the y position of the expanded view if it was top-aligned. */
private float getExpandedViewYTopAligned() {
final int top = getAvailableRect().top;
if (showBubblesVertically()) {
return top - mPointerWidth;
@@ -306,6 +315,116 @@ public class BubblePositioner {
}
}
/** The maximum height the expanded view can be. */
public int getMaxExpandedViewHeight(boolean isOverflow) {
int paddingTop = showBubblesVertically()
? 0
: mPointerHeight;
int settingsHeight = isOverflow ? 0 : mManageButtonHeight;
// Subtract pointer size because it's laid out in LinearLayout with the expanded view.
int pointerSize = showBubblesVertically()
? mPointerWidth
: (mPointerHeight + mPointerMargin);
// Subtract top insets because availableRect.height would account for that
int expandedContainerY = (int) getExpandedViewYTopAligned() - getInsets().top;
return getAvailableRect().height()
- expandedContainerY
- paddingTop
- settingsHeight
- pointerSize;
}
/**
* Determines the height for the bubble, ensuring a minimum height. If the height should be as
* big as available, returns {@link #MAX_HEIGHT}.
*/
public float getExpandedViewHeight(BubbleViewProvider bubble) {
boolean isOverflow = bubble == null || BubbleOverflow.KEY.equals(bubble.getKey());
float desiredHeight = isOverflow
? mOverflowHeight
: ((Bubble) bubble).getDesiredHeight(mContext);
int manageButtonHeight = isOverflow ? 0 : mManageButtonHeight;
desiredHeight = Math.max(manageButtonHeight + desiredHeight, mExpandedViewMinHeight);
if (desiredHeight > getMaxExpandedViewHeight(isOverflow)) {
return MAX_HEIGHT;
}
return desiredHeight;
}
/**
* Gets the y position for the expanded view. This is the position on screen of the top
* horizontal line of the expanded view.
*
* @param bubble the bubble being positioned.
* @param bubblePosition the x position of the bubble if showing on top, the y position of the
* bubble if showing vertically.
* @return the y position for the expanded view.
*/
public float getExpandedViewY(BubbleViewProvider bubble, float bubblePosition) {
boolean isOverflow = bubble == null || BubbleOverflow.KEY.equals(bubble.getKey());
float expandedViewHeight = getExpandedViewHeight(bubble);
float topAlignment = getExpandedViewYTopAligned();
if (!showBubblesVertically() || expandedViewHeight == MAX_HEIGHT) {
// Top-align when bubbles are shown at the top or are max size.
return topAlignment;
}
// If we're here, we're showing vertically & developer has made height less than maximum.
int manageButtonHeight = isOverflow ? 0 : mManageButtonHeight;
float pointerPosition = getPointerPosition(bubblePosition);
float bottomIfCentered = pointerPosition + (expandedViewHeight / 2) + manageButtonHeight;
float topIfCentered = pointerPosition - (expandedViewHeight / 2);
if (topIfCentered > mPositionRect.top && mPositionRect.bottom > bottomIfCentered) {
// Center it
return pointerPosition - mPointerWidth - (expandedViewHeight / 2f);
} else if (topIfCentered <= mPositionRect.top) {
// Top align
return topAlignment;
} else {
// Bottom align
return mPositionRect.bottom - manageButtonHeight - expandedViewHeight - mPointerWidth;
}
}
/**
* The position the pointer points to, the center of the bubble.
*
* @param bubblePosition the x position of the bubble if showing on top, the y position of the
* bubble if showing vertically.
* @return the position the tip of the pointer points to. The x position if showing on top, the
* y position if showing vertically.
*/
public float getPointerPosition(float bubblePosition) {
// TODO: I don't understand why it works but it does - why normalized in portrait
// & not in landscape? Am I missing ~2dp in the portrait expandedViewY calculation?
final float normalizedSize = IconNormalizer.getNormalizedCircleSize(
getBubbleSize());
return showBubblesVertically()
? bubblePosition + (getBubbleSize() / 2f)
: bubblePosition + (normalizedSize / 2f) - mPointerWidth;
}
/**
* When bubbles are expanded in portrait, they display at the top of the screen in a horizontal
* row. When in landscape or on a large screen, they show at the left or right side in a
* vertical row. This method accounts for screen orientation and will return an x or y value
* for the position of the bubble in the row.
*
* @param index bubble index in the row.
* @param numberOfBubbles the number of bubbles (including the overflow) in the row.
* @return the y position of the bubble if showing vertically and the x position if showing
* horizontally.
*/
public float getBubbleXOrYForOrientation(int index, int numberOfBubbles) {
final float positionInBar = index * (mBubbleSize + mSpacingBetweenBubbles);
final float expandedStackSize = (numberOfBubbles * mBubbleSize)
+ ((numberOfBubbles - 1) * mSpacingBetweenBubbles);
final float centerPosition = showBubblesVertically()
? mPositionRect.centerY()
: mPositionRect.centerX();
final float rowStart = centerPosition - (expandedStackSize / 2f);
return rowStart + positionInBar;
}
/**
* Sets the stack's most recent position along the edge of the screen. This is saved when the
* last bubble is removed, so that the stack can be restored in its previous position.

View File

@@ -874,8 +874,10 @@ public class BubbleStackView extends FrameLayout
mExpandedAnimationController.expandFromStack(() -> {
afterExpandedViewAnimation();
} /* after */);
final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
getBubbleIndex(mExpandedBubble));
mExpandedViewContainer.setTranslationX(0f);
mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY());
mExpandedViewContainer.setTranslationY(translationY);
mExpandedViewContainer.setAlpha(1f);
}
removeOnLayoutChangeListener(mOrientationChangedListener);
@@ -1524,6 +1526,7 @@ public class BubbleStackView extends FrameLayout
bubble.cleanupViews();
}
updatePointerPosition();
updateExpandedView();
logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
return;
}
@@ -1815,9 +1818,10 @@ public class BubbleStackView extends FrameLayout
mTaskbarScrim.setVisibility(VISIBLE);
mTaskbarScrim.animate().alpha(1f).start();
}
final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
getBubbleIndex(mExpandedBubble));
mExpandedViewContainer.setTranslationX(0f);
mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY());
mExpandedViewContainer.setTranslationY(translationY);
mExpandedViewContainer.setAlpha(1f);
int index;
@@ -1866,7 +1870,7 @@ public class BubbleStackView extends FrameLayout
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
bubbleWillBeAt + mBubbleSize / 2f,
mPositioner.getExpandedViewY());
translationY);
}
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
@@ -1970,7 +1974,7 @@ public class BubbleStackView extends FrameLayout
mExpandedViewContainerMatrix.setScale(
1f, 1f,
expandingFromBubbleAt + mBubbleSize / 2f,
mPositioner.getExpandedViewY());
mPositioner.getExpandedViewY(mExpandedBubble, index));
}
mExpandedViewAlphaAnimator.reverse();
@@ -2077,7 +2081,7 @@ public class BubbleStackView extends FrameLayout
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
expandingFromBubbleDestination + mBubbleSize / 2f,
mPositioner.getExpandedViewY());
mPositioner.getExpandedViewY(mExpandedBubble, expandingFromBubbleDestination));
}
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
@@ -2698,7 +2702,9 @@ public class BubbleStackView extends FrameLayout
mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
}
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY());
mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY(mExpandedBubble,
mExpandedAnimationController.getBubbleXOrYForOrientation(
getBubbleIndex(mExpandedBubble))));
mExpandedViewContainer.setTranslationX(0f);
mExpandedBubble.getExpandedView().updateView(
mExpandedViewContainer.getLocationOnScreen());

View File

@@ -83,12 +83,6 @@ public class ExpandedAnimationController
private float mBubblePaddingTop;
/** Size of each bubble. */
private float mBubbleSizePx;
/** Max number of bubbles shown in row above expanded view. */
private int mBubblesMaxRendered;
/** Max amount of space to have between bubbles when expanded. */
private int mBubblesMaxSpace;
/** Amount of space between the bubbles when expanded. */
private float mSpaceBetweenBubbles;
/** Whether the expand / collapse animation is running. */
private boolean mAnimatingExpand = false;
@@ -211,8 +205,6 @@ public class ExpandedAnimationController
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
mBubbleSizePx = mPositioner.getBubbleSize();
mBubblesMaxRendered = mPositioner.getMaxBubbles();
mSpaceBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing);
}
/**
@@ -628,14 +620,13 @@ public class ExpandedAnimationController
}
}
// TODO - could move to method on bubblePositioner if mSpaceBetweenBubbles gets moved
/**
* When bubbles are expanded in portrait, they display at the top of the screen in a horizontal
* row. When in landscape or on a large screen, they show at the left or right side in a
* vertical row. This method accounts for screen orientation and will return an x or y value
* for the position of the bubble in the row.
*
* @param index Bubble index in row.
* @param index bubble index in the row.
* @return the y position of the bubble if showing vertically and the x position if showing
* horizontally.
*/
@@ -643,15 +634,6 @@ public class ExpandedAnimationController
if (mLayout == null) {
return 0;
}
final float positionInBar = index * (mBubbleSizePx + mSpaceBetweenBubbles);
Rect availableRect = mPositioner.getAvailableRect();
final boolean isLandscape = mPositioner.showBubblesVertically();
final float expandedStackSize = (mLayout.getChildCount() * mBubbleSizePx)
+ ((mLayout.getChildCount() - 1) * mSpaceBetweenBubbles);
final float centerPosition = isLandscape
? availableRect.centerY()
: availableRect.centerX();
final float rowStart = centerPosition - (expandedStackSize / 2f);
return rowStart + positionInBar;
return mPositioner.getBubbleXOrYForOrientation(index, mLayout.getChildCount());
}
}