Animate overflow button

Add overflow button to mBubbleContainer
Update animation math to account for 6th child

Bug: 138116789
Fixes: 148233216
Test: manual: expand stack - button animates like normal bubbles
Test: manual: collapse stack - button animates like normal bubbles
Test: atest SystemUITests
Change-Id: I8bd575a116ab4a7443c2d682debc5c5207df1808
This commit is contained in:
Lyn Han
2020-01-28 21:43:34 -08:00
parent 0a20294de1
commit c47e171262
3 changed files with 48 additions and 88 deletions

View File

@@ -866,10 +866,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mOverflowCallback.run();
}
if (update.addedBubble != null) {
mStackView.addBubble(update.addedBubble);
}
// Collapsing? Do this first before remaining steps.
if (update.expandedChanged && !update.expanded) {
mStackView.setExpanded(false);
@@ -916,6 +912,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
}
if (update.addedBubble != null) {
mStackView.addBubble(update.addedBubble);
}
if (update.updatedBubble != null) {
mStackView.updateBubble(update.updatedBubble);
}

View File

@@ -526,8 +526,13 @@ public class BubbleStackView extends FrameLayout {
R.layout.bubble_expanded_view, this /* root */, false /* attachToRoot */);
mOverflowExpandedView.setOverflow(true);
mInflater.inflate(R.layout.bubble_overflow_button, this);
mOverflowBtn = findViewById(R.id.bubble_overflow_button);
mOverflowBtn = (ImageView) mInflater.inflate(R.layout.bubble_overflow_button,
this /* root */,
false /* attachToRoot */);
mBubbleContainer.addView(mOverflowBtn, 0,
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
mOverflowBtn.setOnClickListener(v -> {
setSelectedBubble(null);
});
@@ -541,11 +546,13 @@ public class BubbleStackView extends FrameLayout {
ColorDrawable bg = new ColorDrawable(bgColor);
AdaptiveIconDrawable adaptiveIcon = new AdaptiveIconDrawable(bg, fg);
mOverflowBtn.setImageDrawable(adaptiveIcon);
mOverflowBtn.setVisibility(GONE);
}
void showExpandedViewContents(int displayId) {
if (mOverflowExpandedView.getVirtualDisplayId() == displayId) {
if (mOverflowExpandedView != null
&& mOverflowExpandedView.getVirtualDisplayId() == displayId) {
mOverflowExpandedView.setContentVisibility(true);
} else if (mExpandedBubble != null
&& mExpandedBubble.getExpandedView().getVirtualDisplayId() == displayId) {
@@ -714,7 +721,7 @@ public class BubbleStackView extends FrameLayout {
private void updateSystemGestureExcludeRects() {
// Exclude the region occupied by the first BubbleView in the stack
Rect excludeZone = mSystemGestureExclusionRects.get(0);
if (mBubbleContainer.getChildCount() > 0) {
if (getBubbleCount() > 0) {
View firstBubble = mBubbleContainer.getChildAt(0);
excludeZone.set(firstBubble.getLeft(), firstBubble.getTop(), firstBubble.getRight(),
firstBubble.getBottom());
@@ -775,7 +782,7 @@ public class BubbleStackView extends FrameLayout {
Log.d(TAG, "addBubble: " + bubble);
}
if (mBubbleContainer.getChildCount() == 0) {
if (getBubbleCount() == 0) {
mStackOnLeftOrWillBe = mStackAnimationController.isStackOnLeftSide();
}
@@ -817,16 +824,13 @@ public class BubbleStackView extends FrameLayout {
}
if (mIsExpanded) {
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "Expanded && overflow > 0. Show overflow button at");
Log.d(TAG, "x: " + mExpandedAnimationController.getOverflowBtnLeft());
Log.d(TAG, "y: " + mExpandedAnimationController.getExpandedY());
Log.d(TAG, "Show overflow button.");
}
mOverflowBtn.setX(mExpandedAnimationController.getOverflowBtnLeft());
mOverflowBtn.setY(mExpandedAnimationController.getExpandedY());
mOverflowBtn.setVisibility(VISIBLE);
mExpandedAnimationController.setShowOverflowBtn(true);
if (apply) {
mExpandedAnimationController.expandFromStack(null /* after */);
mExpandedAnimationController.expandFromStack(() -> {
updatePointerPosition();
} /* after */);
}
} else {
if (DEBUG_BUBBLE_STACK_VIEW) {
@@ -947,7 +951,7 @@ public class BubbleStackView extends FrameLayout {
if (mIsExpanded) {
if (isIntersecting(mBubbleContainer, x, y)) {
// Could be tapping or dragging a bubble while expanded
for (int i = 0; i < mBubbleContainer.getChildCount(); i++) {
for (int i = 0; i < getBubbleCount(); i++) {
BadgedImageView view = (BadgedImageView) mBubbleContainer.getChildAt(i);
if (isIntersecting(view, x, y)) {
return view;
@@ -1103,7 +1107,7 @@ public class BubbleStackView extends FrameLayout {
/** Return the BubbleView at the given index from the bubble container. */
public BadgedImageView getBubbleAt(int i) {
return mBubbleContainer.getChildCount() > i
return getBubbleCount() > i
? (BadgedImageView) mBubbleContainer.getChildAt(i)
: null;
}
@@ -1567,7 +1571,7 @@ public class BubbleStackView extends FrameLayout {
return;
}
if (!mIsExpanded) {
if (mBubbleContainer.getChildCount() > 0) {
if (getBubbleCount() > 0) {
mBubbleContainer.getChildAt(0).getBoundsOnScreen(outRect);
}
// Increase the touch target size of the bubble
@@ -1661,7 +1665,7 @@ public class BubbleStackView extends FrameLayout {
/** Sets the appropriate Z-order and dot position for each bubble in the stack. */
private void updateBubbleZOrdersAndDotPosition(boolean animate) {
int bubbleCount = mBubbleContainer.getChildCount();
int bubbleCount = getBubbleCount();
for (int i = 0; i < bubbleCount; i++) {
BadgedImageView bv = (BadgedImageView) mBubbleContainer.getChildAt(i);
bv.setZ((mMaxBubbles * mBubbleElevation) - i);
@@ -1677,30 +1681,23 @@ public class BubbleStackView extends FrameLayout {
if (expandedBubble == null) {
return;
}
int index = getBubbleIndex(expandedBubble);
if (index >= mMaxBubbles) {
// In between state, where extra bubble will be overflowed, and new bubble added
index = 0;
}
float bubbleLeftFromScreenLeft = mExpandedAnimationController.getBubbleLeft(index);
float halfBubble = mBubbleSize / 2f;
float bubbleCenter = bubbleLeftFromScreenLeft + halfBubble;
// Padding might be adjusted for insets, so get it directly from the view
bubbleCenter -= mExpandedViewContainer.getPaddingLeft();
if (index >= mMaxBubbles) {
Bubble first = mBubbleData.getBubbles().get(0);
first.getExpandedView().setPointerPosition(bubbleCenter);
} else {
expandedBubble.getExpandedView().setPointerPosition(bubbleCenter);
}
expandedBubble.getExpandedView().setPointerPosition(bubbleCenter);
}
/**
* @return the number of bubbles in the stack view.
*/
public int getBubbleCount() {
if (BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
// Subtract 1 for the overflow button which is always in the bubble container.
return mBubbleContainer.getChildCount() - 1;
}
return mBubbleContainer.getChildCount();
}
@@ -1797,7 +1794,7 @@ public class BubbleStackView extends FrameLayout {
/** For debugging only */
List<Bubble> getBubblesOnScreen() {
List<Bubble> bubbles = new ArrayList<>();
for (int i = 0; i < mBubbleContainer.getChildCount(); i++) {
for (int i = 0; i < getBubbleCount(); i++) {
View child = mBubbleContainer.getChildAt(i);
if (child instanceof BadgedImageView) {
String key = ((BadgedImageView) child).getKey();

View File

@@ -31,6 +31,7 @@ import androidx.dynamicanimation.animation.SpringForce;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleExperimentConfig;
import com.google.android.collect.Sets;
@@ -67,13 +68,13 @@ public class ExpandedAnimationController
private float mBubblePaddingTop;
/** Size of each bubble. */
private float mBubbleSizePx;
/** Width of the overflow button. */
private float mOverflowBtnWidth;
/** Space between bubbles in row above expanded view. */
private float mSpaceBetweenBubbles;
/** Height of the status bar. */
private float mStatusBarHeight;
/** Size of display. */
private Point mDisplaySize;
/** Max number of bubbles shown in row above expanded view.*/
/** Max number of bubbles shown in row above expanded view. */
private int mBubblesMaxRendered;
/** What the current screen orientation is. */
private int mScreenOrientation;
@@ -99,7 +100,6 @@ public class ExpandedAnimationController
private boolean mSpringingBubbleToTouch = false;
private int mExpandedViewPadding;
private boolean mShowOverflowBtn;
public ExpandedAnimationController(Point displaySize, int expandedViewPadding,
int orientation) {
@@ -153,14 +153,6 @@ public class ExpandedAnimationController
}
}
public void setShowOverflowBtn(boolean showBtn) {
mShowOverflowBtn = showBtn;
}
public boolean getShowOverflowBtn() {
return mShowOverflowBtn;
}
/**
* Animates the bubbles along a curved path, either to expand them along the top or collapse
* them back into a stack.
@@ -369,10 +361,10 @@ public class ExpandedAnimationController
}
final WindowInsets insets = mLayout.getRootWindowInsets();
return mBubblePaddingTop + Math.max(
mStatusBarHeight,
insets.getDisplayCutout() != null
? insets.getDisplayCutout().getSafeInsetTop()
: 0);
mStatusBarHeight,
insets.getDisplayCutout() != null
? insets.getDisplayCutout().getSafeInsetTop()
: 0);
}
/** Description of current animation controller state. */
@@ -391,11 +383,15 @@ public class ExpandedAnimationController
mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
mBubbleSizePx = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
mOverflowBtnWidth = mBubbleSizePx;
mStatusBarHeight =
res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
mBubblesMaxRendered = res.getInteger(R.integer.bubbles_max_rendered);
// Includes overflow button.
float totalGapWidth = getWidthForDisplayingBubbles() - (mExpandedViewPadding * 2)
- (mBubblesMaxRendered + 1) * mBubbleSizePx;
mSpaceBetweenBubbles = totalGapWidth / mBubblesMaxRendered;
// Ensure that all child views are at 1x scale, and visible, in case they were animating
// in.
mLayout.setVisibility(View.VISIBLE);
@@ -506,18 +502,10 @@ public class ExpandedAnimationController
* @return Bubble left x from left edge of screen.
*/
public float getBubbleLeft(int index) {
final float bubbleFromRowLeft = index * (mBubbleSizePx + getSpaceBetweenBubbles());
final float bubbleFromRowLeft = index * (mBubbleSizePx + mSpaceBetweenBubbles);
return getRowLeft() + bubbleFromRowLeft;
}
public float getOverflowBtnLeft() {
if (mLayout == null || mLayout.getChildCount() == 0) {
return 0;
}
return getBubbleLeft(mLayout.getChildCount() - 1) + mBubbleSizePx
+ getSpaceBetweenBubbles();
}
/**
* When expanded, the bubbles are centered in the screen. In portrait, all available space is
* used. In landscape we have too much space so the value is restricted. This method accounts
@@ -539,7 +527,7 @@ public class ExpandedAnimationController
* Determines the available screen width without the cutout.
*
* @param subtractStableInsets Whether or not stable insets should also be removed from the
* returned width.
* returned width.
* @return the total screen width available accounting for cutouts and insets,
* iff {@param includeStableInsets} is true.
*/
@@ -566,38 +554,13 @@ public class ExpandedAnimationController
if (mLayout == null) {
return 0;
}
int bubbleCount = mLayout.getChildCount();
final float totalBubbleWidth = bubbleCount * mBubbleSizePx;
final float totalGapWidth = (bubbleCount - 1) * getSpaceBetweenBubbles();
float rowWidth = totalGapWidth + totalBubbleWidth;
if (mShowOverflowBtn) {
rowWidth += getSpaceBetweenBubbles();
rowWidth += mOverflowBtnWidth;
}
float rowWidth = (mLayout.getChildCount() * mBubbleSizePx)
+ ((mLayout.getChildCount() - 1) * mSpaceBetweenBubbles);
// This display size we're using includes the size of the insets, we want the true
// center of the display minus the notch here, which means we should include the
// stable insets (e.g. status bar, nav bar) in this calculation.
final float trueCenter = getAvailableScreenWidth(false /* subtractStableInsets */) / 2f;
final float halfRow = rowWidth / 2f;
final float rowLeft = trueCenter - halfRow;
return rowLeft;
}
/**
* @return Space between bubbles in row above expanded view.
*/
private float getSpaceBetweenBubbles() {
final float totalBubbleWidth = mBubblesMaxRendered * mBubbleSizePx;
final float rowMargins = mExpandedViewPadding * 2;
float totalGapWidth = getWidthForDisplayingBubbles() - rowMargins - totalBubbleWidth;
if (mShowOverflowBtn) {
totalGapWidth -= mBubbleSizePx;
}
final int gapCount = mBubblesMaxRendered - 1;
final float gapWidth = totalGapWidth / gapCount;
return gapWidth;
return trueCenter - (rowWidth / 2f);
}
}