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

Commit ee148d0b authored by Josh Tsuji's avatar Josh Tsuji
Browse files

Avoid bad animation states.

This ignores bubble touches during animations (they are quick, this does not feel restricting) and makes sure to cancel inflight animations if we do start another animation.

Fixes: 158722494
Fixes: 158731143
Test: manual, mash those bubbles
Change-Id: I4b38e2cd335ded1f2b873ad694f5e369be545714
parent 8140ae8d
Loading
Loading
Loading
Loading
+71 −29
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.drawable.TransitionDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.util.Log;
import android.view.Choreographer;
@@ -159,6 +160,12 @@ public class BubbleStackView extends FrameLayout
            new PhysicsAnimator.SpringConfig(
                    SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_NO_BOUNCY);

    /**
     * Handler to use for all delayed animations - this way, we can easily cancel them before
     * starting a new animation.
     */
    private final Handler mDelayedAnimationHandler = new Handler();

    /**
     * Interface to synchronize {@link View} state and the screen.
     *
@@ -293,6 +300,7 @@ public class BubbleStackView extends FrameLayout

    private boolean mViewUpdatedRequested = false;
    private boolean mIsExpansionAnimating = false;
    private boolean mIsBubbleSwitchAnimating = false;
    private boolean mShowingDismiss = false;

    /** The view to desaturate/darken when magneted to the dismiss target. */
@@ -470,6 +478,13 @@ public class BubbleStackView extends FrameLayout
    private OnClickListener mBubbleClickListener = new OnClickListener() {
        @Override
        public void onClick(View view) {
            // Bubble clicks either trigger expansion/collapse or a bubble switch, both of which we
            // shouldn't interrupt. These are quick transitions, so it's not worth trying to adjust
            // the animations inflight.
            if (mIsExpansionAnimating || mIsBubbleSwitchAnimating) {
                return;
            }

            final Bubble clickedBubble = mBubbleData.getBubbleWithView(view);

            // If the bubble has since left us, ignore the click.
@@ -1730,6 +1745,8 @@ public class BubbleStackView extends FrameLayout
    }

    private void animateExpansion() {
        cancelDelayedExpandCollapseSwitchAnimations();

        mIsExpanded = true;
        hideStackUserEducation(true /* fromExpansion */);
        beforeExpandedViewAnimation();
@@ -1778,7 +1795,8 @@ public class BubbleStackView extends FrameLayout
            mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
        }

        postDelayed(() -> PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
        mDelayedAnimationHandler.postDelayed(() ->
                        PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
                                .spring(AnimatableScaleMatrix.SCALE_X,
                                        AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
                                        mScaleInSpringConfig)
@@ -1793,22 +1811,27 @@ public class BubbleStackView extends FrameLayout
                                            mExpandedBubble.getIconView().getTranslationX()
                                                    - bubbleWillBeAtX,
                                            0);
                    mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
                                    mExpandedViewContainer.setAnimationMatrix(
                                            mExpandedViewContainerMatrix);
                                })
                                .withEndActions(() -> {
                    if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
                        mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
                                    if (mExpandedBubble != null
                                            && mExpandedBubble.getExpandedView() != null) {
                                        mExpandedBubble.getExpandedView()
                                                .setSurfaceZOrderedOnTop(false);
                                    }
                                })
                                .start(), startDelay);

    }

    private void animateCollapse() {
        cancelDelayedExpandCollapseSwitchAnimations();

        // Hide the menu if it's visible.
        showManageMenu(false);

        mIsExpanded = false;
        mIsExpansionAnimating = true;

        mBubbleContainer.cancelAllAnimations();

@@ -1824,12 +1847,10 @@ public class BubbleStackView extends FrameLayout

        final long startDelay =
                (long) (ExpandedAnimationController.EXPAND_COLLAPSE_TARGET_ANIM_DURATION * 0.6f);
        postDelayed(() -> mExpandedAnimationController.collapseBackToStack(
        mDelayedAnimationHandler.postDelayed(() -> mExpandedAnimationController.collapseBackToStack(
                mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
                /* collapseTo */,
                () -> {
                    mBubbleContainer.setActiveController(mStackAnimationController);
                }), startDelay);
                () -> mBubbleContainer.setActiveController(mStackAnimationController)), startDelay);

        // We want to visually collapse into this bubble during the animation.
        final View expandingFromBubble = mExpandedBubble.getIconView();
@@ -1884,6 +1905,13 @@ public class BubbleStackView extends FrameLayout
    }

    private void animateSwitchBubbles() {
        // If we're no longer expanded, this is meaningless.
        if (!mIsExpanded) {
            return;
        }

        mIsBubbleSwitchAnimating = true;

        // The surface contains a screenshot of the animating out bubble, so we just need to animate
        // it out (and then release the GraphicBuffer).
        PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
@@ -1909,8 +1937,9 @@ public class BubbleStackView extends FrameLayout
                0f, 0f, expandingFromBubbleDestinationX + mBubbleSize / 2f, getExpandedViewY());
        mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);

        mExpandedViewContainer.postDelayed(() -> {
        mDelayedAnimationHandler.postDelayed(() -> {
            if (!mIsExpanded) {
                mIsBubbleSwitchAnimating = false;
                return;
            }

@@ -1928,11 +1957,24 @@ public class BubbleStackView extends FrameLayout
                        if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
                            mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
                        }

                        mIsBubbleSwitchAnimating = false;
                    })
                    .start();
        }, 25);
    }

    /**
     * Cancels any delayed steps for expand/collapse and bubble switch animations, and resets the is
     * animating flags for those animations.
     */
    private void cancelDelayedExpandCollapseSwitchAnimations() {
        mDelayedAnimationHandler.removeCallbacksAndMessages(null);

        mIsExpansionAnimating = false;
        mIsBubbleSwitchAnimating = false;
    }

    private void notifyExpansionChanged(BubbleViewProvider bubble, boolean expanded) {
        if (mExpandListener != null && bubble != null) {
            mExpandListener.onBubbleExpandChanged(expanded, bubble.getKey());