Merge "Center bubbles horizontally on large screens" into sc-v2-dev

This commit is contained in:
Mady Mellor
2021-08-18 19:42:38 +00:00
committed by Android (Google) Code Review
6 changed files with 232 additions and 203 deletions

View File

@@ -696,8 +696,10 @@ public class BubbleExpandedView extends LinearLayout {
? mPointerHeight - mPointerOverlap
: 0;
final float paddingRight = (showVertically && !onLeft)
? mPointerHeight - mPointerOverlap : 0;
final float paddingTop = showVertically ? 0
? mPointerHeight - mPointerOverlap
: 0;
final float paddingTop = showVertically
? 0
: mPointerHeight - mPointerOverlap;
setPadding((int) paddingLeft, (int) paddingTop, (int) paddingRight, 0);

View File

@@ -79,14 +79,18 @@ public class BubblePositioner {
private int mBubbleSize;
private int mSpacingBetweenBubbles;
private float mExpandedViewLargeScreenWidth;
private int mExpandedViewMinHeight;
private int mExpandedViewLargeScreenWidth;
private int mExpandedViewLargeScreenInset;
private int mOverflowWidth;
private int mExpandedViewPadding;
private int mPointerMargin;
private int mPointerWidth;
private int mPointerHeight;
private int mPointerOverlap;
private int mManageButtonHeight;
private int mExpandedViewMinHeight;
private int mOverflowHeight;
private int mMinimumFlyoutWidthLargeScreen;
@@ -168,15 +172,20 @@ public class BubblePositioner {
mBubbleSize = res.getDimensionPixelSize(R.dimen.bubble_size);
mSpacingBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing);
mDefaultMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
mExpandedViewLargeScreenWidth = bounds.width() * EXPANDED_VIEW_LARGE_SCREEN_WIDTH_PERCENT;
mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
mExpandedViewLargeScreenWidth = (int) (bounds.width()
* EXPANDED_VIEW_LARGE_SCREEN_WIDTH_PERCENT);
mExpandedViewLargeScreenInset = mIsLargeScreen
? (bounds.width() - mExpandedViewLargeScreenWidth) / 2
: mExpandedViewPadding;
mOverflowWidth = mIsLargeScreen
? (int) mExpandedViewLargeScreenWidth
? mExpandedViewLargeScreenWidth
: res.getDimensionPixelSize(
R.dimen.bubble_expanded_view_phone_landscape_overflow_width);
mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
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_total_height);
mExpandedViewMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
@@ -294,66 +303,93 @@ public class BubblePositioner {
}
/**
* Calculates the left & right padding for the bubble expanded view.
* Calculates the padding for the bubble expanded view.
*
* On larger screens the width of the expanded view is restricted via this padding.
* On landscape the bubble overflow expanded view is also restricted via this padding.
* Some specifics:
* On large screens the width of the expanded view is restricted via this padding.
* On phone landscape the bubble overflow expanded view is also restricted via this padding.
* On large screens & landscape no top padding is set, the top position is set via translation.
* On phone portrait top padding is set as the space between the tip of the pointer and the
* bubble.
* When the overflow is shown it doesn't have the manage button to pad out the bottom so
* padding is added.
*/
public int[] getExpandedViewPadding(boolean onLeft, boolean isOverflow) {
int leftPadding = mInsets.left + mExpandedViewPadding;
int rightPadding = mInsets.right + mExpandedViewPadding;
final boolean isLargeOrOverflow = mIsLargeScreen || isOverflow;
final float expandedViewWidth = isOverflow
? mOverflowWidth
: mExpandedViewLargeScreenWidth;
if (showBubblesVertically()) {
if (!onLeft) {
rightPadding += mBubbleSize - mPointerHeight;
leftPadding += isLargeOrOverflow
? (mPositionRect.width() - rightPadding - expandedViewWidth)
: 0;
} else {
leftPadding += mBubbleSize - mPointerHeight;
rightPadding += isLargeOrOverflow
? (mPositionRect.width() - leftPadding - expandedViewWidth)
: 0;
public int[] getExpandedViewContainerPadding(boolean onLeft, boolean isOverflow) {
final int pointerTotalHeight = mPointerHeight - mPointerOverlap;
if (mIsLargeScreen) {
// [left, top, right, bottom]
mPaddings[0] = onLeft
? mExpandedViewLargeScreenInset - pointerTotalHeight
: mExpandedViewLargeScreenInset;
mPaddings[1] = 0;
mPaddings[2] = onLeft
? mExpandedViewLargeScreenInset
: mExpandedViewLargeScreenInset - pointerTotalHeight;
// Overflow doesn't show manage button / get padding from it so add padding here for it
mPaddings[3] = isOverflow ? mExpandedViewPadding : 0;
return mPaddings;
} else {
int leftPadding = mInsets.left + mExpandedViewPadding;
int rightPadding = mInsets.right + mExpandedViewPadding;
final float expandedViewWidth = isOverflow
? mOverflowWidth
: mExpandedViewLargeScreenWidth;
if (showBubblesVertically()) {
if (!onLeft) {
rightPadding += mBubbleSize - pointerTotalHeight;
leftPadding += isOverflow
? (mPositionRect.width() - rightPadding - expandedViewWidth)
: 0;
} else {
leftPadding += mBubbleSize - pointerTotalHeight;
rightPadding += isOverflow
? (mPositionRect.width() - leftPadding - expandedViewWidth)
: 0;
}
}
// [left, top, right, bottom]
mPaddings[0] = leftPadding;
mPaddings[1] = showBubblesVertically() ? 0 : mPointerMargin;
mPaddings[2] = rightPadding;
mPaddings[3] = 0;
return mPaddings;
}
// [left, top, right, bottom]
mPaddings[0] = leftPadding;
mPaddings[1] = showBubblesVertically() ? 0 : mPointerMargin;
mPaddings[2] = rightPadding;
mPaddings[3] = 0;
return mPaddings;
}
/** 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;
return top - mPointerWidth + mExpandedViewPadding;
} else {
return top + mBubbleSize + mPointerMargin;
}
}
/** The maximum height the expanded view can be. */
public float getExpandedBubblesY() {
return getAvailableRect().top + mExpandedViewPadding;
}
/**
* Calculate the maximum height the expanded view can be depending on where it's placed on
* the screen and the size of the elements around it (e.g. padding, pointer, manage button).
*/
public int getMaxExpandedViewHeight(boolean isOverflow) {
// Subtract top insets because availableRect.height would account for that
int expandedContainerY = (int) getExpandedViewYTopAligned() - getInsets().top;
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;
int bottomPadding = isOverflow ? mExpandedViewPadding : mManageButtonHeight;
return getAvailableRect().height()
- expandedContainerY
- paddingTop
- settingsHeight
- pointerSize;
- pointerSize
- bottomPadding;
}
/**
@@ -362,11 +398,14 @@ public class BubblePositioner {
*/
public float getExpandedViewHeight(BubbleViewProvider bubble) {
boolean isOverflow = bubble == null || BubbleOverflow.KEY.equals(bubble.getKey());
if (isOverflow && showBubblesVertically() && !mIsLargeScreen) {
// overflow in landscape on phone is max
return MAX_HEIGHT;
}
float desiredHeight = isOverflow
? mOverflowHeight
: ((Bubble) bubble).getDesiredHeight(mContext);
int manageButtonHeight = isOverflow ? 0 : mManageButtonHeight;
desiredHeight = Math.max(manageButtonHeight + desiredHeight, mExpandedViewMinHeight);
desiredHeight = Math.max(desiredHeight, mExpandedViewMinHeight);
if (desiredHeight > getMaxExpandedViewHeight(isOverflow)) {
return MAX_HEIGHT;
}
@@ -391,7 +430,7 @@ public class BubblePositioner {
return topAlignment;
}
// If we're here, we're showing vertically & developer has made height less than maximum.
int manageButtonHeight = isOverflow ? 0 : mManageButtonHeight;
int manageButtonHeight = isOverflow ? mExpandedViewPadding : mManageButtonHeight;
float pointerPosition = getPointerPosition(bubblePosition);
float bottomIfCentered = pointerPosition + (expandedViewHeight / 2) + manageButtonHeight;
float topIfCentered = pointerPosition - (expandedViewHeight / 2);
@@ -426,25 +465,40 @@ public class BubblePositioner {
}
/**
* 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.
* Returns the position of the bubble on-screen when the stack is expanded.
*
* @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.
* @param index the index of the bubble in the stack.
* @param numberOfBubbles the total number of bubbles in the stack.
* @param onLeftEdge whether the stack would rest on the left edge of the screen when collapsed.
* @return the x, y position of the bubble on-screen when the stack is expanded.
*/
public float getBubbleXOrYForOrientation(int index, int numberOfBubbles) {
final float positionInBar = index * (mBubbleSize + mSpacingBetweenBubbles);
public PointF getExpandedBubbleXY(int index, int numberOfBubbles, boolean onLeftEdge) {
final float positionInRow = index * (mBubbleSize + mSpacingBetweenBubbles);
final float expandedStackSize = (numberOfBubbles * mBubbleSize)
+ ((numberOfBubbles - 1) * mSpacingBetweenBubbles);
final float centerPosition = showBubblesVertically()
? mPositionRect.centerY()
: mPositionRect.centerX();
// alignment - centered on the edge
final float rowStart = centerPosition - (expandedStackSize / 2f);
return rowStart + positionInBar;
float x;
float y;
if (showBubblesVertically()) {
y = rowStart + positionInRow;
int left = mIsLargeScreen
? mExpandedViewLargeScreenInset - mExpandedViewPadding - mBubbleSize
: mPositionRect.left;
int right = mIsLargeScreen
? mPositionRect.right - mExpandedViewLargeScreenInset + mExpandedViewPadding
: mPositionRect.right - mBubbleSize;
x = onLeftEdge
? left
: right;
} else {
y = mPositionRect.top + mExpandedViewPadding;
x = rowStart + positionInRow;
}
return new PointF(x, y);
}
/**
@@ -458,6 +512,17 @@ public class BubblePositioner {
return mScreenRect.width() * FLYOUT_MAX_WIDTH_PERCENT;
}
/**
* @return whether the stack is considered on the left side of the screen.
*/
public boolean isStackOnLeft(PointF currentStackPosition) {
if (currentStackPosition == null) {
currentStackPosition = getRestingPosition();
}
final int stackCenter = (int) currentStackPosition.x + mBubbleSize / 2;
return stackCenter < mScreenRect.width() / 2;
}
/**
* 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

@@ -778,8 +778,8 @@ public class BubbleStackView extends FrameLayout
floatingContentCoordinator, this::getBubbleCount, onBubbleAnimatedOut,
this::animateShadows /* onStackAnimationFinished */, mPositioner);
mExpandedAnimationController = new ExpandedAnimationController(
mPositioner, mExpandedViewPadding, onBubbleAnimatedOut);
mExpandedAnimationController = new ExpandedAnimationController(mPositioner,
onBubbleAnimatedOut);
mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER;
// Force LTR by default since most of the Bubbles UI is positioned manually by the user, or
@@ -1869,28 +1869,28 @@ public class BubbleStackView extends FrameLayout
maybeShowManageEdu();
}
} /* after */);
final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
getBubbleIndex(mExpandedBubble));
mExpandedViewContainer.setTranslationX(0f);
mExpandedViewContainer.setTranslationY(translationY);
mExpandedViewContainer.setAlpha(1f);
int index;
if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) {
index = mBubbleData.getBubbles().size();
} else {
index = getBubbleIndex(mExpandedBubble);
}
// Position of the bubble we're expanding, once it's settled in its row.
final float bubbleWillBeAt =
mExpandedAnimationController.getBubbleXOrYForOrientation(index);
PointF p = mPositioner.getExpandedBubbleXY(index, mBubbleContainer.getChildCount(),
mStackOnLeftOrWillBe);
final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
mPositioner.showBubblesVertically() ? p.y : p.x);
mExpandedViewContainer.setTranslationX(0f);
mExpandedViewContainer.setTranslationY(translationY);
mExpandedViewContainer.setAlpha(1f);
// How far horizontally the bubble will be animating. We'll wait a bit longer for bubbles
// that are animating farther, so that the expanded view doesn't move as much.
final float relevantStackPosition = showVertically
? mStackAnimationController.getStackPosition().y
: mStackAnimationController.getStackPosition().x;
final float bubbleWillBeAt = showVertically
? p.y
: p.x;
final float distanceAnimated = Math.abs(bubbleWillBeAt - relevantStackPosition);
// Wait for the path animation target to reach its end, and add a small amount of extra time
@@ -1907,22 +1907,22 @@ public class BubbleStackView extends FrameLayout
// Set the pivot point for the scale, so the expanded view animates out from the bubble.
if (showVertically) {
float pivotX;
float pivotY = bubbleWillBeAt + mBubbleSize / 2f;
if (mStackOnLeftOrWillBe) {
pivotX = mPositioner.getAvailableRect().left + mBubbleSize + mExpandedViewPadding;
pivotX = p.x + mBubbleSize + mExpandedViewPadding;
} else {
pivotX = mPositioner.getAvailableRect().right - mBubbleSize - mExpandedViewPadding;
pivotX = p.x - mExpandedViewPadding;
}
mExpandedViewContainerMatrix.setScale(
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
pivotX, pivotY);
pivotX,
p.y + mBubbleSize / 2f);
} else {
mExpandedViewContainerMatrix.setScale(
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
bubbleWillBeAt + mBubbleSize / 2f,
translationY);
p.x + mBubbleSize / 2f,
p.y + mBubbleSize + mExpandedViewPadding);
}
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
@@ -1959,6 +1959,7 @@ public class BubbleStackView extends FrameLayout
mExpandedViewContainerMatrix);
})
.withEndActions(() -> {
mExpandedViewContainer.setAnimationMatrix(null);
afterExpandedViewAnimation();
if (mExpandedBubble != null
&& mExpandedBubble.getExpandedView() != null) {
@@ -2009,12 +2010,11 @@ public class BubbleStackView extends FrameLayout
index = mBubbleData.getBubbles().indexOf(mExpandedBubble);
}
// Value the bubble is animating from (back into the stack).
final float expandingFromBubbleAt =
mExpandedAnimationController.getBubbleXOrYForOrientation(index);
final boolean showVertically = mPositioner.showBubblesVertically();
final PointF p = mPositioner.getExpandedBubbleXY(index,
mBubbleContainer.getChildCount(), mStackOnLeftOrWillBe);
if (mPositioner.showBubblesVertically()) {
float pivotX;
float pivotY = expandingFromBubbleAt + mBubbleSize / 2f;
float pivotY = p.y + mBubbleSize / 2f;
if (mStackOnLeftOrWillBe) {
pivotX = mPositioner.getAvailableRect().left + mBubbleSize + mExpandedViewPadding;
} else {
@@ -2026,8 +2026,8 @@ public class BubbleStackView extends FrameLayout
} else {
mExpandedViewContainerMatrix.setScale(
1f, 1f,
expandingFromBubbleAt + mBubbleSize / 2f,
mPositioner.getExpandedViewY(mExpandedBubble, index));
p.x + mBubbleSize / 2f,
p.y + mBubbleSize + mExpandedViewPadding);
}
mExpandedViewAlphaAnimator.reverse();
@@ -2105,32 +2105,31 @@ public class BubbleStackView extends FrameLayout
boolean isOverflow = mExpandedBubble != null
&& mExpandedBubble.getKey().equals(BubbleOverflow.KEY);
float expandingFromBubbleDestination =
mExpandedAnimationController.getBubbleXOrYForOrientation(isOverflow
? getBubbleCount()
: mBubbleData.getBubbles().indexOf(mExpandedBubble));
PointF p = mPositioner.getExpandedBubbleXY(isOverflow
? mBubbleContainer.getChildCount() - 1
: mBubbleData.getBubbles().indexOf(mExpandedBubble),
mBubbleContainer.getChildCount(), mStackOnLeftOrWillBe);
mExpandedViewContainer.setAlpha(1f);
mExpandedViewContainer.setVisibility(View.VISIBLE);
if (mPositioner.showBubblesVertically()) {
float pivotX;
float pivotY = expandingFromBubbleDestination + mBubbleSize / 2f;
float pivotY = p.y + mBubbleSize / 2f;
if (mStackOnLeftOrWillBe) {
pivotX = mPositioner.getAvailableRect().left + mBubbleSize + mExpandedViewPadding;
pivotX = p.x + mBubbleSize + mExpandedViewPadding;
} else {
pivotX = mPositioner.getAvailableRect().right - mBubbleSize - mExpandedViewPadding;
pivotX = p.x - mExpandedViewPadding;
}
mExpandedViewContainerMatrix.setScale(
0f, 0f,
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
pivotX, pivotY);
} else {
mExpandedViewContainerMatrix.setScale(
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
expandingFromBubbleDestination + mBubbleSize / 2f,
mPositioner.getExpandedViewY(mExpandedBubble, expandingFromBubbleDestination));
p.x + mBubbleSize / 2f,
p.y + mBubbleSize + mExpandedViewPadding);
}
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
@@ -2155,6 +2154,7 @@ public class BubbleStackView extends FrameLayout
.withEndActions(() -> {
mExpandedViewTemporarilyHidden = false;
mIsBubbleSwitchAnimating = false;
mExpandedViewContainer.setAnimationMatrix(null);
})
.start();
}, 25);
@@ -2764,16 +2764,17 @@ public class BubbleStackView extends FrameLayout
}
boolean isOverflowExpanded = mExpandedBubble != null
&& BubbleOverflow.KEY.equals(mExpandedBubble.getKey());
int[] paddings = mPositioner.getExpandedViewPadding(
int[] paddings = mPositioner.getExpandedViewContainerPadding(
mStackAnimationController.isStackOnLeftSide(), isOverflowExpanded);
mExpandedViewContainer.setPadding(paddings[0], paddings[1], paddings[2], paddings[3]);
if (mIsExpansionAnimating) {
mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
}
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
PointF p = mPositioner.getExpandedBubbleXY(getBubbleIndex(mExpandedBubble),
mBubbleContainer.getChildCount(), mStackOnLeftOrWillBe);
mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY(mExpandedBubble,
mExpandedAnimationController.getBubbleXOrYForOrientation(
getBubbleIndex(mExpandedBubble))));
mPositioner.showBubblesVertically() ? p.y : p.x));
mExpandedViewContainer.setTranslationX(0f);
mExpandedBubble.getExpandedView().updateView(
mExpandedViewContainer.getLocationOnScreen());
@@ -2856,8 +2857,13 @@ public class BubbleStackView extends FrameLayout
if (index == -1) {
return;
}
float bubblePosition = mExpandedAnimationController.getBubbleXOrYForOrientation(index);
mExpandedBubble.getExpandedView().setPointerPosition(bubblePosition, mStackOnLeftOrWillBe);
PointF bubblePosition = mPositioner.getExpandedBubbleXY(index,
mBubbleContainer.getChildCount(),
mStackOnLeftOrWillBe);
mExpandedBubble.getExpandedView().setPointerPosition(mPositioner.showBubblesVertically()
? bubblePosition.y
: bubblePosition.x,
mStackOnLeftOrWillBe);
}
/**

View File

@@ -76,8 +76,6 @@ public class ExpandedAnimationController
/** Horizontal offset between bubbles, which we need to know to re-stack them. */
private float mStackOffsetPx;
/** Space between status bar and bubbles in the expanded state. */
private float mBubblePaddingTop;
/** Size of each bubble. */
private float mBubbleSizePx;
/** Whether the expand / collapse animation is running. */
@@ -118,8 +116,6 @@ public class ExpandedAnimationController
/** The bubble currently being dragged out of the row (to potentially be dismissed). */
private MagnetizedObject<View> mMagnetizedBubbleDraggingOut;
private int mExpandedViewPadding;
/**
* Callback to run whenever any bubble is animated out. The BubbleStackView will check if the
* end of this animation means we have no bubbles left, and notify the BubbleController.
@@ -128,11 +124,10 @@ public class ExpandedAnimationController
private BubblePositioner mPositioner;
public ExpandedAnimationController(BubblePositioner positioner, int expandedViewPadding,
public ExpandedAnimationController(BubblePositioner positioner,
Runnable onBubbleAnimatedOutAction) {
mPositioner = positioner;
updateResources();
mExpandedViewPadding = expandedViewPadding;
mOnBubbleAnimatedOutAction = onBubbleAnimatedOutAction;
mCollapsePoint = mPositioner.getDefaultStartPosition();
}
@@ -199,7 +194,6 @@ public class ExpandedAnimationController
return;
}
Resources res = mLayout.getContext().getResources();
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
mBubbleSizePx = mPositioner.getBubbleSize();
}
@@ -245,31 +239,22 @@ public class ExpandedAnimationController
final Path path = new Path();
path.moveTo(bubble.getTranslationX(), bubble.getTranslationY());
final float expandedY = mPositioner.showBubblesVertically()
? getBubbleXOrYForOrientation(index)
: getExpandedY();
boolean onLeft = mPositioner.isStackOnLeft(mCollapsePoint);
final PointF p = mPositioner.getExpandedBubbleXY(index,
mLayout.getChildCount(),
onLeft);
if (expanding) {
// If we're expanding, first draw a line from the bubble's current position to the
// top of the screen.
path.lineTo(bubble.getTranslationX(), expandedY);
// If we're expanding, first draw a line from the bubble's current position to where
// it'll end up
path.lineTo(bubble.getTranslationX(), p.y);
// Then, draw a line across the screen to the bubble's resting position.
if (mPositioner.showBubblesVertically()) {
Rect availableRect = mPositioner.getAvailableRect();
boolean onLeft = mCollapsePoint != null
&& mCollapsePoint.x < (availableRect.width() / 2f);
float translationX = onLeft
? availableRect.left
: availableRect.right - mBubbleSizePx;
path.lineTo(translationX, getBubbleXOrYForOrientation(index));
} else {
path.lineTo(getBubbleXOrYForOrientation(index), expandedY);
}
path.lineTo(p.x, p.y);
} else {
final float stackedX = mCollapsePoint.x;
// If we're collapsing, draw a line from the bubble's current position to the side
// of the screen where the bubble will be stacked.
path.lineTo(stackedX, expandedY);
path.lineTo(stackedX, p.y);
// Then, draw a line down to the stack position.
path.lineTo(stackedX, mCollapsePoint.y
@@ -379,8 +364,9 @@ public class ExpandedAnimationController
bubbleView.setTranslationY(y);
}
final float expandedY = mPositioner.getExpandedBubblesY();
final boolean draggedOutEnough =
y > getExpandedY() + mBubbleSizePx || y < getExpandedY() - mBubbleSizePx;
y > expandedY + mBubbleSizePx || y < expandedY - mBubbleSizePx;
if (draggedOutEnough != mBubbleDraggedOutEnough) {
updateBubblePositions();
mBubbleDraggedOutEnough = draggedOutEnough;
@@ -424,9 +410,10 @@ public class ExpandedAnimationController
return;
}
final int index = mLayout.indexOfChild(bubbleView);
final PointF p = mPositioner.getExpandedBubbleXY(index, mLayout.getChildCount(),
mPositioner.isStackOnLeft(mCollapsePoint));
animationForChildAtIndex(index)
.position(getBubbleXOrYForOrientation(index), getExpandedY())
.position(p.x, p.y)
.withPositionStartVelocities(velX, velY)
.start(() -> bubbleView.setTranslationZ(0f) /* after */);
@@ -443,17 +430,13 @@ public class ExpandedAnimationController
}
/**
* Animates the bubbles to {@link #getExpandedY()} position. Used in response to IME showing.
* Animates the bubbles to the y position. Used in response to IME showing.
*/
public void updateYPosition(Runnable after) {
if (mLayout == null) return;
animationsForChildrenFromIndex(
0, (i, anim) -> anim.translationY(getExpandedY())).startAll(after);
}
/** The Y value of the row of expanded bubbles. */
public float getExpandedY() {
return mPositioner.getAvailableRect().top + mBubblePaddingTop;
0, (i, anim) -> anim.translationY(mPositioner.getExpandedBubblesY()))
.startAll(after);
}
/** Description of current animation controller state. */
@@ -511,35 +494,36 @@ public class ExpandedAnimationController
startOrUpdatePathAnimation(true /* expanding */);
} else if (mAnimatingCollapse) {
startOrUpdatePathAnimation(false /* expanding */);
} else if (mPositioner.showBubblesVertically()) {
child.setTranslationY(getBubbleXOrYForOrientation(index));
if (!mPreparingToCollapse) {
// Only animate if we're not collapsing as that animation will handle placing the
// new bubble in the stacked position.
Rect availableRect = mPositioner.getAvailableRect();
boolean onLeft = mCollapsePoint != null
&& mCollapsePoint.x < (availableRect.width() / 2f);
float fromX = onLeft
? -mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR
: availableRect.right + mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR;
float toX = onLeft
? availableRect.left + mExpandedViewPadding
: availableRect.right - mBubbleSizePx - mExpandedViewPadding;
animationForChild(child)
.translationX(fromX, toX)
.start();
updateBubblePositions();
}
} else {
child.setTranslationX(getBubbleXOrYForOrientation(index));
boolean onLeft = mPositioner.isStackOnLeft(mCollapsePoint);
final PointF p = mPositioner.getExpandedBubbleXY(index,
mLayout.getChildCount(),
onLeft);
if (mPositioner.showBubblesVertically()) {
child.setTranslationY(p.y);
} else {
child.setTranslationX(p.x);
}
if (!mPreparingToCollapse) {
// Only animate if we're not collapsing as that animation will handle placing the
// new bubble in the stacked position.
float toY = getExpandedY();
float fromY = getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR;
animationForChild(child)
.translationY(fromY, toY)
.start();
if (mPositioner.showBubblesVertically()) {
Rect availableRect = mPositioner.getAvailableRect();
float fromX = onLeft
? -mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR
: availableRect.right + mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR;
animationForChild(child)
.translationX(fromX, p.y)
.start();
} else {
// Only animate if we're not collapsing as that animation will handle placing
// the new bubble in the stacked position.
float fromY = mPositioner.getExpandedBubblesY() - mBubbleSizePx
* ANIMATE_TRANSLATION_FACTOR;
animationForChild(child)
.translationY(fromY, p.y)
.start();
}
updateBubblePositions();
}
}
@@ -588,7 +572,7 @@ public class ExpandedAnimationController
if (mAnimatingExpand || mAnimatingCollapse) {
return;
}
boolean onLeft = mPositioner.isStackOnLeft(mCollapsePoint);
for (int i = 0; i < mLayout.getChildCount(); i++) {
final View bubble = mLayout.getChildAt(i);
@@ -598,39 +582,11 @@ public class ExpandedAnimationController
return;
}
if (mPositioner.showBubblesVertically()) {
Rect availableRect = mPositioner.getAvailableRect();
boolean onLeft = mCollapsePoint != null
&& mCollapsePoint.x < (availableRect.width() / 2f);
animationForChild(bubble)
.translationX(onLeft
? availableRect.left
: availableRect.right - mBubbleSizePx)
.translationY(getBubbleXOrYForOrientation(i))
.start();
} else {
animationForChild(bubble)
.translationX(getBubbleXOrYForOrientation(i))
.translationY(getExpandedY())
.start();
}
final PointF p = mPositioner.getExpandedBubbleXY(i, mLayout.getChildCount(), onLeft);
animationForChild(bubble)
.translationX(p.x)
.translationY(p.y)
.start();
}
}
/**
* 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.
* @return the y position of the bubble if showing vertically and the x position if showing
* horizontally.
*/
public float getBubbleXOrYForOrientation(int index) {
if (mLayout == null) {
return 0;
}
return mPositioner.getBubbleXOrYForOrientation(index, mLayout.getChildCount());
}
}

View File

@@ -305,10 +305,7 @@ public class StackAnimationController extends
if (mLayout == null || !isStackPositionSet()) {
return true; // Default to left, which is where it starts by default.
}
float stackCenter = mStackPosition.x + mBubbleSize / 2;
float screenCenter = mLayout.getWidth() / 2;
return stackCenter < screenCenter;
return mPositioner.isStackOnLeft(mStackPosition);
}
/**

View File

@@ -19,6 +19,7 @@ package com.android.wm.shell.bubbles.animation;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import android.annotation.SuppressLint;
import android.content.res.Configuration;
@@ -41,7 +42,6 @@ import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Spy;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -49,26 +49,26 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
private int mDisplayWidth = 500;
private int mDisplayHeight = 1000;
private int mExpandedViewPadding = 10;
private Runnable mOnBubbleAnimatedOutAction = mock(Runnable.class);
@Spy
ExpandedAnimationController mExpandedController;
private int mStackOffset;
private PointF mExpansionPoint;
private BubblePositioner mPositioner;
@SuppressLint("VisibleForTests")
@Before
public void setUp() throws Exception {
super.setUp();
BubblePositioner positioner = new BubblePositioner(getContext(), mock(WindowManager.class));
positioner.updateInternal(Configuration.ORIENTATION_PORTRAIT,
mPositioner = new BubblePositioner(getContext(), mock(WindowManager.class));
mPositioner.updateInternal(Configuration.ORIENTATION_PORTRAIT,
Insets.of(0, 0, 0, 0),
new Rect(0, 0, mDisplayWidth, mDisplayHeight));
mExpandedController = new ExpandedAnimationController(positioner, mExpandedViewPadding,
mExpandedController = new ExpandedAnimationController(mPositioner,
mOnBubbleAnimatedOutAction);
spyOn(mExpandedController);
addOneMoreThanBubbleLimitBubbles();
mLayout.setActiveController(mExpandedController);
@@ -141,13 +141,16 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
/** Check that children are in the correct positions for being expanded. */
private void testBubblesInCorrectExpandedPositions() {
boolean onLeft = mPositioner.isStackOnLeft(mExpansionPoint);
// Check all the visible bubbles to see if they're in the right place.
for (int i = 0; i < mLayout.getChildCount(); i++) {
float expectedPosition = mExpandedController.getBubbleXOrYForOrientation(i);
assertEquals(expectedPosition,
PointF expectedPosition = mPositioner.getExpandedBubbleXY(i,
mLayout.getChildCount(),
onLeft);
assertEquals(expectedPosition.x,
mLayout.getChildAt(i).getTranslationX(),
2f);
assertEquals(expectedPosition,
assertEquals(expectedPosition.y,
mLayout.getChildAt(i).getTranslationY(), 2f);
}
}