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

Commit f2ba2deb authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Using common fling detection logic for notification and all-apps am: b72d8b2c

Change-Id: I55ab8d0767804d7dc60b8676a17d5302704dc94f
parents b5bc12f5 b72d8b2c
Loading
Loading
Loading
Loading
+4 −50
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import android.view.animation.Interpolator;

import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.pageindicators.PageIndicator;
import com.android.launcher3.touch.OverScroll;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;

@@ -68,10 +69,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
    public static final int PAGE_SNAP_ANIMATION_DURATION = 750;
    protected static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;

    // Overscroll constants
    // OverScroll constants
    private final static int OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION = 270;
    private static final float OVERSCROLL_ACCELERATE_FACTOR = 2;
    private static final float OVERSCROLL_DAMP_FACTOR = 0.07f;

    private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f;
    // The page is moved more than halfway, automatically move to the next page on touch up.
@@ -188,7 +187,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
    // Convenience/caching
    private static final Matrix sTmpInvMatrix = new Matrix();
    private static final float[] sTmpPoint = new float[2];
    private static final int[] sTmpIntPoint = new int[2];
    private static final Rect sTmpRect = new Rect();

    protected final Rect mInsets = new Rect();
@@ -233,8 +231,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
        mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * density);
        setOnHierarchyChangeListener(this);
        setWillNotDraw(false);

        int edgeEffectColor = Themes.getAttrColor(getContext(), android.R.attr.colorEdgeEffect);
    }

    protected void setDefaultInterpolator(Interpolator interpolator) {
@@ -1305,29 +1301,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
        }
    }

    // This curve determines how the effect of scrolling over the limits of the page dimishes
    // as the user pulls further and further from the bounds
    private float overScrollInfluenceCurve(float f) {
        f -= 1.0f;
        return f * f * f + 1.0f;
    }

    protected float acceleratedOverFactor(float amount) {
        int screenSize = getViewportWidth();

        // We want to reach the max over scroll effect when the user has
        // over scrolled half the size of the screen
        float f = OVERSCROLL_ACCELERATE_FACTOR * (amount / screenSize);

        if (Float.compare(f, 0f) == 0) return 0;

        // Clamp this factor, f, to -1 < f < 1
        if (Math.abs(f) >= 1) {
            f /= Math.abs(f);
        }
        return f;
    }

    // While layout transitions are occurring, a child's position may stray from its baseline
    // position. This method returns the magnitude of this stray at any given time.
    public int getLayoutTransitionOffsetForPage(int index) {
@@ -1348,20 +1321,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
    }

    protected void dampedOverScroll(float amount) {
        int screenSize = getViewportWidth();

        float f = (amount / screenSize);

        if (Float.compare(f, 0f) == 0) return;

        f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
        if (Float.compare(amount, 0f) == 0) return;

        // Clamp this factor, f, to -1 < f < 1
        if (Math.abs(f) >= 1) {
            f /= Math.abs(f);
        }

        int overScrollAmount = (int) Math.round(OVERSCROLL_DAMP_FACTOR * f * screenSize);
        int overScrollAmount = OverScroll.dampedScroll(amount, getViewportWidth());
        if (amount < 0) {
            mOverScrollX = overScrollAmount;
            super.scrollTo(mOverScrollX, getScrollY());
@@ -1376,14 +1338,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
        dampedOverScroll(amount);
    }

    protected float maxOverScroll() {
        // Using the formula in overScroll, assuming that f = 1.0 (which it should generally not
        // exceed). Used to find out how much extra wallpaper we need for the over scroll effect
        float f = 1.0f;
        f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
        return OVERSCROLL_DAMP_FACTOR * f;
    }

    /**
     * return true if freescroll has been enabled, false otherwise
     */
+2 −4
Original line number Diff line number Diff line
@@ -50,8 +50,7 @@ public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDele
        if ((host.getParent() instanceof DeepShortcutView)) {
            info.addAction(mActions.get(ADD_TO_WORKSPACE));
        } else if (host instanceof NotificationMainView) {
            NotificationMainView notificationView = (NotificationMainView) host;
            if (notificationView.canChildBeDismissed(notificationView)) {
            if (((NotificationMainView) host).canChildBeDismissed()) {
                info.addAction(mActions.get(DISMISS_NOTIFICATION));
            }
        }
@@ -88,8 +87,7 @@ public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDele
            if (!(host instanceof NotificationMainView)) {
                return false;
            }
            NotificationMainView notificationView = (NotificationMainView) host;
            notificationView.onChildDismissed(notificationView);
            ((NotificationMainView) host).onChildDismissed();
            announceConfirmation(R.string.notification_dismissed);
            return true;
        }
+3 −33
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
import com.android.launcher3.touch.OverScroll;
import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -98,8 +99,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
                R.dimen.all_apps_empty_search_bg_top_offset);

        mOverScrollHelper = new OverScrollHelper();
        mPullDetector = new SwipeDetector(getContext());
        mPullDetector.setListener(mOverScrollHelper);
        mPullDetector = new SwipeDetector(getContext(), mOverScrollHelper, SwipeDetector.VERTICAL);
        mPullDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, true);
    }

@@ -564,37 +564,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
        }

        private float getDampedOverScroll(float y) {
            return dampedOverScroll(y, getHeight()) * MAX_OVERSCROLL_PERCENTAGE;
        }

        /**
         * This curve determines how the effect of scrolling over the limits of the page diminishes
         * as the user pulls further and further from the bounds
         *
         * @param f The percentage of how much the user has overscrolled.
         * @return A transformed percentage based on the influence curve.
         */
        private float overScrollInfluenceCurve(float f) {
            f -= 1.0f;
            return f * f * f + 1.0f;
        }

        /**
         * @param amount The original amount overscrolled.
         * @param max The maximum amount that the View can overscroll.
         * @return The dampened overscroll amount.
         */
        private float dampedOverScroll(float amount, float max) {
            float f = amount / max;
            if (Float.compare(f, 0) == 0) return 0;
            f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));

            // Clamp this factor, f, to -1 < f < 1
            if (Math.abs(f) >= 1) {
                f /= Math.abs(f);
            }

            return Math.round(f * max);
            return OverScroll.dampedScroll(y, getHeight());
        }
    }
}
+6 −7
Original line number Diff line number Diff line
@@ -107,8 +107,7 @@ public class AllAppsTransitionController implements TouchController, SwipeDetect

    public AllAppsTransitionController(Launcher l) {
        mLauncher = l;
        mDetector = new SwipeDetector(l);
        mDetector.setListener(this);
        mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL);
        mShiftRange = DEFAULT_SHIFT_RANGE;
        mProgress = 1f;

@@ -137,15 +136,15 @@ public class AllAppsTransitionController implements TouchController, SwipeDetect

                if (mDetector.isIdleState()) {
                    if (mLauncher.isAllAppsVisible()) {
                        directionsToDetectScroll |= SwipeDetector.DIRECTION_DOWN;
                        directionsToDetectScroll |= SwipeDetector.DIRECTION_NEGATIVE;
                    } else {
                        directionsToDetectScroll |= SwipeDetector.DIRECTION_UP;
                        directionsToDetectScroll |= SwipeDetector.DIRECTION_POSITIVE;
                    }
                } else {
                    if (isInDisallowRecatchBottomZone()) {
                        directionsToDetectScroll |= SwipeDetector.DIRECTION_UP;
                        directionsToDetectScroll |= SwipeDetector.DIRECTION_POSITIVE;
                    } else if (isInDisallowRecatchTopZone()) {
                        directionsToDetectScroll |= SwipeDetector.DIRECTION_DOWN;
                        directionsToDetectScroll |= SwipeDetector.DIRECTION_NEGATIVE;
                    } else {
                        directionsToDetectScroll |= SwipeDetector.DIRECTION_BOTH;
                        ignoreSlopWhenSettling = true;
@@ -368,7 +367,7 @@ public class AllAppsTransitionController implements TouchController, SwipeDetect
    }

    private void calculateDuration(float velocity, float disp) {
        mAnimationDuration = mDetector.calculateDuration(velocity, disp / mShiftRange);
        mAnimationDuration = SwipeDetector.calculateDuration(velocity, disp / mShiftRange);
    }

    public boolean animateToAllApps(AnimatorSet animationOut, long duration) {
+0 −356
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.notification;

import android.animation.Animator;
import android.content.Context;
import android.view.ViewPropertyAnimator;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;

/**
 * Utility class to calculate general fling animation when the finger is released.
 *
 * This class was copied from com.android.systemui.statusbar.
 */
public class FlingAnimationUtils {

    private static final float LINEAR_OUT_SLOW_IN_X2 = 0.35f;
    private static final float LINEAR_OUT_SLOW_IN_X2_MAX = 0.68f;
    private static final float LINEAR_OUT_FASTER_IN_X2 = 0.5f;
    private static final float LINEAR_OUT_FASTER_IN_Y2_MIN = 0.4f;
    private static final float LINEAR_OUT_FASTER_IN_Y2_MAX = 0.5f;
    private static final float MIN_VELOCITY_DP_PER_SECOND = 250;
    private static final float HIGH_VELOCITY_DP_PER_SECOND = 3000;

    private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 0.75f;
    private final float mSpeedUpFactor;
    private final float mY2;

    private float mMinVelocityPxPerSecond;
    private float mMaxLengthSeconds;
    private float mHighVelocityPxPerSecond;
    private float mLinearOutSlowInX2;

    private AnimatorProperties mAnimatorProperties = new AnimatorProperties();
    private PathInterpolator mInterpolator;
    private float mCachedStartGradient = -1;
    private float mCachedVelocityFactor = -1;

    public FlingAnimationUtils(Context ctx, float maxLengthSeconds) {
        this(ctx, maxLengthSeconds, 0.0f);
    }

    /**
     * @param maxLengthSeconds the longest duration an animation can become in seconds
     * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards
     *                      the end of the animation. 0 means it's at the beginning and no
     *                      acceleration will take place.
     */
    public FlingAnimationUtils(Context ctx, float maxLengthSeconds, float speedUpFactor) {
        this(ctx, maxLengthSeconds, speedUpFactor, -1.0f, 1.0f);
    }

    /**
     * @param maxLengthSeconds the longest duration an animation can become in seconds
     * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards
     *                      the end of the animation. 0 means it's at the beginning and no
     *                      acceleration will take place.
     * @param x2 the x value to take for the second point of the bezier spline. If a value below 0
     *           is provided, the value is automatically calculated.
     * @param y2 the y value to take for the second point of the bezier spline
     */
    public FlingAnimationUtils(Context ctx, float maxLengthSeconds, float speedUpFactor, float x2,
            float y2) {
        mMaxLengthSeconds = maxLengthSeconds;
        mSpeedUpFactor = speedUpFactor;
        if (x2 < 0) {
            mLinearOutSlowInX2 = interpolate(LINEAR_OUT_SLOW_IN_X2,
                    LINEAR_OUT_SLOW_IN_X2_MAX,
                    mSpeedUpFactor);
        } else {
            mLinearOutSlowInX2 = x2;
        }
        mY2 = y2;

        mMinVelocityPxPerSecond
                = MIN_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
        mHighVelocityPxPerSecond
                = HIGH_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
    }

    private static float interpolate(float start, float end, float amount) {
        return start * (1.0f - amount) + end * amount;
    }

    /**
     * Applies the interpolator and length to the animator, such that the fling animation is
     * consistent with the finger motion.
     *
     * @param animator the animator to apply
     * @param currValue the current value
     * @param endValue the end value of the animator
     * @param velocity the current velocity of the motion
     */
    public void apply(Animator animator, float currValue, float endValue, float velocity) {
        apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
    }

    /**
     * Applies the interpolator and length to the animator, such that the fling animation is
     * consistent with the finger motion.
     *
     * @param animator the animator to apply
     * @param currValue the current value
     * @param endValue the end value of the animator
     * @param velocity the current velocity of the motion
     */
    public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
            float velocity) {
        apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
    }

    /**
     * Applies the interpolator and length to the animator, such that the fling animation is
     * consistent with the finger motion.
     *
     * @param animator the animator to apply
     * @param currValue the current value
     * @param endValue the end value of the animator
     * @param velocity the current velocity of the motion
     * @param maxDistance the maximum distance for this interaction; the maximum animation length
     *                    gets multiplied by the ratio between the actual distance and this value
     */
    public void apply(Animator animator, float currValue, float endValue, float velocity,
            float maxDistance) {
        AnimatorProperties properties = getProperties(currValue, endValue, velocity,
                maxDistance);
        animator.setDuration(properties.duration);
        animator.setInterpolator(properties.interpolator);
    }

    /**
     * Applies the interpolator and length to the animator, such that the fling animation is
     * consistent with the finger motion.
     *
     * @param animator the animator to apply
     * @param currValue the current value
     * @param endValue the end value of the animator
     * @param velocity the current velocity of the motion
     * @param maxDistance the maximum distance for this interaction; the maximum animation length
     *                    gets multiplied by the ratio between the actual distance and this value
     */
    public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
            float velocity, float maxDistance) {
        AnimatorProperties properties = getProperties(currValue, endValue, velocity,
                maxDistance);
        animator.setDuration(properties.duration);
        animator.setInterpolator(properties.interpolator);
    }

    private AnimatorProperties getProperties(float currValue,
            float endValue, float velocity, float maxDistance) {
        float maxLengthSeconds = (float) (mMaxLengthSeconds
                * Math.sqrt(Math.abs(endValue - currValue) / maxDistance));
        float diff = Math.abs(endValue - currValue);
        float velAbs = Math.abs(velocity);
        float velocityFactor = mSpeedUpFactor == 0.0f
                ? 1.0f : Math.min(velAbs / HIGH_VELOCITY_DP_PER_SECOND, 1.0f);
        float startGradient = interpolate(LINEAR_OUT_SLOW_IN_START_GRADIENT,
                mY2 / mLinearOutSlowInX2, velocityFactor);
        float durationSeconds = startGradient * diff / velAbs;
        Interpolator slowInInterpolator = getInterpolator(startGradient, velocityFactor);
        if (durationSeconds <= maxLengthSeconds) {
            mAnimatorProperties.interpolator = slowInInterpolator;
        } else if (velAbs >= mMinVelocityPxPerSecond) {

            // Cross fade between fast-out-slow-in and linear interpolator with current velocity.
            durationSeconds = maxLengthSeconds;
            VelocityInterpolator velocityInterpolator
                    = new VelocityInterpolator(durationSeconds, velAbs, diff);
            InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
                    velocityInterpolator, slowInInterpolator, Interpolators.LINEAR_OUT_SLOW_IN);
            mAnimatorProperties.interpolator = superInterpolator;
        } else {

            // Just use a normal interpolator which doesn't take the velocity into account.
            durationSeconds = maxLengthSeconds;
            mAnimatorProperties.interpolator = Interpolators.FAST_OUT_SLOW_IN;
        }
        mAnimatorProperties.duration = (long) (durationSeconds * 1000);
        return mAnimatorProperties;
    }

    private Interpolator getInterpolator(float startGradient, float velocityFactor) {
        if (startGradient != mCachedStartGradient
                || velocityFactor != mCachedVelocityFactor) {
            float speedup = mSpeedUpFactor * (1.0f - velocityFactor);
            mInterpolator = new PathInterpolator(speedup,
                    speedup * startGradient,
                    mLinearOutSlowInX2, mY2);
            mCachedStartGradient = startGradient;
            mCachedVelocityFactor = velocityFactor;
        }
        return mInterpolator;
    }

    /**
     * Applies the interpolator and length to the animator, such that the fling animation is
     * consistent with the finger motion for the case when the animation is making something
     * disappear.
     *
     * @param animator the animator to apply
     * @param currValue the current value
     * @param endValue the end value of the animator
     * @param velocity the current velocity of the motion
     * @param maxDistance the maximum distance for this interaction; the maximum animation length
     *                    gets multiplied by the ratio between the actual distance and this value
     */
    public void applyDismissing(Animator animator, float currValue, float endValue,
            float velocity, float maxDistance) {
        AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
                maxDistance);
        animator.setDuration(properties.duration);
        animator.setInterpolator(properties.interpolator);
    }

    /**
     * Applies the interpolator and length to the animator, such that the fling animation is
     * consistent with the finger motion for the case when the animation is making something
     * disappear.
     *
     * @param animator the animator to apply
     * @param currValue the current value
     * @param endValue the end value of the animator
     * @param velocity the current velocity of the motion
     * @param maxDistance the maximum distance for this interaction; the maximum animation length
     *                    gets multiplied by the ratio between the actual distance and this value
     */
    public void applyDismissing(ViewPropertyAnimator animator, float currValue, float endValue,
            float velocity, float maxDistance) {
        AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
                maxDistance);
        animator.setDuration(properties.duration);
        animator.setInterpolator(properties.interpolator);
    }

    private AnimatorProperties getDismissingProperties(float currValue, float endValue,
            float velocity, float maxDistance) {
        float maxLengthSeconds = (float) (mMaxLengthSeconds
                * Math.pow(Math.abs(endValue - currValue) / maxDistance, 0.5f));
        float diff = Math.abs(endValue - currValue);
        float velAbs = Math.abs(velocity);
        float y2 = calculateLinearOutFasterInY2(velAbs);

        float startGradient = y2 / LINEAR_OUT_FASTER_IN_X2;
        Interpolator mLinearOutFasterIn = new PathInterpolator(0, 0, LINEAR_OUT_FASTER_IN_X2, y2);
        float durationSeconds = startGradient * diff / velAbs;
        if (durationSeconds <= maxLengthSeconds) {
            mAnimatorProperties.interpolator = mLinearOutFasterIn;
        } else if (velAbs >= mMinVelocityPxPerSecond) {

            // Cross fade between linear-out-faster-in and linear interpolator with current
            // velocity.
            durationSeconds = maxLengthSeconds;
            VelocityInterpolator velocityInterpolator
                    = new VelocityInterpolator(durationSeconds, velAbs, diff);
            InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
                    velocityInterpolator, mLinearOutFasterIn, Interpolators.LINEAR_OUT_SLOW_IN);
            mAnimatorProperties.interpolator = superInterpolator;
        } else {

            // Just use a normal interpolator which doesn't take the velocity into account.
            durationSeconds = maxLengthSeconds;
            mAnimatorProperties.interpolator = Interpolators.FAST_OUT_LINEAR_IN;
        }
        mAnimatorProperties.duration = (long) (durationSeconds * 1000);
        return mAnimatorProperties;
    }

    /**
     * Calculates the y2 control point for a linear-out-faster-in path interpolator depending on the
     * velocity. The faster the velocity, the more "linear" the interpolator gets.
     *
     * @param velocity the velocity of the gesture.
     * @return the y2 control point for a cubic bezier path interpolator
     */
    private float calculateLinearOutFasterInY2(float velocity) {
        float t = (velocity - mMinVelocityPxPerSecond)
                / (mHighVelocityPxPerSecond - mMinVelocityPxPerSecond);
        t = Math.max(0, Math.min(1, t));
        return (1 - t) * LINEAR_OUT_FASTER_IN_Y2_MIN + t * LINEAR_OUT_FASTER_IN_Y2_MAX;
    }

    /**
     * @return the minimum velocity a gesture needs to have to be considered a fling
     */
    public float getMinVelocityPxPerSecond() {
        return mMinVelocityPxPerSecond;
    }

    /**
     * An interpolator which interpolates two interpolators with an interpolator.
     */
    private static final class InterpolatorInterpolator implements Interpolator {

        private Interpolator mInterpolator1;
        private Interpolator mInterpolator2;
        private Interpolator mCrossfader;

        InterpolatorInterpolator(Interpolator interpolator1, Interpolator interpolator2,
                Interpolator crossfader) {
            mInterpolator1 = interpolator1;
            mInterpolator2 = interpolator2;
            mCrossfader = crossfader;
        }

        @Override
        public float getInterpolation(float input) {
            float t = mCrossfader.getInterpolation(input);
            return (1 - t) * mInterpolator1.getInterpolation(input)
                    + t * mInterpolator2.getInterpolation(input);
        }
    }

    /**
     * An interpolator which interpolates with a fixed velocity.
     */
    private static final class VelocityInterpolator implements Interpolator {

        private float mDurationSeconds;
        private float mVelocity;
        private float mDiff;

        private VelocityInterpolator(float durationSeconds, float velocity, float diff) {
            mDurationSeconds = durationSeconds;
            mVelocity = velocity;
            mDiff = diff;
        }

        @Override
        public float getInterpolation(float input) {
            float time = input * mDurationSeconds;
            return time * mVelocity / mDiff;
        }
    }

    private static class AnimatorProperties {
        Interpolator interpolator;
        long duration;
    }

}
Loading