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:
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user