Save and later cancel ViewPropertyAnimator on bubble view tag

When a bubble autoexpands (via button button)
 1) order changes and reorder animations start
 2) active controller changes from StackAnimationController to ExpandedAnimationController
 3) the stack expands
 4) PhysicalAnimationLayout doesn't find reorder animations by tag, so they don't get canceled
 5) the "swoop up" reorder animation runs right after expansion completes

This change saves StackAnimationController's reorder animators on bubble
view so that PhysicsAnimationLayout cancels it when the active
controller changes to ExpandedAnimationController.

Fixes: 171850447
Bug: 170267512
Test: manual
 1) Unbubble notif
 2) Send another bubbling notif => HUN shows
 3) Tap HUN's bubble button
     => See that bubble autoexpands without leftover reorder animation
Change-Id: Idd0543659a65fddba4b4fc5bee0ff7b9aad8b352
This commit is contained in:
Lyn Han
2020-10-28 19:26:42 -05:00
parent fa01004977
commit 465c2c07a7
3 changed files with 42 additions and 17 deletions

View File

@@ -155,6 +155,7 @@
<item type="id" name="scale_y_dynamicanimation_tag"/>
<item type="id" name="physics_animator_tag"/>
<item type="id" name="target_animator_tag" />
<item type="id" name="reorder_animator_tag"/>
<!-- Global Actions Menu -->
<item type="id" name="global_actions_view" />

View File

@@ -27,6 +27,7 @@ import android.util.FloatProperty;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
@@ -385,7 +386,7 @@ public class PhysicsAnimationLayout extends FrameLayout {
View view, DynamicAnimation.ViewProperty... properties) {
final ObjectAnimator targetAnimator = getTargetAnimatorFromView(view);
for (DynamicAnimation.ViewProperty property : properties) {
final SpringAnimation animation = getAnimationFromView(property, view);
final SpringAnimation animation = getSpringAnimationFromView(property, view);
if (animation != null && animation.isRunning()) {
return true;
}
@@ -422,11 +423,15 @@ public class PhysicsAnimationLayout extends FrameLayout {
for (int i = 0; i < getChildCount(); i++) {
for (DynamicAnimation.ViewProperty property : properties) {
final DynamicAnimation anim = getAnimationAtIndex(property, i);
final DynamicAnimation anim = getSpringAnimationAtIndex(property, i);
if (anim != null) {
anim.cancel();
}
}
final ViewPropertyAnimator anim = getViewPropertyAnimatorFromView(getChildAt(i));
if (anim != null) {
anim.cancel();
}
}
}
@@ -441,7 +446,7 @@ public class PhysicsAnimationLayout extends FrameLayout {
// Cancel physics animations on the view.
for (DynamicAnimation.ViewProperty property : mController.getAnimatedProperties()) {
final DynamicAnimation animationFromView = getAnimationFromView(property, view);
final DynamicAnimation animationFromView = getSpringAnimationFromView(property, view);
if (animationFromView != null) {
animationFromView.cancel();
}
@@ -502,17 +507,27 @@ public class PhysicsAnimationLayout extends FrameLayout {
* Retrieves the animation of the given property from the view at the given index via the view
* tag system.
*/
@Nullable private SpringAnimation getAnimationAtIndex(
@Nullable private SpringAnimation getSpringAnimationAtIndex(
DynamicAnimation.ViewProperty property, int index) {
return getAnimationFromView(property, getChildAt(index));
return getSpringAnimationFromView(property, getChildAt(index));
}
/** Retrieves the animation of the given property from the view via the view tag system. */
@Nullable private SpringAnimation getAnimationFromView(
/**
* Retrieves the spring animation of the given property from the view via the view tag system.
*/
@Nullable private SpringAnimation getSpringAnimationFromView(
DynamicAnimation.ViewProperty property, View view) {
return (SpringAnimation) view.getTag(getTagIdForProperty(property));
}
/**
* Retrieves the view property animation of the given property from the view via the view tag
* system.
*/
@Nullable private ViewPropertyAnimator getViewPropertyAnimatorFromView(View view) {
return (ViewPropertyAnimator) view.getTag(R.id.reorder_animator_tag);
}
/** Retrieves the target animator from the view via the view tag system. */
@Nullable private ObjectAnimator getTargetAnimatorFromView(View view) {
return (ObjectAnimator) view.getTag(R.id.target_animator_tag);
@@ -539,7 +554,8 @@ public class PhysicsAnimationLayout extends FrameLayout {
final float offset = mController.getOffsetForChainedPropertyAnimation(property);
if (nextAnimInChain < getChildCount()) {
final SpringAnimation nextAnim = getAnimationAtIndex(property, nextAnimInChain);
final SpringAnimation nextAnim = getSpringAnimationAtIndex(
property, nextAnimInChain);
if (nextAnim != null) {
nextAnim.animateToFinalPosition(value + offset);
}
@@ -902,9 +918,9 @@ public class PhysicsAnimationLayout extends FrameLayout {
// and TRANSLATION_Y animations ending, and call them once both have finished.
if (mPositionEndActions != null) {
final SpringAnimation translationXAnim =
getAnimationFromView(DynamicAnimation.TRANSLATION_X, mView);
getSpringAnimationFromView(DynamicAnimation.TRANSLATION_X, mView);
final SpringAnimation translationYAnim =
getAnimationFromView(DynamicAnimation.TRANSLATION_Y, mView);
getSpringAnimationFromView(DynamicAnimation.TRANSLATION_Y, mView);
final Runnable waitForBothXAndY = () -> {
if (!translationXAnim.isRunning() && !translationYAnim.isRunning()) {
if (mPositionEndActions != null) {

View File

@@ -24,6 +24,7 @@ import android.graphics.RectF;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.view.ViewPropertyAnimator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -782,11 +783,11 @@ public class StackAnimationController extends
}
}
public void animateReorder(List<View> bubbleViews, Runnable after) {
public void animateReorder(List<View> bubbleViews, Runnable after) {
for (int newIndex = 0; newIndex < bubbleViews.size(); newIndex++) {
View view = bubbleViews.get(newIndex);
final int oldIndex= mLayout.indexOfChild(view);
animateSwap(view, oldIndex, newIndex, after);
final int oldIndex = mLayout.indexOfChild(view);
animateSwap(view, oldIndex, newIndex, after);
}
}
@@ -795,12 +796,15 @@ public class StackAnimationController extends
final float swapY = newIndex == 0
? newY - mSwapAnimationOffset // Above top of stack
: newY + mSwapAnimationOffset; // Below where bubble will be
view.animate()
final ViewPropertyAnimator animator = view.animate()
.scaleX(BUBBLE_SWAP_SCALE)
.scaleY(BUBBLE_SWAP_SCALE)
.translationY(swapY)
.setDuration(BUBBLE_SWAP_DURATION)
.withEndAction(() -> finishSwapAnimation(view, oldIndex, newIndex, finishReorder));
.withEndAction(() -> {
finishSwapAnimation(view, oldIndex, newIndex, finishReorder);
});
view.setTag(R.id.reorder_animator_tag, animator);
}
private void finishSwapAnimation(View view, int oldIndex, int newIndex,
@@ -818,12 +822,16 @@ public class StackAnimationController extends
// Animate bubble back into stack, at new index and original size.
final float newY = getStackPosition().y + newIndex * mStackOffset;
view.animate()
final ViewPropertyAnimator animator = view.animate()
.scaleX(1f)
.scaleY(1f)
.translationY(newY)
.setDuration(BUBBLE_SWAP_DURATION)
.withEndAction(() -> finishReorder.run());
.withEndAction(() -> {
view.setTag(R.id.reorder_animator_tag, null);
finishReorder.run();
});
view.setTag(R.id.reorder_animator_tag, animator);
}
@Override