Fix issue with IconAppChipView animated states
Cancel in progress animations and resume from previous position.
Display TaskMenuView once.
Fixes: 322813710
Test: Manual
Flag: ACONFIG com.android.launcher3.enable_overview_icon_menu TEAMFOOD
Change-Id: I73410d6116876ca83f3b16311d2e9eb372308295
diff --git a/quickstep/src/com/android/quickstep/views/IconAppChipView.java b/quickstep/src/com/android/quickstep/views/IconAppChipView.java
index ee09c4d..b064405 100644
--- a/quickstep/src/com/android/quickstep/views/IconAppChipView.java
+++ b/quickstep/src/com/android/quickstep/views/IconAppChipView.java
@@ -86,6 +86,7 @@
private final int mMinIconBackgroundHeight;
private final int mMaxIconBackgroundCornerRadius;
private final float mMinIconBackgroundCornerRadius;
+ private AnimatorSet mAnimator;
private int mMaxWidth = Integer.MAX_VALUE;
@@ -315,11 +316,13 @@
}
protected void revealAnim(boolean isRevealing) {
+ cancelInProgressAnimations();
+
if (isRevealing) {
boolean isRtl = isLayoutRtl();
bringToFront();
((AnimatedVectorDrawable) mIconArrowView.getDrawable()).start();
- AnimatorSet anim = new AnimatorSet();
+ mAnimator = new AnimatorSet();
float backgroundScaleY = mMaxIconBackgroundHeight / (float) mMinIconBackgroundHeight;
float maxCornerSize = Math.min(mMaxIconBackgroundHeight / 2f,
mMaxIconBackgroundCornerRadius);
@@ -340,7 +343,7 @@
mIconTextMaxWidth + maxCornerSize);
}
});
- anim.playTogether(
+ mAnimator.playTogether(
expandedTextRevealAnim,
ObjectAnimator.ofFloat(mIconViewBackgroundCornersStart, SCALE_Y,
backgroundScaleY),
@@ -366,9 +369,9 @@
ObjectAnimator.ofFloat(mIconTextExpandedView, ALPHA, 1),
ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X,
isRtl ? -arrowTranslationX : arrowTranslationX));
- anim.setDuration(MENU_BACKGROUND_REVEAL_DURATION);
- anim.setInterpolator(EMPHASIZED);
- anim.start();
+ mAnimator.setDuration(MENU_BACKGROUND_REVEAL_DURATION);
+ mAnimator.setInterpolator(EMPHASIZED);
+ mAnimator.start();
} else {
((AnimatedVectorDrawable) mIconArrowView.getDrawable()).reverse();
float maxCornerSize = Math.min(mMaxIconBackgroundHeight / 2f,
@@ -385,8 +388,8 @@
mIconTextExpandedView.getHeight() / 2f, 0);
}
});
- AnimatorSet anim = new AnimatorSet();
- anim.playTogether(
+ mAnimator = new AnimatorSet();
+ mAnimator.playTogether(
expandedTextClipAnim,
ObjectAnimator.ofFloat(mIconViewBackgroundCornersStart, SCALE_X, 1),
ObjectAnimator.ofFloat(mIconViewBackgroundCornersStart, SCALE_Y, 1),
@@ -402,9 +405,9 @@
ObjectAnimator.ofFloat(mIconTextCollapsedView, ALPHA, 1),
ObjectAnimator.ofFloat(mIconTextExpandedView, ALPHA, 0),
ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X, 0));
- anim.setDuration(MENU_BACKGROUND_HIDE_DURATION);
- anim.setInterpolator(EMPHASIZED);
- anim.start();
+ mAnimator.setDuration(MENU_BACKGROUND_HIDE_DURATION);
+ mAnimator.setInterpolator(EMPHASIZED);
+ mAnimator.start();
}
}
@@ -424,6 +427,16 @@
mIconTextExpandedView.setAlpha(0);
mIconArrowView.setTranslationX(0);
((AnimatedVectorDrawable) mIconArrowView.getDrawable()).reset();
+ mAnimator = null;
+ }
+
+ private void cancelInProgressAnimations() {
+ // We null the `AnimatorSet` because it holds references to the `Animators` which aren't
+ // expecting to be mutable and will cause a crash if they are re-used.
+ if (mAnimator != null && mAnimator.isStarted()) {
+ mAnimator.cancel();
+ mAnimator = null;
+ }
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 77033b2..3a4056a 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -24,6 +24,7 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Outline;
import android.graphics.Rect;
@@ -69,6 +70,8 @@
private TextView mTaskName;
@Nullable
private AnimatorSet mOpenCloseAnimator;
+ @Nullable
+ private ValueAnimator mRevealAnimator;
@Nullable private Runnable mOnClosingStartCallback;
private TaskView mTaskView;
private TaskIdAttributeContainer mTaskContainer;
@@ -289,13 +292,18 @@
private void animateOpenOrClosed(boolean closing) {
if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
- mOpenCloseAnimator.end();
+ mOpenCloseAnimator.cancel();
}
mOpenCloseAnimator = new AnimatorSet();
-
- final Animator revealAnimator = createOpenCloseOutlineProvider()
- .createRevealAnimator(this, closing);
- revealAnimator.setInterpolator(enableOverviewIconMenu() ? Interpolators.EMPHASIZED
+ // If we're opening, we just start from the beginning as a new `TaskMenuView` is created
+ // each time we do the open animation so there will never be a partial value here.
+ float revealAnimationStartProgress = 0f;
+ if (closing && mRevealAnimator != null) {
+ revealAnimationStartProgress = 1f - mRevealAnimator.getAnimatedFraction();
+ }
+ mRevealAnimator = createOpenCloseOutlineProvider()
+ .createRevealAnimator(this, closing, revealAnimationStartProgress);
+ mRevealAnimator.setInterpolator(enableOverviewIconMenu() ? Interpolators.EMPHASIZED
: Interpolators.DECELERATE);
if (enableOverviewIconMenu()) {
@@ -348,7 +356,7 @@
mOpenCloseAnimator.playTogether(translationXAnim, menuTranslationXAnim);
}
- mOpenCloseAnimator.playTogether(revealAnimator,
+ mOpenCloseAnimator.playTogether(mRevealAnimator,
ObjectAnimator.ofFloat(
mTaskContainer.getThumbnailView(), DIM_ALPHA,
closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA),
@@ -377,6 +385,7 @@
mIsOpen = false;
resetOverviewIconMenu();
mActivity.getDragLayer().removeView(this);
+ mRevealAnimator = null;
}
private void resetOverviewIconMenu() {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index f2c0286..65020bc 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -1137,9 +1137,8 @@
DeviceProfile dp = mActivity.getDeviceProfile();
if (enableOverviewIconMenu() && iconView instanceof IconAppChipView) {
((IconAppChipView) iconView).revealAnim(/* isRevealing= */ true);
- return TaskMenuView.showForTask(menuContainer, () -> {
- ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ false);
- });
+ return TaskMenuView.showForTask(menuContainer,
+ () -> ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ false));
} else if (dp.isTablet) {
int alignedOptionIndex = 0;
if (getRecentsView().isOnGridBottomRow(menuContainer.getTaskView()) && dp.isLandscape) {