New motion for ArrowPopup open/close.
Bug: 175329686
Test: long press on apps where container opens above & below
and where container is aligned left & right
Change-Id: I09bbf57b6e19cc6f022b9a96fb48d8c4ae080813
diff --git a/res/values/config.xml b/res/values/config.xml
index 9ad1224..2e5ecba 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -77,11 +77,6 @@
<!-- Menu id for feature flags -->
<item type="id" name="menu_apply_flags" />
- <!-- Popup items -->
- <integer name="config_popupOpenCloseDuration">150</integer>
- <integer name="config_popupArrowOpenCloseDuration">40</integer>
- <integer name="config_removeNotificationViewDuration">300</integer>
-
<!-- Default packages -->
<string name="wallpaper_picker_package" translatable="false"></string>
<string name="local_colors_extraction_class" translatable="false"></string>
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 11e831e..9d73bba 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -53,6 +53,9 @@
public static final Interpolator AGGRESSIVE_EASE = new PathInterpolator(0.2f, 0f, 0f, 1f);
public static final Interpolator AGGRESSIVE_EASE_IN_OUT = new PathInterpolator(0.6f,0, 0.4f, 1);
+ public static final Interpolator DECELERATED_EASE = new PathInterpolator(0, 0, .2f, 1f);
+ public static final Interpolator ACCELERATED_EASE = new PathInterpolator(0.4f, 0, 1f, 1f);
+
public static final Interpolator EXAGGERATED_EASE;
public static final Interpolator INSTANT = t -> 1;
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index c63d69d..115f718 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -16,7 +16,9 @@
package com.android.launcher3.popup;
-import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
+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.LINEAR;
import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
import android.animation.Animator;
@@ -24,7 +26,6 @@
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
@@ -42,6 +43,7 @@
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
+import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
@@ -51,13 +53,10 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
-import com.android.launcher3.anim.RevealOutlineAnimation;
-import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.statemanager.StatefulActivity;
@@ -77,6 +76,19 @@
public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
extends AbstractFloatingView {
+ // Duration values (ms) for popup open and close animations.
+ private static final int OPEN_DURATION = 276;
+ private static final int OPEN_FADE_START_DELAY = 0;
+ private static final int OPEN_FADE_DURATION = 38;
+ private static final int OPEN_CHILD_FADE_START_DELAY = 38;
+ private static final int OPEN_CHILD_FADE_DURATION = 76;
+
+ private static final int CLOSE_DURATION = 200;
+ private static final int CLOSE_FADE_START_DELAY = 140;
+ private static final int CLOSE_FADE_DURATION = 50;
+ private static final int CLOSE_CHILD_FADE_START_DELAY = 0;
+ private static final int CLOSE_CHILD_FADE_DURATION = 140;
+
// +1 for system shortcut view
private static final int MAX_NUM_CHILDREN = MAX_SHORTCUTS + 1;
// Index used to get background color when using local wallpaper color extraction,
@@ -103,10 +115,8 @@
protected boolean mIsAboveIcon;
private int mGravity;
- protected Animator mOpenCloseAnimator;
+ protected AnimatorSet mOpenCloseAnimator;
protected boolean mDeferContainerRemoval;
- private final Rect mStartRect = new Rect();
- private final Rect mEndRect = new Rect();
private final GradientDrawable mRoundedTop;
private final GradientDrawable mRoundedBottom;
@@ -557,48 +567,13 @@
return getChildCount() > 0 ? getChildAt(0) : this;
}
- private int getArrowDuration() {
- return shouldAddArrow()
- ? getResources().getInteger(R.integer.config_popupArrowOpenCloseDuration)
- : 0;
- }
-
private void animateOpen() {
setVisibility(View.VISIBLE);
- final AnimatorSet openAnim = new AnimatorSet();
- final Resources res = getResources();
- final long revealDuration = (long) res.getInteger(R.integer.config_popupOpenCloseDuration);
- final long arrowDuration = getArrowDuration();
- final TimeInterpolator revealInterpolator = ACCEL_DEACCEL;
-
- // Rectangular reveal.
- mEndRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
- final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
- .createRevealAnimator(this, false);
- revealAnim.setDuration(revealDuration);
- revealAnim.setInterpolator(revealInterpolator);
- // Clip the popup to the initial outline while the notification dot and arrow animate.
- revealAnim.start();
- revealAnim.pause();
-
- ValueAnimator fadeIn = ValueAnimator.ofFloat(0, 1);
- fadeIn.setDuration(revealDuration + arrowDuration);
- fadeIn.setInterpolator(revealInterpolator);
- fadeIn.addUpdateListener(anim -> {
- float alpha = (float) anim.getAnimatedValue();
- mArrow.setAlpha(alpha);
- setAlpha(revealAnim.isStarted() ? alpha : 0);
- });
- openAnim.play(fadeIn);
-
- // Animate the arrow.
- mArrow.setScaleX(0);
- mArrow.setScaleY(0);
- Animator arrowScale = ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 1)
- .setDuration(arrowDuration);
-
- openAnim.addListener(new AnimatorListenerAdapter() {
+ mOpenCloseAnimator = getOpenCloseAnimator(true, OPEN_DURATION, OPEN_FADE_START_DELAY,
+ OPEN_FADE_DURATION, OPEN_CHILD_FADE_START_DELAY, OPEN_CHILD_FADE_DURATION,
+ DECELERATED_EASE);
+ mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
setAlpha(1f);
@@ -606,56 +581,68 @@
mOpenCloseAnimator = null;
}
});
-
- mOpenCloseAnimator = openAnim;
- openAnim.playSequentially(arrowScale, revealAnim);
- openAnim.start();
+ mOpenCloseAnimator.start();
}
+ private AnimatorSet getOpenCloseAnimator(boolean isOpening, int totalDuration,
+ int fadeStartDelay, int fadeDuration, int childFadeStartDelay,
+ int childFadeDuration, Interpolator interpolator) {
+ final AnimatorSet openAnim = new AnimatorSet();
+ float[] alphaValues = isOpening ? new float[] {0, 1} : new float[] {1, 0};
+ float[] scaleValues = isOpening ? new float[] {0.5f, 1} : new float[] {1, 0.5f};
+
+ ValueAnimator fade = ValueAnimator.ofFloat(alphaValues);
+ fade.setStartDelay(fadeStartDelay);
+ fade.setDuration(fadeDuration);
+ fade.setInterpolator(LINEAR);
+ fade.addUpdateListener(anim -> {
+ float alpha = (float) anim.getAnimatedValue();
+ mArrow.setAlpha(alpha);
+ setAlpha(alpha);
+ });
+ openAnim.play(fade);
+
+ setPivotX(mIsLeftAligned ? 0 : getMeasuredWidth());
+ setPivotY(mIsAboveIcon ? getMeasuredHeight() : 0);
+ Animator scale = ObjectAnimator.ofFloat(this, View.SCALE_Y, scaleValues);
+ scale.setDuration(totalDuration);
+ scale.setInterpolator(interpolator);
+ openAnim.play(scale);
+
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ View view = getChildAt(i);
+ if (view.getVisibility() == VISIBLE && view instanceof ViewGroup) {
+ for (int j = ((ViewGroup) view).getChildCount() - 1; j >= 0; --j) {
+ View childView = ((ViewGroup) view).getChildAt(j);
+
+ childView.setAlpha(alphaValues[0]);
+ ValueAnimator childFade = ObjectAnimator.ofFloat(childView, ALPHA, alphaValues);
+ childFade.setStartDelay(childFadeStartDelay);
+ childFade.setDuration(childFadeDuration);
+ childFade.setInterpolator(LINEAR);
+
+ openAnim.play(childFade);
+ }
+ }
+ }
+ return openAnim;
+ }
+
+
protected void animateClose() {
if (!mIsOpen) {
return;
}
- if (getOutlineProvider() instanceof RevealOutlineAnimation) {
- ((RevealOutlineAnimation) getOutlineProvider()).getOutline(mEndRect);
- } else {
- mEndRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
- }
if (mOpenCloseAnimator != null) {
mOpenCloseAnimator.cancel();
}
mIsOpen = false;
-
- final AnimatorSet closeAnim = new AnimatorSet();
- final Resources res = getResources();
- final TimeInterpolator revealInterpolator = ACCEL_DEACCEL;
- final long revealDuration = res.getInteger(R.integer.config_popupOpenCloseDuration);
- final long arrowDuration = getArrowDuration();
-
- // Hide the arrow
- Animator scaleArrow = ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 0)
- .setDuration(arrowDuration);
-
- // Rectangular reveal (reversed).
- final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
- .createRevealAnimator(this, true);
- revealAnim.setDuration(revealDuration);
- revealAnim.setInterpolator(revealInterpolator);
- closeAnim.playSequentially(revealAnim, scaleArrow);
-
- ValueAnimator fadeOut = ValueAnimator.ofFloat(getAlpha(), 0);
- fadeOut.setDuration(revealDuration + arrowDuration);
- fadeOut.setInterpolator(revealInterpolator);
- fadeOut.addUpdateListener(anim -> {
- float alpha = (float) anim.getAnimatedValue();
- mArrow.setAlpha(alpha);
- setAlpha(scaleArrow.isStarted() ? 0 : alpha);
- });
- closeAnim.play(fadeOut);
-
- onCreateCloseAnimation(closeAnim);
- closeAnim.addListener(new AnimatorListenerAdapter() {
+ mOpenCloseAnimator = 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
public void onAnimationEnd(Animator animation) {
mOpenCloseAnimator = null;
@@ -666,8 +653,7 @@
}
}
});
- mOpenCloseAnimator = closeAnim;
- closeAnim.start();
+ mOpenCloseAnimator.start();
}
/**
@@ -675,16 +661,6 @@
*/
protected void onCreateCloseAnimation(AnimatorSet anim) { }
- private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
- int arrowLeft = getArrowLeft();
- int arrowCenterY = mIsAboveIcon ? getMeasuredHeight() : 0;
-
- mStartRect.set(arrowLeft, arrowCenterY, arrowLeft + mArrowWidth, arrowCenterY);
-
- return new RoundedRectRevealOutlineProvider(
- mArrowPointRadius, mOutlineRadius, mStartRect, mEndRect);
- }
-
/**
* Closes the popup without animation.
*/