Merge "Use spring animation for Notification SnapBack" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
04262328d5
@@ -16,6 +16,10 @@
|
||||
|
||||
package com.android.systemui;
|
||||
|
||||
import static androidx.dynamicanimation.animation.DynamicAnimation.TRANSLATION_X;
|
||||
import static androidx.dynamicanimation.animation.DynamicAnimation.TRANSLATION_Y;
|
||||
import static androidx.dynamicanimation.animation.FloatPropertyCompat.createFloatPropertyCompat;
|
||||
|
||||
import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -40,6 +44,7 @@ import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.internal.dynamicanimation.animation.SpringForce;
|
||||
import com.android.systemui.animation.Interpolators;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
@@ -47,14 +52,14 @@ import com.android.systemui.plugins.FalsingManager;
|
||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
import com.android.wm.shell.animation.FlingAnimationUtils;
|
||||
import com.android.wm.shell.animation.PhysicsAnimator;
|
||||
import com.android.wm.shell.animation.PhysicsAnimator.SpringConfig;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class SwipeHelper implements Gefingerpoken {
|
||||
static final String TAG = "com.android.systemui.SwipeHelper";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean DEBUG_INVALIDATE = false;
|
||||
private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
|
||||
private static final boolean CONSTRAIN_SWIPE = true;
|
||||
private static final boolean FADE_OUT_DURING_SWIPE = true;
|
||||
private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;
|
||||
@@ -66,7 +71,6 @@ public class SwipeHelper implements Gefingerpoken {
|
||||
private static final int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
|
||||
private static final int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
|
||||
private static final int MAX_DISMISS_VELOCITY = 4000; // dp/sec
|
||||
private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
|
||||
|
||||
public static final float SWIPE_PROGRESS_FADE_END = 0.6f; // fraction of thumbnail width
|
||||
// beyond which swipe progress->0
|
||||
@@ -78,6 +82,9 @@ public class SwipeHelper implements Gefingerpoken {
|
||||
private float mMinSwipeProgress = 0f;
|
||||
private float mMaxSwipeProgress = 1f;
|
||||
|
||||
private final SpringConfig mSnapBackSpringConfig =
|
||||
new SpringConfig(SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
|
||||
|
||||
private final FlingAnimationUtils mFlingAnimationUtils;
|
||||
private float mPagingTouchSlop;
|
||||
private final float mSlopMultiplier;
|
||||
@@ -188,23 +195,27 @@ public class SwipeHelper implements Gefingerpoken {
|
||||
vt.getYVelocity();
|
||||
}
|
||||
|
||||
protected ObjectAnimator createTranslationAnimation(View v, float newPos) {
|
||||
ObjectAnimator anim = ObjectAnimator.ofFloat(v,
|
||||
mSwipeDirection == X ? View.TRANSLATION_X : View.TRANSLATION_Y, newPos);
|
||||
return anim;
|
||||
}
|
||||
|
||||
private float getPerpendicularVelocity(VelocityTracker vt) {
|
||||
return mSwipeDirection == X ? vt.getYVelocity() :
|
||||
vt.getXVelocity();
|
||||
}
|
||||
|
||||
protected Animator getViewTranslationAnimator(View v, float target,
|
||||
protected Animator getViewTranslationAnimator(View view, float target,
|
||||
AnimatorUpdateListener listener) {
|
||||
ObjectAnimator anim = createTranslationAnimation(v, target);
|
||||
|
||||
cancelSnapbackAnimation(view);
|
||||
|
||||
if (view instanceof ExpandableNotificationRow) {
|
||||
return ((ExpandableNotificationRow) view).getTranslateViewAnimator(target, listener);
|
||||
}
|
||||
|
||||
return createTranslationAnimation(view, target, listener);
|
||||
}
|
||||
|
||||
protected Animator createTranslationAnimation(View view, float newPos,
|
||||
AnimatorUpdateListener listener) {
|
||||
ObjectAnimator anim = ObjectAnimator.ofFloat(view,
|
||||
mSwipeDirection == X ? View.TRANSLATION_X : View.TRANSLATION_Y, newPos);
|
||||
|
||||
if (listener != null) {
|
||||
anim.addUpdateListener(listener);
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
@@ -327,6 +338,7 @@ public class SwipeHelper implements Gefingerpoken {
|
||||
mTouchedView = mCallback.getChildAtPosition(ev);
|
||||
|
||||
if (mTouchedView != null) {
|
||||
cancelSnapbackAnimation(mTouchedView);
|
||||
onDownUpdate(mTouchedView, ev);
|
||||
mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mTouchedView);
|
||||
mVelocityTracker.addMovement(ev);
|
||||
@@ -526,47 +538,59 @@ public class SwipeHelper implements Gefingerpoken {
|
||||
}
|
||||
|
||||
/**
|
||||
* After snapChild() and related animation finished, this function will be called.
|
||||
* Starts a snapback animation and cancels any previous translate animations on the given view.
|
||||
*
|
||||
* @param animView view to animate
|
||||
* @param targetLeft the end position of the translation
|
||||
* @param velocity the initial velocity of the animation
|
||||
*/
|
||||
protected void onSnapChildWithAnimationFinished() {}
|
||||
|
||||
public void snapChild(final View animView, final float targetLeft, float velocity) {
|
||||
protected void snapChild(final View animView, final float targetLeft, float velocity) {
|
||||
final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
|
||||
AnimatorUpdateListener updateListener = animation -> onTranslationUpdate(animView,
|
||||
(float) animation.getAnimatedValue(), canBeDismissed);
|
||||
|
||||
Animator anim = getViewTranslationAnimator(animView, targetLeft, updateListener);
|
||||
if (anim == null) {
|
||||
onSnapChildWithAnimationFinished();
|
||||
return;
|
||||
}
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
boolean wasCancelled = false;
|
||||
cancelTranslateAnimation(animView);
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animator) {
|
||||
wasCancelled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animator) {
|
||||
mSnappingChild = false;
|
||||
if (!wasCancelled) {
|
||||
updateSwipeProgressFromOffset(animView, canBeDismissed);
|
||||
resetSwipeState();
|
||||
}
|
||||
onSnapChildWithAnimationFinished();
|
||||
}
|
||||
PhysicsAnimator<? extends View> anim =
|
||||
createSnapBackAnimation(animView, targetLeft, velocity);
|
||||
anim.addUpdateListener((target, values) -> {
|
||||
onTranslationUpdate(target, getTranslation(target), canBeDismissed);
|
||||
});
|
||||
anim.addEndListener((t, p, wasFling, cancelled, finalValue, finalVelocity, allEnded) -> {
|
||||
mSnappingChild = false;
|
||||
|
||||
if (!cancelled) {
|
||||
updateSwipeProgressFromOffset(animView, canBeDismissed);
|
||||
resetSwipeState();
|
||||
}
|
||||
onChildSnappedBack(animView, targetLeft);
|
||||
});
|
||||
prepareSnapBackAnimation(animView, anim);
|
||||
mSnappingChild = true;
|
||||
float maxDistance = Math.abs(targetLeft - getTranslation(animView));
|
||||
mFlingAnimationUtils.apply(anim, getTranslation(animView), targetLeft, velocity,
|
||||
maxDistance);
|
||||
anim.start();
|
||||
mCallback.onChildSnappedBack(animView, targetLeft);
|
||||
}
|
||||
|
||||
private PhysicsAnimator<? extends View> createSnapBackAnimation(View target, float toPosition,
|
||||
float startVelocity) {
|
||||
if (target instanceof ExpandableNotificationRow) {
|
||||
return PhysicsAnimator.getInstance((ExpandableNotificationRow) target).spring(
|
||||
createFloatPropertyCompat(ExpandableNotificationRow.TRANSLATE_CONTENT),
|
||||
toPosition,
|
||||
startVelocity,
|
||||
mSnapBackSpringConfig);
|
||||
}
|
||||
return PhysicsAnimator.getInstance(target).spring(
|
||||
mSwipeDirection == X ? TRANSLATION_X : TRANSLATION_Y, toPosition, startVelocity,
|
||||
mSnapBackSpringConfig);
|
||||
}
|
||||
|
||||
private void cancelTranslateAnimation(View animView) {
|
||||
if (animView instanceof ExpandableNotificationRow) {
|
||||
((ExpandableNotificationRow) animView).cancelTranslateAnimation();
|
||||
}
|
||||
cancelSnapbackAnimation(animView);
|
||||
}
|
||||
|
||||
private void cancelSnapbackAnimation(View target) {
|
||||
PhysicsAnimator.getInstance(target).cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to update the content alpha while the view is swiped
|
||||
@@ -576,17 +600,10 @@ public class SwipeHelper implements Gefingerpoken {
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the swipe helper itself a chance to do something on snap back so NSSL doesn't have
|
||||
* to tell us what to do
|
||||
* Called after {@link #snapChild(View, float, float)} and its related animation has finished.
|
||||
*/
|
||||
protected void onChildSnappedBack(View animView, float targetLeft) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to update the snap back animation.
|
||||
*/
|
||||
protected void prepareSnapBackAnimation(View view, Animator anim) {
|
||||
// Do nothing
|
||||
mCallback.onChildSnappedBack(animView, targetLeft);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,7 +47,6 @@ import android.util.FloatProperty;
|
||||
import android.util.IndentingPrintWriter;
|
||||
import android.util.Log;
|
||||
import android.util.MathUtils;
|
||||
import android.util.Property;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
@@ -336,8 +335,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
};
|
||||
private boolean mKeepInParentForDismissAnimation;
|
||||
private boolean mRemoved;
|
||||
private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
|
||||
new FloatProperty<ExpandableNotificationRow>("translate") {
|
||||
public static final FloatProperty<ExpandableNotificationRow> TRANSLATE_CONTENT =
|
||||
new FloatProperty<>("translate") {
|
||||
@Override
|
||||
public void setValue(ExpandableNotificationRow object, float value) {
|
||||
object.setTranslation(value);
|
||||
@@ -348,6 +347,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
return object.getTranslation();
|
||||
}
|
||||
};
|
||||
|
||||
private OnClickListener mOnClickListener;
|
||||
private OnDragSuccessListener mOnDragSuccessListener;
|
||||
private boolean mHeadsupDisappearRunning;
|
||||
@@ -2177,6 +2177,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
return translateAnim;
|
||||
}
|
||||
|
||||
/** Cancels the ongoing translate animation if there is any. */
|
||||
public void cancelTranslateAnimation() {
|
||||
if (mTranslateAnim != null) {
|
||||
mTranslateAnim.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void ensureGutsInflated() {
|
||||
if (mGuts == null) {
|
||||
mGutsStub.inflate();
|
||||
|
||||
@@ -135,11 +135,15 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
|
||||
|
||||
@Override
|
||||
protected void onChildSnappedBack(View animView, float targetLeft) {
|
||||
super.onChildSnappedBack(animView, targetLeft);
|
||||
|
||||
final NotificationMenuRowPlugin menuRow = getCurrentMenuRow();
|
||||
if (menuRow != null && targetLeft == 0) {
|
||||
menuRow.resetMenu();
|
||||
clearCurrentMenuRow();
|
||||
}
|
||||
|
||||
InteractionJankMonitor.getInstance().end(CUJ_NOTIFICATION_SHADE_ROW_SWIPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -348,18 +352,13 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
|
||||
super.dismissChild(view, velocity, useAccelerateInterpolator);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSnapChildWithAnimationFinished() {
|
||||
InteractionJankMonitor.getInstance().end(CUJ_NOTIFICATION_SHADE_ROW_SWIPE);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void superSnapChild(final View animView, final float targetLeft, float velocity) {
|
||||
super.snapChild(animView, targetLeft, velocity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void snapChild(final View animView, final float targetLeft, float velocity) {
|
||||
protected void snapChild(final View animView, final float targetLeft, float velocity) {
|
||||
superSnapChild(animView, targetLeft, velocity);
|
||||
mCallback.onDragCancelled(animView);
|
||||
if (targetLeft == 0) {
|
||||
@@ -380,20 +379,18 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@VisibleForTesting
|
||||
protected Animator superGetViewTranslationAnimator(View v, float target,
|
||||
protected Animator getViewTranslationAnimator(View view, float target,
|
||||
ValueAnimator.AnimatorUpdateListener listener) {
|
||||
return super.getViewTranslationAnimator(v, target, listener);
|
||||
return super.getViewTranslationAnimator(view, target, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animator getViewTranslationAnimator(View v, float target,
|
||||
@VisibleForTesting
|
||||
protected Animator createTranslationAnimation(View view, float newPos,
|
||||
ValueAnimator.AnimatorUpdateListener listener) {
|
||||
if (v instanceof ExpandableNotificationRow) {
|
||||
return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
|
||||
} else {
|
||||
return superGetViewTranslationAnimator(v, target, listener);
|
||||
}
|
||||
return super.createTranslationAnimation(view, newPos, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -425,12 +425,12 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
|
||||
public void testGetViewTranslationAnimator_notExpandableNotificationRow() {
|
||||
Animator animator = mock(Animator.class);
|
||||
AnimatorUpdateListener listener = mock(AnimatorUpdateListener.class);
|
||||
doReturn(animator).when(mSwipeHelper).superGetViewTranslationAnimator(mView, 0, listener);
|
||||
doReturn(animator).when(mSwipeHelper).createTranslationAnimation(mView, 0, listener);
|
||||
|
||||
assertEquals("returns the correct animator from super", animator,
|
||||
assertEquals("Should create a new animator", animator,
|
||||
mSwipeHelper.getViewTranslationAnimator(mView, 0, listener));
|
||||
|
||||
verify(mSwipeHelper, times(1)).superGetViewTranslationAnimator(mView, 0, listener);
|
||||
verify(mSwipeHelper).createTranslationAnimation(mView, 0, listener);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -439,10 +439,10 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
|
||||
AnimatorUpdateListener listener = mock(AnimatorUpdateListener.class);
|
||||
doReturn(animator).when(mNotificationRow).getTranslateViewAnimator(0, listener);
|
||||
|
||||
assertEquals("returns the correct animator from super when view is an ENR", animator,
|
||||
assertEquals("Should return the animator from ExpandableNotificationRow", animator,
|
||||
mSwipeHelper.getViewTranslationAnimator(mNotificationRow, 0, listener));
|
||||
|
||||
verify(mNotificationRow, times(1)).getTranslateViewAnimator(0, listener);
|
||||
verify(mNotificationRow).getTranslateViewAnimator(0, listener);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user