[go: nahoru, domu]

FlingAnimationUtils.java revision b6cdcbc66b4b862f83afde85b8e7109b6450b15e
187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi/*
287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * Copyright (C) 2014 The Android Open Source Project
387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi *
487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License");
587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * you may not use this file except in compliance with the License.
687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * You may obtain a copy of the License at
787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi *
887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi *      http://www.apache.org/licenses/LICENSE-2.0
987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi *
1087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * Unless required by applicable law or agreed to in writing, software
1187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS,
1287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * See the License for the specific language governing permissions and
1487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * limitations under the License
1587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi */
1687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
1787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggipackage com.android.systemui.statusbar;
1887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
19b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggiimport android.animation.Animator;
2087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggiimport android.animation.ValueAnimator;
2187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggiimport android.content.Context;
224c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinekimport android.view.ViewPropertyAnimator;
2387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggiimport android.view.animation.AnimationUtils;
2487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggiimport android.view.animation.Interpolator;
2587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggiimport android.view.animation.PathInterpolator;
2687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
2787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi/**
2887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * Utility class to calculate general fling animation when the finger is released.
2987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi */
3087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggipublic class FlingAnimationUtils {
3187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
321d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    private static final float LINEAR_OUT_SLOW_IN_X2 = 0.35f;
332580a976ec93a01ed00fae51364ad872bc591d95Jorim Jaggi    private static final float LINEAR_OUT_FASTER_IN_X2 = 0.5f;
342580a976ec93a01ed00fae51364ad872bc591d95Jorim Jaggi    private static final float LINEAR_OUT_FASTER_IN_Y2_MIN = 0.4f;
352580a976ec93a01ed00fae51364ad872bc591d95Jorim Jaggi    private static final float LINEAR_OUT_FASTER_IN_Y2_MAX = 0.5f;
3687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi    private static final float MIN_VELOCITY_DP_PER_SECOND = 250;
37efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi    private static final float HIGH_VELOCITY_DP_PER_SECOND = 3000;
3887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
3987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi    /**
4087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi     * Crazy math. http://en.wikipedia.org/wiki/B%C3%A9zier_curve
4187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi     */
421d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 1.0f / LINEAR_OUT_SLOW_IN_X2;
4387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
4487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi    private Interpolator mLinearOutSlowIn;
4587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi    private Interpolator mFastOutSlowIn;
461d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    private Interpolator mFastOutLinearIn;
471d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi
4887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi    private float mMinVelocityPxPerSecond;
491d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    private float mMaxLengthSeconds;
50efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi    private float mHighVelocityPxPerSecond;
5187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
524c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    private AnimatorProperties mAnimatorProperties = new AnimatorProperties();
534c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek
541d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    public FlingAnimationUtils(Context ctx, float maxLengthSeconds) {
551d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        mMaxLengthSeconds = maxLengthSeconds;
561d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        mLinearOutSlowIn = new PathInterpolator(0, 0, LINEAR_OUT_SLOW_IN_X2, 1);
5787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        mFastOutSlowIn
5887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi                = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in);
591d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        mFastOutLinearIn
601d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi                = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_linear_in);
6187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        mMinVelocityPxPerSecond
6287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi                = MIN_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
63efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi        mHighVelocityPxPerSecond
64efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi                = HIGH_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
6587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi    }
6687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
6787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi    /**
6887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi     * Applies the interpolator and length to the animator, such that the fling animation is
6987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi     * consistent with the finger motion.
7087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi     *
7187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi     * @param animator the animator to apply
7287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi     * @param currValue the current value
7387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi     * @param endValue the end value of the animator
7487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi     * @param velocity the current velocity of the motion
7587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi     */
76b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi    public void apply(Animator animator, float currValue, float endValue, float velocity) {
771d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
781d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    }
791d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi
801d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    /**
811d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * Applies the interpolator and length to the animator, such that the fling animation is
821d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * consistent with the finger motion.
831d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     *
841d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * @param animator the animator to apply
851d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * @param currValue the current value
861d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * @param endValue the end value of the animator
871d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * @param velocity the current velocity of the motion
884c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     */
894c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
904c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek            float velocity) {
914c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
924c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    }
934c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek
944c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    /**
954c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * Applies the interpolator and length to the animator, such that the fling animation is
964c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * consistent with the finger motion.
974c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     *
984c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * @param animator the animator to apply
994c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * @param currValue the current value
1004c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * @param endValue the end value of the animator
1014c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * @param velocity the current velocity of the motion
1021d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * @param maxDistance the maximum distance for this interaction; the maximum animation length
1031d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     *                    gets multiplied by the ratio between the actual distance and this value
1041d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     */
105b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi    public void apply(Animator animator, float currValue, float endValue, float velocity,
1061d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            float maxDistance) {
1074c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        AnimatorProperties properties = getProperties(currValue, endValue, velocity,
1084c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek                maxDistance);
1094c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        animator.setDuration(properties.duration);
1104c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        animator.setInterpolator(properties.interpolator);
1114c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    }
1124c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek
1134c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    /**
1144c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * Applies the interpolator and length to the animator, such that the fling animation is
1154c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * consistent with the finger motion.
1164c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     *
1174c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * @param animator the animator to apply
1184c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * @param currValue the current value
1194c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * @param endValue the end value of the animator
1204c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * @param velocity the current velocity of the motion
1214c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * @param maxDistance the maximum distance for this interaction; the maximum animation length
1224c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     *                    gets multiplied by the ratio between the actual distance and this value
1234c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     */
1244c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
1254c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek            float velocity, float maxDistance) {
1264c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        AnimatorProperties properties = getProperties(currValue, endValue, velocity,
1274c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek                maxDistance);
1284c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        animator.setDuration(properties.duration);
1294c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        animator.setInterpolator(properties.interpolator);
1304c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    }
1314c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek
1324c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    private AnimatorProperties getProperties(float currValue,
1334c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek            float endValue, float velocity, float maxDistance) {
1341d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        float maxLengthSeconds = (float) (mMaxLengthSeconds
1351d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi                * Math.sqrt(Math.abs(endValue - currValue) / maxDistance));
13687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        float diff = Math.abs(endValue - currValue);
13787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        float velAbs = Math.abs(velocity);
13887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        float durationSeconds = LINEAR_OUT_SLOW_IN_START_GRADIENT * diff / velAbs;
1391d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        if (durationSeconds <= maxLengthSeconds) {
1404c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek            mAnimatorProperties.interpolator = mLinearOutSlowIn;
14187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        } else if (velAbs >= mMinVelocityPxPerSecond) {
14287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
14387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi            // Cross fade between fast-out-slow-in and linear interpolator with current velocity.
1441d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            durationSeconds = maxLengthSeconds;
14587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi            VelocityInterpolator velocityInterpolator
14687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi                    = new VelocityInterpolator(durationSeconds, velAbs, diff);
14787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi            InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
14887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi                    velocityInterpolator, mLinearOutSlowIn, mLinearOutSlowIn);
1494c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek            mAnimatorProperties.interpolator = superInterpolator;
15087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        } else {
15187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
15287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi            // Just use a normal interpolator which doesn't take the velocity into account.
1531d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            durationSeconds = maxLengthSeconds;
1544c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek            mAnimatorProperties.interpolator = mFastOutSlowIn;
15587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        }
1564c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        mAnimatorProperties.duration = (long) (durationSeconds * 1000);
1574c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        return mAnimatorProperties;
15887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi    }
15987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
16087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi    /**
1611d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * Applies the interpolator and length to the animator, such that the fling animation is
1621d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * consistent with the finger motion for the case when the animation is making something
1631d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * disappear.
1641d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     *
1651d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * @param animator the animator to apply
1661d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * @param currValue the current value
1671d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * @param endValue the end value of the animator
1681d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * @param velocity the current velocity of the motion
1691d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * @param maxDistance the maximum distance for this interaction; the maximum animation length
1701d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     *                    gets multiplied by the ratio between the actual distance and this value
1711d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     */
172b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi    public void applyDismissing(Animator animator, float currValue, float endValue,
1731d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            float velocity, float maxDistance) {
1744c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
1754c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek                maxDistance);
1764c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        animator.setDuration(properties.duration);
1774c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        animator.setInterpolator(properties.interpolator);
1784c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    }
1794c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek
1804c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    /**
1814c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * Applies the interpolator and length to the animator, such that the fling animation is
1824c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * consistent with the finger motion for the case when the animation is making something
1834c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * disappear.
1844c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     *
1854c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * @param animator the animator to apply
1864c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * @param currValue the current value
1874c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * @param endValue the end value of the animator
1884c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * @param velocity the current velocity of the motion
1894c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     * @param maxDistance the maximum distance for this interaction; the maximum animation length
1904c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     *                    gets multiplied by the ratio between the actual distance and this value
1914c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek     */
1924c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    public void applyDismissing(ViewPropertyAnimator animator, float currValue, float endValue,
1934c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek            float velocity, float maxDistance) {
1944c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
1954c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek                maxDistance);
1964c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        animator.setDuration(properties.duration);
1974c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        animator.setInterpolator(properties.interpolator);
1984c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    }
1994c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek
2004c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    private AnimatorProperties getDismissingProperties(float currValue, float endValue,
2014c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek            float velocity, float maxDistance) {
2021d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        float maxLengthSeconds = (float) (mMaxLengthSeconds
2031d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi                * Math.pow(Math.abs(endValue - currValue) / maxDistance, 0.5f));
2041d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        float diff = Math.abs(endValue - currValue);
2051d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        float velAbs = Math.abs(velocity);
206efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi        float y2 = calculateLinearOutFasterInY2(velAbs);
207efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi
2082580a976ec93a01ed00fae51364ad872bc591d95Jorim Jaggi        float startGradient = y2 / LINEAR_OUT_FASTER_IN_X2;
2092580a976ec93a01ed00fae51364ad872bc591d95Jorim Jaggi        Interpolator mLinearOutFasterIn = new PathInterpolator(0, 0, LINEAR_OUT_FASTER_IN_X2, y2);
210efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi        float durationSeconds = startGradient * diff / velAbs;
2111d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        if (durationSeconds <= maxLengthSeconds) {
2124c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek            mAnimatorProperties.interpolator = mLinearOutFasterIn;
2131d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        } else if (velAbs >= mMinVelocityPxPerSecond) {
2141d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi
2151d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            // Cross fade between linear-out-faster-in and linear interpolator with current
2161d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            // velocity.
2171d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            durationSeconds = maxLengthSeconds;
2181d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            VelocityInterpolator velocityInterpolator
2191d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi                    = new VelocityInterpolator(durationSeconds, velAbs, diff);
2201d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
2211d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi                    velocityInterpolator, mLinearOutFasterIn, mLinearOutSlowIn);
2224c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek            mAnimatorProperties.interpolator = superInterpolator;
2231d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        } else {
2241d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi
2251d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            // Just use a normal interpolator which doesn't take the velocity into account.
2261d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi            durationSeconds = maxLengthSeconds;
2274c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek            mAnimatorProperties.interpolator = mFastOutLinearIn;
2281d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        }
2294c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        mAnimatorProperties.duration = (long) (durationSeconds * 1000);
2304c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        return mAnimatorProperties;
2311d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    }
2321d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi
2331d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    /**
234efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi     * Calculates the y2 control point for a linear-out-faster-in path interpolator depending on the
235efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi     * velocity. The faster the velocity, the more "linear" the interpolator gets.
236efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi     *
237efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi     * @param velocity the velocity of the gesture.
238efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi     * @return the y2 control point for a cubic bezier path interpolator
239efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi     */
240efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi    private float calculateLinearOutFasterInY2(float velocity) {
241efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi        float t = (velocity - mMinVelocityPxPerSecond)
242efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi                / (mHighVelocityPxPerSecond - mMinVelocityPxPerSecond);
243efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi        t = Math.max(0, Math.min(1, t));
244efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi        return (1 - t) * LINEAR_OUT_FASTER_IN_Y2_MIN + t * LINEAR_OUT_FASTER_IN_Y2_MAX;
245efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi    }
246efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi
247efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi    /**
2481d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     * @return the minimum velocity a gesture needs to have to be considered a fling
2491d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi     */
2501d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    public float getMinVelocityPxPerSecond() {
2511d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi        return mMinVelocityPxPerSecond;
2521d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    }
2531d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi
2541d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi    /**
25587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi     * An interpolator which interpolates two interpolators with an interpolator.
25687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi     */
25787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi    private static final class InterpolatorInterpolator implements Interpolator {
25887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
25987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        private Interpolator mInterpolator1;
26087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        private Interpolator mInterpolator2;
26187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        private Interpolator mCrossfader;
26287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
26387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        InterpolatorInterpolator(Interpolator interpolator1, Interpolator interpolator2,
26487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi                Interpolator crossfader) {
26587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi            mInterpolator1 = interpolator1;
26687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi            mInterpolator2 = interpolator2;
26787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi            mCrossfader = crossfader;
26887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        }
26987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
27087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        @Override
27187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        public float getInterpolation(float input) {
27287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi            float t = mCrossfader.getInterpolation(input);
27387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi            return (1 - t) * mInterpolator1.getInterpolation(input)
27487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi                    + t * mInterpolator2.getInterpolation(input);
27587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        }
27687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi    }
27787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
27887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi    /**
27987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi     * An interpolator which interpolates with a fixed velocity.
28087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi     */
28187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi    private static final class VelocityInterpolator implements Interpolator {
28287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
28387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        private float mDurationSeconds;
28487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        private float mVelocity;
28587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        private float mDiff;
28687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
28787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        private VelocityInterpolator(float durationSeconds, float velocity, float diff) {
28887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi            mDurationSeconds = durationSeconds;
28987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi            mVelocity = velocity;
29087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi            mDiff = diff;
29187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        }
29287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi
29387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        @Override
29487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        public float getInterpolation(float input) {
29587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi            float time = input * mDurationSeconds;
29687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi            return time * mVelocity / mDiff;
29787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi        }
29887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi    }
2994c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek
3004c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    private static class AnimatorProperties {
3014c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        Interpolator interpolator;
3024c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek        long duration;
3034c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek    }
3044c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek
30587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi}
306