FlingAnimationUtils.java revision 4c6969a512cd70831249ec1d07691f16fe5465f5
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 1987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggiimport android.animation.ValueAnimator; 2087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggiimport android.content.Context; 214c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinekimport android.view.ViewPropertyAnimator; 2287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggiimport android.view.animation.AnimationUtils; 2387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggiimport android.view.animation.Interpolator; 2487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggiimport android.view.animation.PathInterpolator; 2587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 2687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi/** 2787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * Utility class to calculate general fling animation when the finger is released. 2887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi */ 2987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggipublic class FlingAnimationUtils { 3087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 311d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi private static final float LINEAR_OUT_SLOW_IN_X2 = 0.35f; 32efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi private static final float LINEAR_OUT_FASTER_IN_Y2_MIN = 0.7f; 33efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi private static final float LINEAR_OUT_FASTER_IN_Y2_MAX = 1f; 3487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private static final float MIN_VELOCITY_DP_PER_SECOND = 250; 35efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi private static final float HIGH_VELOCITY_DP_PER_SECOND = 3000; 3687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 3787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi /** 3887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * Crazy math. http://en.wikipedia.org/wiki/B%C3%A9zier_curve 3987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi */ 401d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 1.0f / LINEAR_OUT_SLOW_IN_X2; 4187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 4287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private Interpolator mLinearOutSlowIn; 4387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private Interpolator mFastOutSlowIn; 441d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi private Interpolator mFastOutLinearIn; 451d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi 4687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private float mMinVelocityPxPerSecond; 471d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi private float mMaxLengthSeconds; 48efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi private float mHighVelocityPxPerSecond; 4987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 504c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek private AnimatorProperties mAnimatorProperties = new AnimatorProperties(); 514c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 521d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi public FlingAnimationUtils(Context ctx, float maxLengthSeconds) { 531d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi mMaxLengthSeconds = maxLengthSeconds; 541d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi mLinearOutSlowIn = new PathInterpolator(0, 0, LINEAR_OUT_SLOW_IN_X2, 1); 5587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mFastOutSlowIn 5687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in); 571d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi mFastOutLinearIn 581d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_linear_in); 5987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mMinVelocityPxPerSecond 6087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi = MIN_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density; 61efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi mHighVelocityPxPerSecond 62efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi = HIGH_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density; 6387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 6487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 6587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi /** 6687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * Applies the interpolator and length to the animator, such that the fling animation is 6787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * consistent with the finger motion. 6887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * 6987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * @param animator the animator to apply 7087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * @param currValue the current value 7187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * @param endValue the end value of the animator 7287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * @param velocity the current velocity of the motion 7387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi */ 7487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi public void apply(ValueAnimator animator, float currValue, float endValue, float velocity) { 751d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue)); 761d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi } 771d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi 781d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi /** 791d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * Applies the interpolator and length to the animator, such that the fling animation is 801d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * consistent with the finger motion. 811d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * 821d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param animator the animator to apply 831d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param currValue the current value 841d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param endValue the end value of the animator 851d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param velocity the current velocity of the motion 864c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek */ 874c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek public void apply(ViewPropertyAnimator animator, float currValue, float endValue, 884c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek float velocity) { 894c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue)); 904c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek } 914c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 924c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek /** 934c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * Applies the interpolator and length to the animator, such that the fling animation is 944c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * consistent with the finger motion. 954c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * 964c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param animator the animator to apply 974c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param currValue the current value 984c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param endValue the end value of the animator 994c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param velocity the current velocity of the motion 1001d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param maxDistance the maximum distance for this interaction; the maximum animation length 1011d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * gets multiplied by the ratio between the actual distance and this value 1021d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi */ 1031d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi public void apply(ValueAnimator animator, float currValue, float endValue, float velocity, 1041d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi float maxDistance) { 1054c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek AnimatorProperties properties = getProperties(currValue, endValue, velocity, 1064c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek maxDistance); 1074c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setDuration(properties.duration); 1084c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setInterpolator(properties.interpolator); 1094c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek } 1104c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 1114c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek /** 1124c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * Applies the interpolator and length to the animator, such that the fling animation is 1134c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * consistent with the finger motion. 1144c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * 1154c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param animator the animator to apply 1164c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param currValue the current value 1174c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param endValue the end value of the animator 1184c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param velocity the current velocity of the motion 1194c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param maxDistance the maximum distance for this interaction; the maximum animation length 1204c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * gets multiplied by the ratio between the actual distance and this value 1214c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek */ 1224c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek public void apply(ViewPropertyAnimator animator, float currValue, float endValue, 1234c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek float velocity, float maxDistance) { 1244c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek AnimatorProperties properties = getProperties(currValue, endValue, velocity, 1254c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek maxDistance); 1264c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setDuration(properties.duration); 1274c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setInterpolator(properties.interpolator); 1284c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek } 1294c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 1304c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek private AnimatorProperties getProperties(float currValue, 1314c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek float endValue, float velocity, float maxDistance) { 1321d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi float maxLengthSeconds = (float) (mMaxLengthSeconds 1331d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * Math.sqrt(Math.abs(endValue - currValue) / maxDistance)); 13487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi float diff = Math.abs(endValue - currValue); 13587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi float velAbs = Math.abs(velocity); 13687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi float durationSeconds = LINEAR_OUT_SLOW_IN_START_GRADIENT * diff / velAbs; 1371d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi if (durationSeconds <= maxLengthSeconds) { 1384c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek mAnimatorProperties.interpolator = mLinearOutSlowIn; 13987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } else if (velAbs >= mMinVelocityPxPerSecond) { 14087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 14187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi // Cross fade between fast-out-slow-in and linear interpolator with current velocity. 1421d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi durationSeconds = maxLengthSeconds; 14387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi VelocityInterpolator velocityInterpolator 14487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi = new VelocityInterpolator(durationSeconds, velAbs, diff); 14587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator( 14687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi velocityInterpolator, mLinearOutSlowIn, mLinearOutSlowIn); 1474c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek mAnimatorProperties.interpolator = superInterpolator; 14887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } else { 14987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 15087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi // Just use a normal interpolator which doesn't take the velocity into account. 1511d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi durationSeconds = maxLengthSeconds; 1524c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek mAnimatorProperties.interpolator = mFastOutSlowIn; 15387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 1544c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek mAnimatorProperties.duration = (long) (durationSeconds * 1000); 1554c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek return mAnimatorProperties; 15687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 15787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 15887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi /** 1591d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * Applies the interpolator and length to the animator, such that the fling animation is 1601d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * consistent with the finger motion for the case when the animation is making something 1611d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * disappear. 1621d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * 1631d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param animator the animator to apply 1641d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param currValue the current value 1651d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param endValue the end value of the animator 1661d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param velocity the current velocity of the motion 1671d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param maxDistance the maximum distance for this interaction; the maximum animation length 1681d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * gets multiplied by the ratio between the actual distance and this value 1691d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi */ 1701d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi public void applyDismissing(ValueAnimator animator, float currValue, float endValue, 1711d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi float velocity, float maxDistance) { 1724c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity, 1734c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek maxDistance); 1744c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setDuration(properties.duration); 1754c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setInterpolator(properties.interpolator); 1764c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek } 1774c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 1784c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek /** 1794c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * Applies the interpolator and length to the animator, such that the fling animation is 1804c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * consistent with the finger motion for the case when the animation is making something 1814c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * disappear. 1824c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * 1834c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param animator the animator to apply 1844c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param currValue the current value 1854c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param endValue the end value of the animator 1864c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param velocity the current velocity of the motion 1874c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param maxDistance the maximum distance for this interaction; the maximum animation length 1884c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * gets multiplied by the ratio between the actual distance and this value 1894c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek */ 1904c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek public void applyDismissing(ViewPropertyAnimator animator, float currValue, float endValue, 1914c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek float velocity, float maxDistance) { 1924c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity, 1934c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek maxDistance); 1944c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setDuration(properties.duration); 1954c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setInterpolator(properties.interpolator); 1964c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek } 1974c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 1984c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek private AnimatorProperties getDismissingProperties(float currValue, float endValue, 1994c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek float velocity, float maxDistance) { 2001d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi float maxLengthSeconds = (float) (mMaxLengthSeconds 2011d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * Math.pow(Math.abs(endValue - currValue) / maxDistance, 0.5f)); 2021d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi float diff = Math.abs(endValue - currValue); 2031d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi float velAbs = Math.abs(velocity); 204efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi float y2 = calculateLinearOutFasterInY2(velAbs); 205efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi 206efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi // The gradient at the start of the curve is just y2. 207efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi float startGradient = y2; 208efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi Interpolator mLinearOutFasterIn = new PathInterpolator(0, 0, 1, y2); 209efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi float durationSeconds = startGradient * diff / velAbs; 2101d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi if (durationSeconds <= maxLengthSeconds) { 2114c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek mAnimatorProperties.interpolator = mLinearOutFasterIn; 2121d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi } else if (velAbs >= mMinVelocityPxPerSecond) { 2131d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi 2141d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi // Cross fade between linear-out-faster-in and linear interpolator with current 2151d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi // velocity. 2161d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi durationSeconds = maxLengthSeconds; 2171d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi VelocityInterpolator velocityInterpolator 2181d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi = new VelocityInterpolator(durationSeconds, velAbs, diff); 2191d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator( 2201d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi velocityInterpolator, mLinearOutFasterIn, mLinearOutSlowIn); 2214c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek mAnimatorProperties.interpolator = superInterpolator; 2221d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi } else { 2231d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi 2241d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi // Just use a normal interpolator which doesn't take the velocity into account. 2251d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi durationSeconds = maxLengthSeconds; 2264c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek mAnimatorProperties.interpolator = mFastOutLinearIn; 2271d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi } 2284c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek mAnimatorProperties.duration = (long) (durationSeconds * 1000); 2294c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek return mAnimatorProperties; 2301d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi } 2311d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi 2321d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi /** 233efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi * Calculates the y2 control point for a linear-out-faster-in path interpolator depending on the 234efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi * velocity. The faster the velocity, the more "linear" the interpolator gets. 235efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi * 236efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi * @param velocity the velocity of the gesture. 237efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi * @return the y2 control point for a cubic bezier path interpolator 238efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi */ 239efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi private float calculateLinearOutFasterInY2(float velocity) { 240efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi float t = (velocity - mMinVelocityPxPerSecond) 241efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi / (mHighVelocityPxPerSecond - mMinVelocityPxPerSecond); 242efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi t = Math.max(0, Math.min(1, t)); 243efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi return (1 - t) * LINEAR_OUT_FASTER_IN_Y2_MIN + t * LINEAR_OUT_FASTER_IN_Y2_MAX; 244efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi } 245efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi 246efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi /** 2471d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @return the minimum velocity a gesture needs to have to be considered a fling 2481d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi */ 2491d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi public float getMinVelocityPxPerSecond() { 2501d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi return mMinVelocityPxPerSecond; 2511d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi } 2521d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi 2531d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi /** 25487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * An interpolator which interpolates two interpolators with an interpolator. 25587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi */ 25687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private static final class InterpolatorInterpolator implements Interpolator { 25787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 25887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private Interpolator mInterpolator1; 25987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private Interpolator mInterpolator2; 26087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private Interpolator mCrossfader; 26187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 26287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi InterpolatorInterpolator(Interpolator interpolator1, Interpolator interpolator2, 26387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi Interpolator crossfader) { 26487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mInterpolator1 = interpolator1; 26587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mInterpolator2 = interpolator2; 26687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mCrossfader = crossfader; 26787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 26887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 26987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi @Override 27087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi public float getInterpolation(float input) { 27187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi float t = mCrossfader.getInterpolation(input); 27287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi return (1 - t) * mInterpolator1.getInterpolation(input) 27387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi + t * mInterpolator2.getInterpolation(input); 27487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 27587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 27687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 27787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi /** 27887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * An interpolator which interpolates with a fixed velocity. 27987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi */ 28087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private static final class VelocityInterpolator implements Interpolator { 28187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 28287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private float mDurationSeconds; 28387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private float mVelocity; 28487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private float mDiff; 28587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 28687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private VelocityInterpolator(float durationSeconds, float velocity, float diff) { 28787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mDurationSeconds = durationSeconds; 28887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mVelocity = velocity; 28987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mDiff = diff; 29087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 29187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 29287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi @Override 29387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi public float getInterpolation(float input) { 29487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi float time = input * mDurationSeconds; 29587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi return time * mVelocity / mDiff; 29687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 29787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 2984c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 2994c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek private static class AnimatorProperties { 3004c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek Interpolator interpolator; 3014c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek long duration; 3024c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek } 3034c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 30487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi} 305