Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c1fa7d21 authored by András Kurucz's avatar András Kurucz Committed by Automerger Merge Worker
Browse files

Merge "Use spring animation for Notification SnapBack" into udc-dev am: 04262328

parents 50880678 04262328
Loading
Loading
Loading
Loading
+69 −52
Original line number Diff line number Diff line
@@ -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;
    protected Animator getViewTranslationAnimator(View view, float target,
            AnimatorUpdateListener listener) {

        cancelSnapbackAnimation(view);

        if (view instanceof ExpandableNotificationRow) {
            return ((ExpandableNotificationRow) view).getTranslateViewAnimator(target, listener);
        }

    private float getPerpendicularVelocity(VelocityTracker vt) {
        return mSwipeDirection == X ? vt.getYVelocity() :
                vt.getXVelocity();
        return createTranslationAnimation(view, target, listener);
    }

    protected Animator getViewTranslationAnimator(View v, float target,
    protected Animator createTranslationAnimation(View view, float newPos,
            AnimatorUpdateListener listener) {
        ObjectAnimator anim = createTranslationAnimation(v, target);
        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;

            @Override
            public void onAnimationCancel(Animator animator) {
                wasCancelled = true;
            }
        cancelTranslateAnimation(animView);

            @Override
            public void onAnimationEnd(Animator animator) {
        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 (!wasCancelled) {

            if (!cancelled) {
                updateSwipeProgressFromOffset(animView, canBeDismissed);
                resetSwipeState();
            }
                onSnapChildWithAnimationFinished();
            }
            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);
    }

    /**
+10 −3
Original line number Diff line number Diff line
@@ -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();
+11 −14
Original line number Diff line number Diff line
@@ -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
+5 −5
Original line number Diff line number Diff line
@@ -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