Merge "Avoid bad animation states." into rvc-dev

This commit is contained in:
Josh Tsuji
2020-06-14 20:00:56 +00:00
committed by Android (Google) Code Review

View File

@@ -49,6 +49,7 @@ import android.graphics.RectF;
import android.graphics.Region; import android.graphics.Region;
import android.graphics.drawable.TransitionDrawable; import android.graphics.drawable.TransitionDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings; import android.provider.Settings;
import android.util.Log; import android.util.Log;
import android.view.Choreographer; import android.view.Choreographer;
@@ -158,6 +159,12 @@ public class BubbleStackView extends FrameLayout
new PhysicsAnimator.SpringConfig( new PhysicsAnimator.SpringConfig(
SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_NO_BOUNCY); 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. * Interface to synchronize {@link View} state and the screen.
* *
@@ -292,6 +299,7 @@ public class BubbleStackView extends FrameLayout
private boolean mViewUpdatedRequested = false; private boolean mViewUpdatedRequested = false;
private boolean mIsExpansionAnimating = false; private boolean mIsExpansionAnimating = false;
private boolean mIsBubbleSwitchAnimating = false;
private boolean mShowingDismiss = false; private boolean mShowingDismiss = false;
/** The view to desaturate/darken when magneted to the dismiss target. */ /** The view to desaturate/darken when magneted to the dismiss target. */
@@ -469,6 +477,13 @@ public class BubbleStackView extends FrameLayout
private OnClickListener mBubbleClickListener = new OnClickListener() { private OnClickListener mBubbleClickListener = new OnClickListener() {
@Override @Override
public void onClick(View view) { 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); final Bubble clickedBubble = mBubbleData.getBubbleWithView(view);
// If the bubble has since left us, ignore the click. // If the bubble has since left us, ignore the click.
@@ -1732,6 +1747,8 @@ public class BubbleStackView extends FrameLayout
} }
private void animateExpansion() { private void animateExpansion() {
cancelDelayedExpandCollapseSwitchAnimations();
mIsExpanded = true; mIsExpanded = true;
hideStackUserEducation(true /* fromExpansion */); hideStackUserEducation(true /* fromExpansion */);
beforeExpandedViewAnimation(); beforeExpandedViewAnimation();
@@ -1780,37 +1797,43 @@ public class BubbleStackView extends FrameLayout
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false); mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
} }
postDelayed(() -> PhysicsAnimator.getInstance(mExpandedViewContainerMatrix) mDelayedAnimationHandler.postDelayed(() ->
.spring(AnimatableScaleMatrix.SCALE_X, PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f), .spring(AnimatableScaleMatrix.SCALE_X,
mScaleInSpringConfig) AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
.spring(AnimatableScaleMatrix.SCALE_Y, mScaleInSpringConfig)
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f), .spring(AnimatableScaleMatrix.SCALE_Y,
mScaleInSpringConfig) AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
.addUpdateListener((target, values) -> { mScaleInSpringConfig)
if (mExpandedBubble.getIconView() == null) { .addUpdateListener((target, values) -> {
return; if (mExpandedBubble.getIconView() == null) {
} return;
mExpandedViewContainerMatrix.postTranslate( }
mExpandedBubble.getIconView().getTranslationX() mExpandedViewContainerMatrix.postTranslate(
- bubbleWillBeAtX, mExpandedBubble.getIconView().getTranslationX()
0); - bubbleWillBeAtX,
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix); 0);
}) mExpandedViewContainer.setAnimationMatrix(
.withEndActions(() -> { mExpandedViewContainerMatrix);
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) { })
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false); .withEndActions(() -> {
} if (mExpandedBubble != null
}) && mExpandedBubble.getExpandedView() != null) {
.start(), startDelay); mExpandedBubble.getExpandedView()
.setSurfaceZOrderedOnTop(false);
}
})
.start(), startDelay);
} }
private void animateCollapse() { private void animateCollapse() {
cancelDelayedExpandCollapseSwitchAnimations();
// Hide the menu if it's visible. // Hide the menu if it's visible.
showManageMenu(false); showManageMenu(false);
mIsExpanded = false; mIsExpanded = false;
mIsExpansionAnimating = true;
mBubbleContainer.cancelAllAnimations(); mBubbleContainer.cancelAllAnimations();
@@ -1830,12 +1853,10 @@ public class BubbleStackView extends FrameLayout
final long startDelay = final long startDelay =
(long) (ExpandedAnimationController.EXPAND_COLLAPSE_TARGET_ANIM_DURATION * 0.6f); (long) (ExpandedAnimationController.EXPAND_COLLAPSE_TARGET_ANIM_DURATION * 0.6f);
postDelayed(() -> mExpandedAnimationController.collapseBackToStack( mDelayedAnimationHandler.postDelayed(() -> mExpandedAnimationController.collapseBackToStack(
mStackAnimationController.getStackPositionAlongNearestHorizontalEdge() mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
/* collapseTo */, /* collapseTo */,
() -> { () -> mBubbleContainer.setActiveController(mStackAnimationController)), startDelay);
mBubbleContainer.setActiveController(mStackAnimationController);
}), startDelay);
// We want to visually collapse into this bubble during the animation. // We want to visually collapse into this bubble during the animation.
final View expandingFromBubble = mExpandedBubble.getIconView(); final View expandingFromBubble = mExpandedBubble.getIconView();
@@ -1890,6 +1911,13 @@ public class BubbleStackView extends FrameLayout
} }
private void animateSwitchBubbles() { 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 // The surface contains a screenshot of the animating out bubble, so we just need to animate
// it out (and then release the GraphicBuffer). // it out (and then release the GraphicBuffer).
PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel(); PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
@@ -1915,8 +1943,9 @@ public class BubbleStackView extends FrameLayout
0f, 0f, expandingFromBubbleDestinationX + mBubbleSize / 2f, getExpandedViewY()); 0f, 0f, expandingFromBubbleDestinationX + mBubbleSize / 2f, getExpandedViewY());
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix); mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
mExpandedViewContainer.postDelayed(() -> { mDelayedAnimationHandler.postDelayed(() -> {
if (!mIsExpanded) { if (!mIsExpanded) {
mIsBubbleSwitchAnimating = false;
return; return;
} }
@@ -1934,11 +1963,24 @@ public class BubbleStackView extends FrameLayout
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) { if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false); mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
} }
mIsBubbleSwitchAnimating = false;
}) })
.start(); .start();
}, 25); }, 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) { private void notifyExpansionChanged(BubbleViewProvider bubble, boolean expanded) {
if (mExpandListener != null && bubble != null) { if (mExpandListener != null && bubble != null) {
mExpandListener.onBubbleExpandChanged(expanded, bubble.getKey()); mExpandListener.onBubbleExpandChanged(expanded, bubble.getKey());