Merge "Center bubbles horizontally on large screens" into sc-v2-dev
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user