Merge "Animate bubble swap for update while collapsed"

This commit is contained in:
Lyn Han
2020-10-27 22:02:30 +00:00
committed by Android (Google) Code Review
4 changed files with 93 additions and 13 deletions

View File

@@ -1218,6 +1218,8 @@
<dimen name="bubble_message_padding">4dp</dimen>
<!-- Offset between bubbles in their stacked position. -->
<dimen name="bubble_stack_offset">10dp</dimen>
<!-- Offset between stack y and animation y for bubble swap. -->
<dimen name="bubble_swap_animation_offset">15dp</dimen>
<!-- How far offscreen the bubble stack rests. Cuts off padding and part of icon bitmap. -->
<dimen name="bubble_stack_offscreen">9dp</dimen>
<!-- How far down the screen the stack starts. -->

View File

@@ -113,6 +113,18 @@ public class BadgedImageView extends ImageView {
setClickable(true);
}
public void showDotAndBadge(boolean onLeft) {
removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.BEHIND_STACK);
animateDotBadgePositions(onLeft);
}
public void hideDotAndBadge(boolean onLeft) {
addDotSuppressionFlag(BadgedImageView.SuppressionFlag.BEHIND_STACK);
mOnLeft = onLeft;
hideBadge();
}
/**
* Updates the view with provided info.
*/

View File

@@ -90,6 +90,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* Renders bubbles in a stack and handles animating expanded and collapsed states.
@@ -1479,12 +1480,24 @@ public class BubbleStackView extends FrameLayout
logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__UPDATED);
}
/**
* Update bubble order and pointer position.
*/
public void updateBubbleOrder(List<Bubble> bubbles) {
for (int i = 0; i < bubbles.size(); i++) {
Bubble bubble = bubbles.get(i);
mBubbleContainer.reorderView(bubble.getIconView(), i);
final Runnable reorder = () -> {
for (int i = 0; i < bubbles.size(); i++) {
Bubble bubble = bubbles.get(i);
mBubbleContainer.reorderView(bubble.getIconView(), i);
}
};
if (mIsExpanded) {
reorder.run();
updateBubbleIcons();
} else {
List<View> bubbleViews = bubbles.stream()
.map(b -> b.getIconView()).collect(Collectors.toList());
mStackAnimationController.animateReorder(bubbleViews, reorder);
}
updateBubbleIcons();
updatePointerPosition();
}
@@ -2595,17 +2608,11 @@ public class BubbleStackView extends FrameLayout
bv.setZ((mMaxBubbles * mBubbleElevation) - i);
if (mIsExpanded) {
bv.removeDotSuppressionFlag(
BadgedImageView.SuppressionFlag.BEHIND_STACK);
bv.animateDotBadgePositions(false /* onLeft */);
bv.showDotAndBadge(false /* onLeft */);
} else if (i == 0) {
bv.removeDotSuppressionFlag(
BadgedImageView.SuppressionFlag.BEHIND_STACK);
bv.animateDotBadgePositions(!mStackOnLeftOrWillBe);
bv.showDotAndBadge(!mStackOnLeftOrWillBe);
} else {
bv.addDotSuppressionFlag(
BadgedImageView.SuppressionFlag.BEHIND_STACK);
bv.hideBadge();
bv.hideDotAndBadge(!mStackOnLeftOrWillBe);
}
}
}

View File

@@ -34,6 +34,7 @@ import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import com.android.systemui.R;
import com.android.systemui.bubbles.BadgedImageView;
import com.android.systemui.bubbles.BubblePositioner;
import com.android.systemui.bubbles.BubbleStackView;
import com.android.wm.shell.animation.PhysicsAnimator;
@@ -45,6 +46,7 @@ import com.google.android.collect.Sets;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.function.IntSupplier;
@@ -63,6 +65,10 @@ public class StackAnimationController extends
private static final float ANIMATE_IN_STIFFNESS = 1000f;
private static final int ANIMATE_IN_START_DELAY = 25;
/** Values to use for animating updated bubble to top of stack. */
private static final float BUBBLE_SWAP_SCALE = 0.8f;
private static final long BUBBLE_SWAP_DURATION = 300L;
/**
* Values to use for the default {@link SpringForce} provided to the physics animation layout.
*/
@@ -180,6 +186,12 @@ public class StackAnimationController extends
/** Horizontal offset of bubbles in the stack. */
private float mStackOffset;
/** Offset between stack y and animation y for bubble swap. */
private float mSwapAnimationOffset;
/** Max number of bubbles to show in the expanded bubble row. */
private int mMaxBubbles;
/** Default bubble elevation. */
private int mElevation;
/** Diameter of the bubble icon. */
private int mBubbleBitmapSize;
/** Width of the bubble (icon and padding). */
@@ -770,6 +782,50 @@ public class StackAnimationController extends
}
}
public void animateReorder(List<View> bubbleViews, Runnable after) {
for (int newIndex = 0; newIndex < bubbleViews.size(); newIndex++) {
View view = bubbleViews.get(newIndex);
final int oldIndex= mLayout.indexOfChild(view);
animateSwap(view, oldIndex, newIndex, after);
}
}
private void animateSwap(View view, int oldIndex, int newIndex, Runnable finishReorder) {
final float newY = getStackPosition().y + newIndex * mSwapAnimationOffset;
final float swapY = newIndex == 0
? newY - mSwapAnimationOffset // Above top of stack
: newY + mSwapAnimationOffset; // Below where bubble will be
view.animate()
.scaleX(BUBBLE_SWAP_SCALE)
.scaleY(BUBBLE_SWAP_SCALE)
.translationY(swapY)
.setDuration(BUBBLE_SWAP_DURATION)
.withEndAction(() -> finishSwapAnimation(view, oldIndex, newIndex, finishReorder));
}
private void finishSwapAnimation(View view, int oldIndex, int newIndex,
Runnable finishReorder) {
// At this point, swapping bubbles have the least overlap.
// Update z-index and badge visibility here for least jarring transition.
view.setZ((mMaxBubbles * mElevation) - newIndex);
BadgedImageView bv = (BadgedImageView) view;
if (oldIndex == 0 && newIndex > 0) {
bv.hideDotAndBadge(!isStackOnLeftSide());
} else if (oldIndex > 0 && newIndex == 0) {
bv.showDotAndBadge(!isStackOnLeftSide());
}
// Animate bubble back into stack, at new index and original size.
final float newY = getStackPosition().y + newIndex * mStackOffset;
view.animate()
.scaleX(1f)
.scaleY(1f)
.translationY(newY)
.setDuration(BUBBLE_SWAP_DURATION)
.withEndAction(() -> finishReorder.run());
}
@Override
void onChildReordered(View child, int oldIndex, int newIndex) {
if (isStackPositionSet()) {
@@ -781,6 +837,9 @@ public class StackAnimationController extends
void onActiveControllerForLayout(PhysicsAnimationLayout layout) {
Resources res = layout.getResources();
mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
mSwapAnimationOffset = res.getDimensionPixelSize(R.dimen.bubble_swap_animation_offset);
mMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
mElevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
mBubbleBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_bitmap_size);
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);