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
This commit is contained in:
Josh Tsuji
2020-06-12 16:20:02 -04:00
parent 8140ae8d22
commit ee148d0bc0

View File

@@ -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,37 +1795,43 @@ public class BubbleStackView extends FrameLayout
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
}
postDelayed(() -> PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
.spring(AnimatableScaleMatrix.SCALE_X,
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
mScaleInSpringConfig)
.spring(AnimatableScaleMatrix.SCALE_Y,
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
mScaleInSpringConfig)
.addUpdateListener((target, values) -> {
if (mExpandedBubble.getIconView() == null) {
return;
}
mExpandedViewContainerMatrix.postTranslate(
mExpandedBubble.getIconView().getTranslationX()
- bubbleWillBeAtX,
0);
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
})
.withEndActions(() -> {
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
}
})
.start(), startDelay);
mDelayedAnimationHandler.postDelayed(() ->
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
.spring(AnimatableScaleMatrix.SCALE_X,
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
mScaleInSpringConfig)
.spring(AnimatableScaleMatrix.SCALE_Y,
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
mScaleInSpringConfig)
.addUpdateListener((target, values) -> {
if (mExpandedBubble.getIconView() == null) {
return;
}
mExpandedViewContainerMatrix.postTranslate(
mExpandedBubble.getIconView().getTranslationX()
- bubbleWillBeAtX,
0);
mExpandedViewContainer.setAnimationMatrix(
mExpandedViewContainerMatrix);
})
.withEndActions(() -> {
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());