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

Commit 29a3e5d6 authored by Liran Binyamin's avatar Liran Binyamin
Browse files

Animate the bubble bar to show new bubble

This change updates that animation that plays when a new bubble notification is received. We now animate the entire bubble bar rather than the individual bubble.

Demo: http://recall/-/bJtug1HhvXkkeA4MQvIaiP/dwbsZJZlqLwJ2IG7RfJZ7c

Flag: ACONFIG com.android.wm.shell.enable_bubble_bar DEVELOPMENT
Bug: 280605846
Test: atest BubbleBarViewAnimatorTest
Change-Id: I2dc58ad61b880d76c9eefa462c3aee4e8bbb3584
parent 88a90587
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -155,13 +155,16 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas
            )

            // if there's an animating bubble add it to the touch region so that it's clickable
            val animatingBubbleBounds =
            val isAnimatingNewBubble =
                controllers.bubbleControllers
                    .getOrNull()
                    ?.bubbleBarViewController
                    ?.animatingBubbleBounds
            if (animatingBubbleBounds != null) {
                defaultTouchableRegion.op(animatingBubbleBounds, Region.Op.UNION)
                    ?.isAnimatingNewBubble
                    ?: false
            if (isAnimatingNewBubble) {
                val iconBounds =
                    controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds
                defaultTouchableRegion.op(iconBounds, Region.Op.UNION)
            }
        }

+18 −64
Original line number Diff line number Diff line
@@ -104,8 +104,6 @@ public class BubbleBarView extends FrameLayout {
     * updates the bounds and accounts for translation.
     */
    private final Rect mBubbleBarBounds = new Rect();
    /** The bounds of the animating bubble in the coordinate space of the BubbleBarView. */
    private final Rect mAnimatingBubbleBounds = new Rect();
    // The amount the bubbles overlap when they are stacked in the bubble bar
    private final float mIconOverlapAmount;
    // The spacing between the bubbles when bubble bar is expanded
@@ -185,7 +183,7 @@ public class BubbleBarView extends FrameLayout {

        setClipToPadding(false);

        mBubbleBarBackground = new BubbleBarBackground(context, getBubbleBarHeight());
        mBubbleBarBackground = new BubbleBarBackground(context, getBubbleBarExpandedHeight());
        setBackgroundDrawable(mBubbleBarBackground);

        mWidthAnimator.setDuration(WIDTH_ANIMATION_DURATION_MS);
@@ -246,7 +244,7 @@ public class BubbleBarView extends FrameLayout {
            params.width = (int) mIconSize;
            childView.setLayoutParams(params);
        }
        mBubbleBarBackground.setHeight(getBubbleBarHeight());
        mBubbleBarBackground.setHeight(getBubbleBarExpandedHeight());
        updateLayoutParams();
    }

@@ -462,30 +460,6 @@ public class BubbleBarView extends FrameLayout {
        return mBubbleBarBounds;
    }

    /** Returns the bounds of the animating bubble, or {@code null} if no bubble is animating. */
    @Nullable
    public Rect getAnimatingBubbleBounds() {
        if (mIsAnimatingNewBubble) {
            return mAnimatingBubbleBounds;
        }
        return null;
    }

    /**
     * Updates the animating bubble bounds. This should be called when the bubble is fully animated
     * in so that we can include it in taskbar touchable region.
     *
     * <p>The bounds are adjusted to the coordinate space of BubbleBarView so that it can be used
     * by taskbar.
     */
    public void updateAnimatingBubbleBounds(int left, int top, int width, int height) {
        Rect bubbleBarBounds = getBubbleBarBounds();
        mAnimatingBubbleBounds.left = bubbleBarBounds.left + left;
        mAnimatingBubbleBounds.top = bubbleBarBounds.top + top;
        mAnimatingBubbleBounds.right = mAnimatingBubbleBounds.left + width;
        mAnimatingBubbleBounds.bottom = mAnimatingBubbleBounds.top + height;
    }

    /**
     * Set bubble bar relative pivot value for X and Y, applied as a fraction of view width/height
     * respectively. If the value is not in range of 0 to 1 it will be normalized.
@@ -498,6 +472,11 @@ public class BubbleBarView extends FrameLayout {
        requestLayout();
    }

    /** Like {@link #setRelativePivot(float, float)} but only updates pivot y. */
    public void setRelativePivotY(float y) {
        setRelativePivot(mRelativePivotX, y);
    }

    /**
     * Get current relative pivot for X axis
     */
@@ -512,38 +491,14 @@ public class BubbleBarView extends FrameLayout {
        return mRelativePivotY;
    }

    /** Prepares for animating a bubble while being stashed. */
    public void prepareForAnimatingBubbleWhileStashed(String bubbleKey) {
    /** Notifies the bubble bar that a new bubble animation is starting. */
    public void onAnimatingBubbleStarted() {
        mIsAnimatingNewBubble = true;
        // we're about to animate the new bubble in. the new bubble has already been added to this
        // view, but we're currently stashed, so before we can start the animation we need make
        // everything else in the bubble bar invisible, except for the bubble that's being animated.
        setBackground(null);
        for (int i = 0; i < getChildCount(); i++) {
            final BubbleView view = (BubbleView) getChildAt(i);
            final String key = view.getBubble().getKey();
            if (!bubbleKey.equals(key)) {
                view.setVisibility(INVISIBLE);
            }
        }
        setVisibility(VISIBLE);
        setAlpha(1);
        setTranslationY(0);
        setScaleX(1);
        setScaleY(1);
    }

    /** Resets the state after the bubble animation completed. */
    /** Notifies the bubble bar that a new bubble animation is complete. */
    public void onAnimatingBubbleCompleted() {
        mIsAnimatingNewBubble = false;
        // setting the background triggers relayout so no need to explicitly invalidate after the
        // animation
        setBackground(mBubbleBarBackground);
        for (int i = 0; i < getChildCount(); i++) {
            final BubbleView view = (BubbleView) getChildAt(i);
            view.setVisibility(VISIBLE);
            view.setAlpha(1f);
        }
    }

    // TODO: (b/280605790) animate it
@@ -577,7 +532,7 @@ public class BubbleBarView extends FrameLayout {

    private void updateLayoutParams() {
        LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
        lp.height = getBubbleBarHeight();
        lp.height = (int) getBubbleBarExpandedHeight();
        lp.width = (int) (mIsBarExpanded ? expandedWidth() : collapsedWidth());
        setLayoutParams(lp);
    }
@@ -593,12 +548,6 @@ public class BubbleBarView extends FrameLayout {
     * on the expanded state.
     */
    private void updateChildrenRenderNodeProperties() {
        if (mIsAnimatingNewBubble) {
            // don't update bubbles if a new bubble animation is playing.
            // the bubble bar will redraw itself via onLayout after the animation.
            return;
        }

        final float widthState = (float) mWidthAnimator.getAnimatedValue();
        final float currentWidth = getWidth();
        final float expandedWidth = expandedWidth();
@@ -864,8 +813,13 @@ public class BubbleBarView extends FrameLayout {
                : mIconSize + horizontalPadding;
    }

    private int getBubbleBarHeight() {
        return (int) (mIconSize + mBubbleBarPadding * 2 + mPointerSize);
    private float getBubbleBarExpandedHeight() {
        return getBubbleBarCollapsedHeight() + mPointerSize;
    }

    float getBubbleBarCollapsedHeight() {
        // the pointer is invisible when collapsed
        return mIconSize + mBubbleBarPadding * 2;
    }

    /**
+7 −4
Original line number Diff line number Diff line
@@ -189,6 +189,10 @@ public class BubbleBarViewController {
        return mBubbleBarTranslationY;
    }

    float getBubbleBarCollapsedHeight() {
        return mBarView.getBubbleBarCollapsedHeight();
    }

    /**
     * Whether the bubble bar is visible or not.
     */
@@ -222,10 +226,9 @@ public class BubbleBarViewController {
        return mBarView.getBubbleBarBounds();
    }

    /** The bounds of the animating bubble, or {@code null} if no bubble is animating. */
    @Nullable
    public Rect getAnimatingBubbleBounds() {
        return mBarView.getAnimatingBubbleBounds();
    /** Whether a new bubble is animating. */
    public boolean isAnimatingNewBubble() {
        return mBarView.isAnimatingNewBubble();
    }

    /** The horizontal margin of the bubble bar from the edge of the screen. */
+42 −8
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.view.InsetsController;
import android.view.MotionEvent;
import android.view.View;

import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.taskbar.StashedHandleViewController;
import com.android.launcher3.taskbar.TaskbarActivityContext;
@@ -77,11 +78,16 @@ public class BubbleStashController {
    private boolean mBubblesShowingOnOverview;
    private boolean mIsSysuiLocked;

    private final float mHandleCenterFromScreenBottom;

    @Nullable
    private AnimatorSet mAnimator;

    public BubbleStashController(TaskbarActivityContext activity) {
        mActivity = activity;
        // the handle is centered within the stashed taskbar area
        mHandleCenterFromScreenBottom =
                mActivity.getResources().getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f;
    }

    public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
@@ -266,7 +272,6 @@ public class BubbleStashController {
     */
    private AnimatorSet createStashAnimator(boolean isStashed, long duration) {
        AnimatorSet animatorSet = new AnimatorSet();
        final float stashTranslation = (mUnstashedHeight - mStashedHeight) / 2f;

        AnimatorSet fullLengthAnimatorSet = new AnimatorSet();
        // Not exactly half and may overlap. See [first|second]HalfDurationScale below.
@@ -280,7 +285,8 @@ public class BubbleStashController {
            firstHalfDurationScale = 0.75f;
            secondHalfDurationScale = 0.5f;

            fullLengthAnimatorSet.play(mIconTranslationYForStash.animateToValue(stashTranslation));
            fullLengthAnimatorSet.play(
                    mIconTranslationYForStash.animateToValue(getStashTranslation()));

            firstHalfAnimatorSet.playTogether(
                    mIconAlphaForStash.animateToValue(0),
@@ -329,6 +335,10 @@ public class BubbleStashController {
        return animatorSet;
    }

    private float getStashTranslation() {
        return (mUnstashedHeight - mStashedHeight) / 2f;
    }

    private void onIsStashedChanged() {
        mControllers.runAfterInit(() -> {
            mHandleViewController.onIsStashedChanged();
@@ -336,7 +346,7 @@ public class BubbleStashController {
        });
    }

    private float getBubbleBarTranslationYForTaskbar() {
    public float getBubbleBarTranslationYForTaskbar() {
        return -mActivity.getDeviceProfile().taskbarBottomMargin;
    }

@@ -355,6 +365,25 @@ public class BubbleStashController {
                : getBubbleBarTranslationYForTaskbar();
    }

    /**
     * The difference on the Y axis between the center of the handle and the center of the bubble
     * bar.
     */
    public float getDiffBetweenHandleAndBarCenters() {
        // the difference between the centers of the handle and the bubble bar is the difference
        // between their distance from the bottom of the screen.

        float barCenter = mBarViewController.getBubbleBarCollapsedHeight() / 2f;
        return mHandleCenterFromScreenBottom - barCenter;
    }

    /** The distance the handle moves as part of the new bubble animation. */
    public float getStashedHandleTranslationForNewBubbleAnimation() {
        // the should move up to the top of the stashed taskbar area. it is centered within it so
        // it should move the same distance as it is away from the bottom.
        return -mHandleCenterFromScreenBottom;
    }

    /** Checks whether the motion event is over the stash handle. */
    public boolean isEventOverStashHandle(MotionEvent ev) {
        return mHandleViewController.isEventOverHandle(ev);
@@ -365,11 +394,6 @@ public class BubbleStashController {
        mHandleViewController.setBubbleBarLocation(bubbleBarLocation);
    }

    /** Returns the x position of the center of the stashed handle. */
    public float getStashedHandleCenterX() {
        return mHandleViewController.getStashedHandleCenterX();
    }

    /** Returns the [PhysicsAnimator] for the stashed handle view. */
    public PhysicsAnimator<View> getStashedHandlePhysicsAnimator() {
        return mHandleViewController.getPhysicsAnimator();
@@ -389,4 +413,14 @@ public class BubbleStashController {
        mIsStashed = false;
        onIsStashedChanged();
    }

    /** Stashes the bubble bar immediately without animation. */
    public void stashBubbleBarImmediate() {
        mHandleViewController.setTranslationYForSwipe(0);
        mIconAlphaForStash.setValue(0);
        mIconTranslationYForStash.updateValue(getStashTranslation());
        mIconScaleForStash.updateValue(STASHED_BAR_SCALE);
        mIsStashed = true;
        onIsStashedChanged();
    }
}
+0 −5
Original line number Diff line number Diff line
@@ -251,11 +251,6 @@ public class BubbleStashedHandleViewController {
        return mStashedHandleAlpha;
    }

    /** Returns the x position of the center of the stashed handle. */
    public float getStashedHandleCenterX() {
        return mStashedHandleBounds.exactCenterX();
    }

    /**
     * Creates and returns an Animator that updates the stashed handle  shape and size.
     * When stashed, the shape is a thin rounded pill. When unstashed, the shape morphs into
Loading