Adds new motion animation for U popups
Bug: b/247880037
Test: manually on tablet
Change-Id: I8677cef39a5dc4094cad38f42b9314ac37b95fc2
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index 0da70a9..428bd95 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -75,6 +75,7 @@
clipToOutline = true
shouldScaleArrow = true
+ mIsArrowRotated = true
// This synchronizes the arrow and menu to open at the same time
OPEN_CHILD_FADE_START_DELAY = OPEN_FADE_START_DELAY
OPEN_CHILD_FADE_DURATION = OPEN_FADE_DURATION
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index c23ea8a..a0f21dc 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -20,6 +20,8 @@
import static com.android.launcher3.anim.Interpolators.ACCELERATED_EASE;
import static com.android.launcher3.anim.Interpolators.DECELERATED_EASE;
+import static com.android.launcher3.anim.Interpolators.EMPHASIZED_ACCELERATE;
+import static com.android.launcher3.anim.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
@@ -37,11 +39,13 @@
import android.graphics.drawable.GradientDrawable;
import android.util.AttributeSet;
import android.util.Pair;
+import android.util.Property;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
@@ -81,6 +85,19 @@
protected int CLOSE_CHILD_FADE_START_DELAY = 0;
protected int CLOSE_CHILD_FADE_DURATION = 140;
+ private static final int OPEN_DURATION_U = 200;
+ private static final int OPEN_FADE_START_DELAY_U = 0;
+ private static final int OPEN_FADE_DURATION_U = 83;
+ private static final int OPEN_CHILD_FADE_START_DELAY_U = 0;
+ private static final int OPEN_CHILD_FADE_DURATION_U = 83;
+ private static final int OPEN_OVERSHOOT_DURATION_U = 200;
+
+ private static final int CLOSE_DURATION_U = 233;
+ private static final int CLOSE_FADE_START_DELAY_U = 150;
+ private static final int CLOSE_FADE_DURATION_U = 83;
+ private static final int CLOSE_CHILD_FADE_START_DELAY_U = 150;
+ private static final int CLOSE_CHILD_FADE_DURATION_U = 83;
+
protected final Rect mTempRect = new Rect();
protected final LayoutInflater mInflater;
@@ -104,6 +121,7 @@
protected AnimatorSet mOpenCloseAnimator;
protected boolean mDeferContainerRemoval;
protected boolean shouldScaleArrow = false;
+ protected boolean mIsArrowRotated = false;
private final GradientDrawable mRoundedTop;
private final GradientDrawable mRoundedBottom;
@@ -591,10 +609,24 @@
protected void animateOpen() {
setVisibility(View.VISIBLE);
+ mOpenCloseAnimator = ENABLE_MATERIAL_U_POPUP.get()
+ ? getMaterialUOpenCloseAnimator(
+ true,
+ OPEN_DURATION_U,
+ OPEN_FADE_START_DELAY_U,
+ OPEN_FADE_DURATION_U,
+ OPEN_CHILD_FADE_START_DELAY_U,
+ OPEN_CHILD_FADE_DURATION_U,
+ EMPHASIZED_DECELERATE)
+ : getOpenCloseAnimator(
+ true,
+ OPEN_DURATION,
+ OPEN_FADE_START_DELAY,
+ OPEN_FADE_DURATION,
+ OPEN_CHILD_FADE_START_DELAY,
+ OPEN_CHILD_FADE_DURATION,
+ DECELERATED_EASE);
- mOpenCloseAnimator = getOpenCloseAnimator(true, OPEN_DURATION, OPEN_FADE_START_DELAY,
- OPEN_FADE_DURATION, OPEN_CHILD_FADE_START_DELAY, OPEN_CHILD_FADE_DURATION,
- DECELERATED_EASE);
onCreateOpenAnimation(mOpenCloseAnimator);
mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -680,6 +712,24 @@
mOpenCloseAnimator = getOpenCloseAnimator(false, CLOSE_DURATION, CLOSE_FADE_START_DELAY,
CLOSE_FADE_DURATION, CLOSE_CHILD_FADE_START_DELAY, CLOSE_CHILD_FADE_DURATION,
ACCELERATED_EASE);
+
+ mOpenCloseAnimator = ENABLE_MATERIAL_U_POPUP.get()
+ ? getMaterialUOpenCloseAnimator(
+ false,
+ CLOSE_DURATION_U,
+ CLOSE_FADE_START_DELAY_U,
+ CLOSE_FADE_DURATION_U,
+ CLOSE_CHILD_FADE_START_DELAY_U,
+ CLOSE_CHILD_FADE_DURATION_U,
+ EMPHASIZED_ACCELERATE)
+ : getOpenCloseAnimator(false,
+ CLOSE_DURATION,
+ CLOSE_FADE_START_DELAY,
+ CLOSE_FADE_DURATION,
+ CLOSE_CHILD_FADE_START_DELAY,
+ CLOSE_CHILD_FADE_DURATION,
+ ACCELERATED_EASE);
+
onCreateCloseAnimation(mOpenCloseAnimator);
mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -695,6 +745,59 @@
mOpenCloseAnimator.start();
}
+ protected AnimatorSet getMaterialUOpenCloseAnimator(boolean isOpening, int scaleDuration,
+ int fadeStartDelay, int fadeDuration, int childFadeStartDelay, int childFadeDuration,
+ Interpolator interpolator) {
+
+ int arrowCenter = mArrowOffsetHorizontal + mArrowWidth / 2;
+ if (mIsArrowRotated) {
+ setPivotX(mIsLeftAligned ? 0f : getMeasuredWidth());
+ setPivotY(arrowCenter);
+ } else {
+ setPivotX(mIsLeftAligned ? arrowCenter : getMeasuredWidth() - arrowCenter);
+ setPivotY(mIsAboveIcon ? getMeasuredHeight() : 0f);
+ }
+
+ float[] alphaValues = isOpening ? new float[] {0, 1} : new float[] {1, 0};
+ float[] scaleValues = isOpening ? new float[] {0.5f, 1.02f} : new float[] {1f, 0.5f};
+ Animator alpha = getAnimatorOfFloat(this, View.ALPHA, fadeDuration, fadeStartDelay,
+ LINEAR, alphaValues);
+ Animator arrowAlpha = getAnimatorOfFloat(mArrow, View.ALPHA, fadeDuration, fadeStartDelay,
+ LINEAR, alphaValues);
+ Animator scaleY = getAnimatorOfFloat(this, View.SCALE_Y, scaleDuration, 0, interpolator,
+ scaleValues);
+ Animator scaleX = getAnimatorOfFloat(this, View.SCALE_X, scaleDuration, 0, interpolator,
+ scaleValues);
+
+ final AnimatorSet animatorSet = new AnimatorSet();
+ if (isOpening) {
+ float[] scaleValuesOvershoot = new float[] {1.02f, 1f};
+ PathInterpolator overshootInterpolator = new PathInterpolator(0.3f, 0, 0.33f, 1f);
+ Animator overshootY = getAnimatorOfFloat(this, View.SCALE_Y,
+ OPEN_OVERSHOOT_DURATION_U, scaleDuration, overshootInterpolator,
+ scaleValuesOvershoot);
+ Animator overshootX = getAnimatorOfFloat(this, View.SCALE_X,
+ OPEN_OVERSHOOT_DURATION_U, scaleDuration, overshootInterpolator,
+ scaleValuesOvershoot);
+
+ animatorSet.playTogether(alpha, arrowAlpha, scaleY, scaleX, overshootX, overshootY);
+ } else {
+ animatorSet.playTogether(alpha, arrowAlpha, scaleY, scaleX);
+ }
+
+ fadeInChildViews(this, alphaValues, childFadeStartDelay, childFadeDuration, animatorSet);
+ return animatorSet;
+ }
+
+ private Animator getAnimatorOfFloat(View view, Property<View, Float> property,
+ int duration, int startDelay, Interpolator interpolator, float... values) {
+ Animator animator = ObjectAnimator.ofFloat(view, property, values);
+ animator.setDuration(duration);
+ animator.setInterpolator(interpolator);
+ animator.setStartDelay(startDelay);
+ return animator;
+ }
+
/**
* Called when creating the open transition allowing subclass can add additional animations.
*/