Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14036d61 authored by Lyn Han's avatar Lyn Han Committed by Android (Google) Code Review
Browse files

Merge "Animate bubble swap for update while collapsed"

parents 316c10ed 233218f9
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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. -->
+12 −0
Original line number Diff line number Diff line
@@ -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.
     */
+20 −13
Original line number Diff line number Diff line
@@ -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) {
        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);
        }
        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);
            }
        }
    }
+59 −0
Original line number Diff line number Diff line
@@ -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);