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

Commit 4aed7e0c authored by Josh Tsuji's avatar Josh Tsuji Committed by android-build-merger
Browse files

Merge changes I1360deb0,Id9a9eb85,I7f05f2ee,Ie48da88d into qt-dev

am: 06cbf657

Change-Id: I5bbfb0ec91ab5ae8760a8208b9d3a967103df999
parents 98eed7dc 06cbf657
Loading
Loading
Loading
Loading
+28 −19
Original line number Diff line number Diff line
@@ -330,9 +330,7 @@ public class BubbleStackView extends FrameLayout {
        mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER;

        mBubbleContainer = new PhysicsAnimationLayout(context);
        mBubbleContainer.setMaxRenderedChildren(
                getResources().getInteger(R.integer.bubbles_max_rendered));
        mBubbleContainer.setController(mStackAnimationController);
        mBubbleContainer.setActiveController(mStackAnimationController);
        mBubbleContainer.setElevation(elevation);
        mBubbleContainer.setClipChildren(false);
        addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
@@ -728,7 +726,7 @@ public class BubbleStackView extends FrameLayout {
    public void updateBubbleOrder(List<Bubble> bubbles) {
        for (int i = 0; i < bubbles.size(); i++) {
            Bubble bubble = bubbles.get(i);
            mBubbleContainer.moveViewTo(bubble.iconView, i);
            mBubbleContainer.reorderView(bubble.iconView, i);
        }
    }

@@ -908,19 +906,17 @@ public class BubbleStackView extends FrameLayout {
            };

            if (shouldExpand) {
                mBubbleContainer.setController(mExpandedAnimationController);
                mExpandedAnimationController.expandFromStack(
                        mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
                        /* collapseTo */,
                        () -> {
                mBubbleContainer.setActiveController(mExpandedAnimationController);
                mExpandedAnimationController.expandFromStack(() -> {
                    updatePointerPosition();
                    updateAfter.run();
                } /* after */);
            } else {
                mBubbleContainer.cancelAllAnimations();
                mExpandedAnimationController.collapseBackToStack(
                        mStackAnimationController.getStackPositionAlongNearestHorizontalEdge(),
                        () -> {
                            mBubbleContainer.setController(mStackAnimationController);
                            mBubbleContainer.setActiveController(mStackAnimationController);
                            updateAfter.run();
                        });
            }
@@ -1013,7 +1009,7 @@ public class BubbleStackView extends FrameLayout {
        }

        mStackAnimationController.cancelStackPositionAnimations();
        mBubbleContainer.setController(mStackAnimationController);
        mBubbleContainer.setActiveController(mStackAnimationController);
        hideFlyoutImmediate();

        mDraggingInDismissTarget = false;
@@ -1111,6 +1107,10 @@ public class BubbleStackView extends FrameLayout {
    /** Called when a gesture is completed or cancelled. */
    void onGestureFinished() {
        mIsGestureInProgress = false;

        if (mIsExpanded) {
            mExpandedAnimationController.onGestureFinished();
        }
    }

    /** Prepares and starts the desaturate/darken animation on the bubble stack. */
@@ -1201,6 +1201,7 @@ public class BubbleStackView extends FrameLayout {
     */
    void magnetToStackIfNeededThenAnimateDismissal(
            View touchedView, float velX, float velY, Runnable after) {
        final View draggedOutBubble = mExpandedAnimationController.getDraggedOutBubble();
        final Runnable animateDismissal = () -> {
            mAfterMagnet = null;

@@ -1218,7 +1219,7 @@ public class BubbleStackView extends FrameLayout {
                            resetDesaturationAndDarken();
                        });
            } else {
                mExpandedAnimationController.dismissDraggedOutBubble(() -> {
                mExpandedAnimationController.dismissDraggedOutBubble(draggedOutBubble, () -> {
                    mAnimatingMagnet = false;
                    mShowingDismiss = false;
                    mDraggingInDismissTarget = false;
@@ -1385,10 +1386,18 @@ public class BubbleStackView extends FrameLayout {
                };

                // Post in case layout isn't complete and getWidth returns 0.
                post(() -> mFlyout.showFlyout(
                post(() -> {
                    // An auto-expanding bubble could have been posted during the time it takes to
                    // layout.
                    if (isExpanded()) {
                        return;
                    }

                    mFlyout.showFlyout(
                            updateMessage, mStackAnimationController.getStackPosition(), getWidth(),
                            mStackAnimationController.isStackOnLeftSide(),
                        bubble.iconView.getBadgeColor(), mAfterFlyoutHides));
                            bubble.iconView.getBadgeColor(), mAfterFlyoutHides);
                });
            }

            mFlyout.removeCallbacks(mHideFlyout);
+98 −74
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.graphics.PointF;
import android.view.View;
import android.view.WindowInsets;

import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringForce;

@@ -63,12 +64,16 @@ public class ExpandedAnimationController
    private Point mDisplaySize;
    /** Size of dismiss target at bottom of screen. */
    private float mPipDismissHeight;
    /** Max number of bubbles shown in row above expanded view.*/
    private int mBubblesMaxRendered;

    /** Whether the dragged-out bubble is in the dismiss target. */
    private boolean mIndividualBubbleWithinDismissTarget = false;

    private boolean mAnimatingExpand = false;
    private boolean mAnimatingCollapse = false;
    private Runnable mAfterExpand;
    private Runnable mAfterCollapse;
    private PointF mCollapsePoint;

    /**
     * Whether the dragged out bubble is springing towards the touch point, rather than using the
     * default behavior of moving directly to the touch point.
@@ -97,56 +102,60 @@ public class ExpandedAnimationController
    private View mBubbleDraggingOut;

    /**
     * Drag velocities for the dragging-out bubble when the drag finished. These are used by
     * {@link #onChildRemoved} to animate out the bubble while respecting touch velocity.
     * Animates expanding the bubbles into a row along the top of the screen.
     */
    private float mBubbleDraggingOutVelX;
    private float mBubbleDraggingOutVelY;
    public void expandFromStack(Runnable after) {
        mAnimatingCollapse = false;
        mAnimatingExpand = true;
        mAfterExpand = after;

    @Override
    protected void setLayout(PhysicsAnimationLayout layout) {
        super.setLayout(layout);
        startOrUpdateExpandAnimation();
    }

        final Resources res = layout.getResources();
        mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
        mBubblePaddingPx = res.getDimensionPixelSize(R.dimen.bubble_padding);
        mBubbleSizePx = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
        mStatusBarHeight =
                res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
        mPipDismissHeight = res.getDimensionPixelSize(R.dimen.pip_dismiss_gradient_height);
        mBubblesMaxRendered = res.getInteger(R.integer.bubbles_max_rendered);
    /** Animate collapsing the bubbles back to their stacked position. */
    public void collapseBackToStack(PointF collapsePoint, Runnable after) {
        mAnimatingExpand = false;
        mAnimatingCollapse = true;
        mAfterCollapse = after;
        mCollapsePoint = collapsePoint;

        startOrUpdateCollapseAnimation();
    }

    /**
     * Animates expanding the bubbles into a row along the top of the screen.
     */
    public void expandFromStack(PointF collapseTo, Runnable after) {
    private void startOrUpdateExpandAnimation() {
        animationsForChildrenFromIndex(
                0, /* startIndex */
                new ChildAnimationConfigurator() {
                    @Override
                    public void configureAnimationForChildAtIndex(
                            int index, PhysicsAnimationLayout.PhysicsPropertyAnimator animation) {
                        animation.position(getBubbleLeft(index), getExpandedY());
                (index, animation) -> animation.position(getBubbleLeft(index), getExpandedY()))
                .startAll(() -> {
                    mAnimatingExpand = false;

                    if (mAfterExpand != null) {
                        mAfterExpand.run();
                    }
            })
            .startAll(after);

        mCollapseToPoint = collapseTo;
                    mAfterExpand = null;
                });
    }

    /** Animate collapsing the bubbles back to their stacked position. */
    public void collapseBackToStack(Runnable after) {
    private void startOrUpdateCollapseAnimation() {
        // Stack to the left if we're going to the left, or right if not.
        final float sideMultiplier = mLayout.isFirstChildXLeftOfCenter(mCollapseToPoint.x) ? -1 : 1;

        final float sideMultiplier = mLayout.isFirstChildXLeftOfCenter(mCollapsePoint.x) ? -1 : 1;
        animationsForChildrenFromIndex(
                0, /* startIndex */
                (index, animation) ->
                (index, animation) -> {
                    animation.position(
                            mCollapseToPoint.x + (sideMultiplier * index * mStackOffsetPx),
                            mCollapseToPoint.y))
            .startAll(after /* endAction */);
                            mCollapsePoint.x + (sideMultiplier * index * mStackOffsetPx),
                            mCollapsePoint.y);
                })
                .startAll(() -> {
                    mAnimatingCollapse = false;

                    if (mAfterCollapse != null) {
                        mAfterCollapse.run();
                    }

                    mAfterCollapse = null;
                });
    }

    /** Prepares the given bubble to be dragged out. */
@@ -190,10 +199,10 @@ public class ExpandedAnimationController
    }

    /** Plays a dismiss animation on the dragged out bubble. */
    public void dismissDraggedOutBubble(Runnable after) {
    public void dismissDraggedOutBubble(View bubble, Runnable after) {
        mIndividualBubbleWithinDismissTarget = false;

        animationForChild(mBubbleDraggingOut)
        animationForChild(bubble)
                .withStiffness(SpringForce.STIFFNESS_HIGH)
                .scaleX(1.1f)
                .scaleY(1.1f)
@@ -203,6 +212,10 @@ public class ExpandedAnimationController
        updateBubblePositions();
    }

    @Nullable public View getDraggedOutBubble() {
        return mBubbleDraggingOut;
    }

    /** Magnets the given bubble to the dismiss target. */
    public void magnetBubbleToDismiss(
            View bubbleView, float velX, float velY, float destY, Runnable after) {
@@ -245,20 +258,13 @@ public class ExpandedAnimationController
                .withPositionStartVelocities(velX, velY)
                .start(() -> bubbleView.setTranslationZ(0f) /* after */);

        mBubbleDraggingOut = null;
        mBubbleDraggedOutEnough = false;
        updateBubblePositions();
    }

    /**
     * Sets configuration variables so that when the given bubble is removed, the animations are
     * started with the given velocities.
     */
    public void prepareForDismissalWithVelocity(View bubbleView, float velX, float velY) {
        mBubbleDraggingOut = bubbleView;
        mBubbleDraggingOutVelX = velX;
        mBubbleDraggingOutVelY = velY;
    /** Resets bubble drag out gesture flags. */
    public void onGestureFinished() {
        mBubbleDraggedOutEnough = false;
        mBubbleDraggingOut = null;
    }

    /**
@@ -296,6 +302,23 @@ public class ExpandedAnimationController
                : 0);
    }

    @Override
    void onActiveControllerForLayout(PhysicsAnimationLayout layout) {
        final Resources res = layout.getResources();
        mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
        mBubblePaddingPx = res.getDimensionPixelSize(R.dimen.bubble_padding);
        mBubbleSizePx = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
        mStatusBarHeight =
                res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
        mPipDismissHeight = res.getDimensionPixelSize(R.dimen.pip_dismiss_gradient_height);

        // Ensure that all child views are at 1x scale, and visible, in case they were animating
        // in.
        mLayout.setVisibility(View.VISIBLE);
        animationsForChildrenFromIndex(0 /* startIndex */, (index, animation) ->
                animation.scaleX(1f).scaleY(1f).alpha(1f)).startAll();
    }

    @Override
    Set<DynamicAnimation.ViewProperty> getAnimatedProperties() {
        return Sets.newHashSet(
@@ -325,8 +348,14 @@ public class ExpandedAnimationController

    @Override
    void onChildAdded(View child, int index) {
        // If a bubble is added while the expand/collapse animations are playing, update the
        // animation to include the new bubble.
        if (mAnimatingExpand) {
            startOrUpdateExpandAnimation();
        } else if (mAnimatingCollapse) {
            startOrUpdateCollapseAnimation();
        } else {
            child.setTranslationX(getXForChildAtIndex(index));

            animationForChild(child)
                    .translationY(
                            getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR, /* from */
@@ -334,6 +363,7 @@ public class ExpandedAnimationController
                    .start();
            updateBubblePositions();
        }
    }

    @Override
    void onChildRemoved(View child, int index, Runnable finishRemoval) {
@@ -357,19 +387,15 @@ public class ExpandedAnimationController
    }

    @Override
    protected void setChildVisibility(View child, int index, int visibility) {
        if (visibility == View.VISIBLE) {
            // Set alpha to 0 but then become visible immediately so the animation is visible.
            child.setAlpha(0f);
            child.setVisibility(View.VISIBLE);
    void onChildReordered(View child, int oldIndex, int newIndex) {
        updateBubblePositions();
    }

        animationForChild(child)
                .alpha(visibility == View.GONE ? 0f : 1f)
                .start(() -> super.setChildVisibility(child, index, visibility) /* after */);
    private void updateBubblePositions() {
        if (mAnimatingExpand || mAnimatingCollapse) {
            return;
        }

    private void updateBubblePositions() {
        for (int i = 0; i < mLayout.getChildCount(); i++) {
            final View bubble = mLayout.getChildAt(i);

@@ -378,6 +404,7 @@ public class ExpandedAnimationController
            if (bubble.equals(mBubbleDraggingOut)) {
                return;
            }

            animationForChild(bubble)
                    .translationX(getBubbleLeft(i))
                    .start();
@@ -403,10 +430,7 @@ public class ExpandedAnimationController
            return 0;
        }
        int bubbleCount = mLayout.getChildCount();
        if (bubbleCount > mBubblesMaxRendered) {
            // Only shown bubbles are relevant for calculating position.
            bubbleCount = mBubblesMaxRendered;
        }

        // Width calculations.
        double bubble = bubbleCount * mBubbleSizePx;
        float gap = (bubbleCount - 1) * mBubblePaddingPx;
+136 −124

File changed.

Preview size limit exceeded, changes collapsed.

+43 −28
Original line number Diff line number Diff line
@@ -154,21 +154,6 @@ public class StackAnimationController extends
    /** Height of the status bar. */
    private float mStatusBarHeight;

    @Override
    protected void setLayout(PhysicsAnimationLayout layout) {
        super.setLayout(layout);

        Resources res = layout.getResources();
        mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
        mIndividualBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
        mBubblePadding = res.getDimensionPixelSize(R.dimen.bubble_padding);
        mBubbleOffscreen = res.getDimensionPixelSize(R.dimen.bubble_stack_offscreen);
        mStackStartingVerticalOffset =
                res.getDimensionPixelSize(R.dimen.bubble_stack_starting_offset_y);
        mStatusBarHeight =
                res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
    }

    /**
     * Instantly move the first bubble to the given point, and animate the rest of the stack behind
     * it with the 'following' effect.
@@ -286,6 +271,8 @@ public class StackAnimationController extends
                },
                DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);

        // If we're flinging now, there's no more touch event to catch up to.
        mFirstBubbleSpringingToTouch = false;
        mIsMovingFromFlinging = true;
        return destinationRelativeX;
    }
@@ -656,7 +643,27 @@ public class StackAnimationController extends

        if (mLayout.getChildCount() > 0) {
            animationForChildAtIndex(0).translationX(mStackPosition.x).start();
        } else {
            // Set the start position back to the default since we're out of bubbles. New bubbles
            // will then animate in from the start position.
            mStackPosition = getDefaultStartPosition();
        }
    }

    @Override
    void onChildReordered(View child, int oldIndex, int newIndex) {}

    @Override
    void onActiveControllerForLayout(PhysicsAnimationLayout layout) {
        Resources res = layout.getResources();
        mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
        mIndividualBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
        mBubblePadding = res.getDimensionPixelSize(R.dimen.bubble_padding);
        mBubbleOffscreen = res.getDimensionPixelSize(R.dimen.bubble_stack_offscreen);
        mStackStartingVerticalOffset =
                res.getDimensionPixelSize(R.dimen.bubble_stack_starting_offset_y);
        mStatusBarHeight =
                res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
    }

    /** Moves the stack, without any animation, to the starting position. */
@@ -664,11 +671,10 @@ public class StackAnimationController extends
        // Post to ensure that the layout's width and height have been calculated.
        mLayout.setVisibility(View.INVISIBLE);
        mLayout.post(() -> {
            mStackMovedToStartPosition = true;
            setStackPosition(
                    mRestingStackPosition == null
            setStackPosition(mRestingStackPosition == null
                    ? getDefaultStartPosition()
                    : mRestingStackPosition);
            mStackMovedToStartPosition = true;
            mLayout.setVisibility(View.VISIBLE);

            // Animate in the top bubble now that we're visible.
@@ -707,17 +713,22 @@ public class StackAnimationController extends
        Log.d(TAG, String.format("Setting position to (%f, %f).", pos.x, pos.y));
        mStackPosition.set(pos.x, pos.y);

        // If we're not the active controller, we don't want to physically move the bubble views.
        if (isActiveController()) {
            mLayout.cancelAllAnimations();
            cancelStackPositionAnimations();

            // Since we're not using the chained animations, apply the offsets manually.
        final float xOffset = getOffsetForChainedPropertyAnimation(DynamicAnimation.TRANSLATION_X);
        final float yOffset = getOffsetForChainedPropertyAnimation(DynamicAnimation.TRANSLATION_Y);
            final float xOffset = getOffsetForChainedPropertyAnimation(
                    DynamicAnimation.TRANSLATION_X);
            final float yOffset = getOffsetForChainedPropertyAnimation(
                    DynamicAnimation.TRANSLATION_Y);
            for (int i = 0; i < mLayout.getChildCount(); i++) {
                mLayout.getChildAt(i).setTranslationX(pos.x + (i * xOffset));
                mLayout.getChildAt(i).setTranslationY(pos.y + (i * yOffset));
            }
        }
    }

    /** Returns the default stack position, which is on the top right. */
    private PointF getDefaultStartPosition() {
@@ -732,6 +743,10 @@ public class StackAnimationController extends

    /** Animates in the given bubble. */
    private void animateInBubble(View child) {
        if (!isActiveController()) {
            return;
        }

        child.setTranslationY(mStackPosition.y);

        float xOffset = getOffsetForChainedPropertyAnimation(DynamicAnimation.TRANSLATION_X);
+9 −19
Original line number Diff line number Diff line
@@ -60,8 +60,8 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
    @Before
    public void setUp() throws Exception {
        super.setUp();
        addOneMoreThanRenderLimitBubbles();
        mLayout.setController(mExpandedController);
        addOneMoreThanBubbleLimitBubbles();
        mLayout.setActiveController(mExpandedController);

        Resources res = mLayout.getResources();
        mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
@@ -73,14 +73,14 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
    @Test
    public void testExpansionAndCollapse() throws InterruptedException {
        Runnable afterExpand = Mockito.mock(Runnable.class);
        mExpandedController.expandFromStack(mExpansionPoint, afterExpand);
        mExpandedController.expandFromStack(afterExpand);
        waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);

        testBubblesInCorrectExpandedPositions();
        verify(afterExpand).run();

        Runnable afterCollapse = Mockito.mock(Runnable.class);
        mExpandedController.collapseBackToStack(afterCollapse);
        mExpandedController.collapseBackToStack(mExpansionPoint, afterCollapse);
        waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);

        testStackedAtPosition(mExpansionPoint.x, mExpansionPoint.y, -1);
@@ -139,7 +139,6 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
        assertEquals(500f, draggedBubble.getTranslationY(), 1f);

        // Snap it back and make sure it made it back correctly.
        mExpandedController.prepareForDismissalWithVelocity(draggedBubble, 0f, 0f);
        mLayout.removeView(draggedBubble);
        waitForLayoutMessageQueue();
        waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
@@ -169,7 +168,7 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC

        // Dismiss the now-magneted bubble, verify that the callback was called.
        final Runnable afterDismiss = Mockito.mock(Runnable.class);
        mExpandedController.dismissDraggedOutBubble(afterDismiss);
        mExpandedController.dismissDraggedOutBubble(draggedOutView, afterDismiss);
        waitForPropertyAnimations(DynamicAnimation.ALPHA);
        verify(after).run();

@@ -224,7 +223,7 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC

    /** Expand the stack and wait for animations to finish. */
    private void expand() throws InterruptedException {
        mExpandedController.expandFromStack(mExpansionPoint, Mockito.mock(Runnable.class));
        mExpandedController.expandFromStack(Mockito.mock(Runnable.class));
        waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
    }

@@ -236,26 +235,19 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
            assertEquals(x + i * offsetMultiplier * mStackOffset,
                    mLayout.getChildAt(i).getTranslationX(), 2f);
            assertEquals(y, mLayout.getChildAt(i).getTranslationY(), 2f);

            if (i < mMaxRenderedBubbles) {
            assertEquals(1f, mLayout.getChildAt(i).getAlpha(), .01f);
        }
    }
    }

    /** Check that children are in the correct positions for being expanded. */
    private void testBubblesInCorrectExpandedPositions() {
        // Check all the visible bubbles to see if they're in the right place.
        for (int i = 0; i < Math.min(mLayout.getChildCount(), mMaxRenderedBubbles); i++) {
        for (int i = 0; i < mLayout.getChildCount(); i++) {
            assertEquals(getBubbleLeft(i),
                    mLayout.getChildAt(i).getTranslationX(),
                    2f);
            assertEquals(mExpandedController.getExpandedY(),
                    mLayout.getChildAt(i).getTranslationY(), 2f);

            if (i < mMaxRenderedBubbles) {
                assertEquals(1f, mLayout.getChildAt(i).getAlpha(), .01f);
            }
        }
    }

@@ -273,9 +265,7 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
            return 0;
        }
        int bubbleCount = mLayout.getChildCount();
        if (bubbleCount > mMaxRenderedBubbles) {
            bubbleCount = mMaxRenderedBubbles;
        }

        // Width calculations.
        double bubble = bubbleCount * mBubbleSize;
        float gap = (bubbleCount - 1) * mBubblePadding;
Loading