FlingAnimationUtils.java revision 593ee2084919a44936decd12e624625c18401347
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.content.Context; 214c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinekimport android.view.ViewPropertyAnimator; 2287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggiimport android.view.animation.Interpolator; 2387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggiimport android.view.animation.PathInterpolator; 2487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 25c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport com.android.systemui.Interpolators; 26593ee2084919a44936decd12e624625c18401347Selim Cinekimport com.android.systemui.statusbar.notification.NotificationUtils; 27c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson 2887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi/** 2987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * Utility class to calculate general fling animation when the finger is released. 3087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi */ 3187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggipublic class FlingAnimationUtils { 3287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 331d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi private static final float LINEAR_OUT_SLOW_IN_X2 = 0.35f; 34593ee2084919a44936decd12e624625c18401347Selim Cinek private static final float LINEAR_OUT_SLOW_IN_X2_MAX = 0.68f; 352580a976ec93a01ed00fae51364ad872bc591d95Jorim Jaggi private static final float LINEAR_OUT_FASTER_IN_X2 = 0.5f; 362580a976ec93a01ed00fae51364ad872bc591d95Jorim Jaggi private static final float LINEAR_OUT_FASTER_IN_Y2_MIN = 0.4f; 372580a976ec93a01ed00fae51364ad872bc591d95Jorim Jaggi private static final float LINEAR_OUT_FASTER_IN_Y2_MAX = 0.5f; 3887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private static final float MIN_VELOCITY_DP_PER_SECOND = 250; 39efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi private static final float HIGH_VELOCITY_DP_PER_SECOND = 3000; 4087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 41593ee2084919a44936decd12e624625c18401347Selim Cinek private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 0.75f; 42593ee2084919a44936decd12e624625c18401347Selim Cinek private final float mSpeedUpFactor; 431d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi 4487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private float mMinVelocityPxPerSecond; 451d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi private float mMaxLengthSeconds; 46efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi private float mHighVelocityPxPerSecond; 47593ee2084919a44936decd12e624625c18401347Selim Cinek private float mLinearOutSlowInX2; 4887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 494c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek private AnimatorProperties mAnimatorProperties = new AnimatorProperties(); 50593ee2084919a44936decd12e624625c18401347Selim Cinek private PathInterpolator mInterpolator; 51593ee2084919a44936decd12e624625c18401347Selim Cinek private float mCachedStartGradient = -1; 52593ee2084919a44936decd12e624625c18401347Selim Cinek private float mCachedVelocityFactor = -1; 534c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 541d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi public FlingAnimationUtils(Context ctx, float maxLengthSeconds) { 55593ee2084919a44936decd12e624625c18401347Selim Cinek this(ctx, maxLengthSeconds, 0.0f); 56593ee2084919a44936decd12e624625c18401347Selim Cinek } 57593ee2084919a44936decd12e624625c18401347Selim Cinek 58593ee2084919a44936decd12e624625c18401347Selim Cinek /** 59593ee2084919a44936decd12e624625c18401347Selim Cinek * @param maxLengthSeconds the longest duration an animation can become in seconds 60593ee2084919a44936decd12e624625c18401347Selim Cinek * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards 61593ee2084919a44936decd12e624625c18401347Selim Cinek * the end of the animation. 0 means it's at the beginning and no 62593ee2084919a44936decd12e624625c18401347Selim Cinek * acceleration will take place. 63593ee2084919a44936decd12e624625c18401347Selim Cinek */ 64593ee2084919a44936decd12e624625c18401347Selim Cinek public FlingAnimationUtils(Context ctx, float maxLengthSeconds, float speedUpFactor) { 651d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi mMaxLengthSeconds = maxLengthSeconds; 66593ee2084919a44936decd12e624625c18401347Selim Cinek mSpeedUpFactor = speedUpFactor; 67593ee2084919a44936decd12e624625c18401347Selim Cinek mLinearOutSlowInX2 = NotificationUtils.interpolate(LINEAR_OUT_SLOW_IN_X2, 68593ee2084919a44936decd12e624625c18401347Selim Cinek LINEAR_OUT_SLOW_IN_X2_MAX, 69593ee2084919a44936decd12e624625c18401347Selim Cinek mSpeedUpFactor); 70593ee2084919a44936decd12e624625c18401347Selim Cinek 7187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mMinVelocityPxPerSecond 7287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi = MIN_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density; 73efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi mHighVelocityPxPerSecond 74efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi = HIGH_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density; 7587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 7687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 7787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi /** 7887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * Applies the interpolator and length to the animator, such that the fling animation is 7987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * consistent with the finger motion. 8087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * 8187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * @param animator the animator to apply 8287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * @param currValue the current value 8387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * @param endValue the end value of the animator 8487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * @param velocity the current velocity of the motion 8587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi */ 86b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi public void apply(Animator animator, float currValue, float endValue, float velocity) { 871d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue)); 881d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi } 891d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi 901d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi /** 911d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * Applies the interpolator and length to the animator, such that the fling animation is 921d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * consistent with the finger motion. 931d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * 941d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param animator the animator to apply 951d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param currValue the current value 961d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param endValue the end value of the animator 971d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param velocity the current velocity of the motion 984c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek */ 994c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek public void apply(ViewPropertyAnimator animator, float currValue, float endValue, 1004c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek float velocity) { 1014c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue)); 1024c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek } 1034c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 1044c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek /** 1054c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * Applies the interpolator and length to the animator, such that the fling animation is 1064c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * consistent with the finger motion. 1074c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * 1084c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param animator the animator to apply 1094c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param currValue the current value 1104c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param endValue the end value of the animator 1114c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param velocity the current velocity of the motion 1121d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param maxDistance the maximum distance for this interaction; the maximum animation length 1131d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * gets multiplied by the ratio between the actual distance and this value 1141d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi */ 115b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi public void apply(Animator animator, float currValue, float endValue, float velocity, 1161d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi float maxDistance) { 1174c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek AnimatorProperties properties = getProperties(currValue, endValue, velocity, 1184c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek maxDistance); 1194c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setDuration(properties.duration); 1204c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setInterpolator(properties.interpolator); 1214c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek } 1224c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 1234c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek /** 1244c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * Applies the interpolator and length to the animator, such that the fling animation is 1254c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * consistent with the finger motion. 1264c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * 1274c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param animator the animator to apply 1284c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param currValue the current value 1294c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param endValue the end value of the animator 1304c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param velocity the current velocity of the motion 1314c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param maxDistance the maximum distance for this interaction; the maximum animation length 1324c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * gets multiplied by the ratio between the actual distance and this value 1334c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek */ 1344c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek public void apply(ViewPropertyAnimator animator, float currValue, float endValue, 1354c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek float velocity, float maxDistance) { 1364c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek AnimatorProperties properties = getProperties(currValue, endValue, velocity, 1374c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek maxDistance); 1384c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setDuration(properties.duration); 1394c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setInterpolator(properties.interpolator); 1404c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek } 1414c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 1424c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek private AnimatorProperties getProperties(float currValue, 1434c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek float endValue, float velocity, float maxDistance) { 1441d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi float maxLengthSeconds = (float) (mMaxLengthSeconds 1451d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * Math.sqrt(Math.abs(endValue - currValue) / maxDistance)); 14687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi float diff = Math.abs(endValue - currValue); 14787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi float velAbs = Math.abs(velocity); 148593ee2084919a44936decd12e624625c18401347Selim Cinek float velocityFactor = mSpeedUpFactor == 0.0f 149593ee2084919a44936decd12e624625c18401347Selim Cinek ? 1.0f : Math.min(velAbs / HIGH_VELOCITY_DP_PER_SECOND, 1.0f); 150593ee2084919a44936decd12e624625c18401347Selim Cinek float startGradient = NotificationUtils.interpolate(LINEAR_OUT_SLOW_IN_START_GRADIENT, 151593ee2084919a44936decd12e624625c18401347Selim Cinek 1.0f / mLinearOutSlowInX2, velocityFactor); 152593ee2084919a44936decd12e624625c18401347Selim Cinek float durationSeconds = startGradient * diff / velAbs; 153593ee2084919a44936decd12e624625c18401347Selim Cinek Interpolator slowInInterpolator = getInterpolator(startGradient, velocityFactor); 1541d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi if (durationSeconds <= maxLengthSeconds) { 155593ee2084919a44936decd12e624625c18401347Selim Cinek mAnimatorProperties.interpolator = slowInInterpolator; 15687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } else if (velAbs >= mMinVelocityPxPerSecond) { 15787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 15887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi // Cross fade between fast-out-slow-in and linear interpolator with current velocity. 1591d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi durationSeconds = maxLengthSeconds; 16087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi VelocityInterpolator velocityInterpolator 16187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi = new VelocityInterpolator(durationSeconds, velAbs, diff); 16287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator( 163593ee2084919a44936decd12e624625c18401347Selim Cinek velocityInterpolator, slowInInterpolator, Interpolators.LINEAR_OUT_SLOW_IN); 1644c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek mAnimatorProperties.interpolator = superInterpolator; 16587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } else { 16687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 16787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi // Just use a normal interpolator which doesn't take the velocity into account. 1681d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi durationSeconds = maxLengthSeconds; 169c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek mAnimatorProperties.interpolator = Interpolators.FAST_OUT_SLOW_IN; 17087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 1714c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek mAnimatorProperties.duration = (long) (durationSeconds * 1000); 1724c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek return mAnimatorProperties; 17387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 17487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 175593ee2084919a44936decd12e624625c18401347Selim Cinek private Interpolator getInterpolator(float startGradient, float velocityFactor) { 176593ee2084919a44936decd12e624625c18401347Selim Cinek if (startGradient != mCachedStartGradient 177593ee2084919a44936decd12e624625c18401347Selim Cinek || velocityFactor != mCachedVelocityFactor) { 178593ee2084919a44936decd12e624625c18401347Selim Cinek float speedup = mSpeedUpFactor * (1.0f - velocityFactor); 179593ee2084919a44936decd12e624625c18401347Selim Cinek mInterpolator = new PathInterpolator(speedup, 180593ee2084919a44936decd12e624625c18401347Selim Cinek speedup * startGradient, 181593ee2084919a44936decd12e624625c18401347Selim Cinek mLinearOutSlowInX2, 1); 182593ee2084919a44936decd12e624625c18401347Selim Cinek mCachedStartGradient = startGradient; 183593ee2084919a44936decd12e624625c18401347Selim Cinek mCachedVelocityFactor = velocityFactor; 184593ee2084919a44936decd12e624625c18401347Selim Cinek } 185593ee2084919a44936decd12e624625c18401347Selim Cinek return mInterpolator; 186593ee2084919a44936decd12e624625c18401347Selim Cinek } 187593ee2084919a44936decd12e624625c18401347Selim Cinek 18887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi /** 1891d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * Applies the interpolator and length to the animator, such that the fling animation is 1901d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * consistent with the finger motion for the case when the animation is making something 1911d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * disappear. 1921d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * 1931d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param animator the animator to apply 1941d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param currValue the current value 1951d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param endValue the end value of the animator 1961d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param velocity the current velocity of the motion 1971d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @param maxDistance the maximum distance for this interaction; the maximum animation length 1981d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * gets multiplied by the ratio between the actual distance and this value 1991d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi */ 200b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi public void applyDismissing(Animator animator, float currValue, float endValue, 2011d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi float velocity, float maxDistance) { 2024c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity, 2034c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek maxDistance); 2044c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setDuration(properties.duration); 2054c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setInterpolator(properties.interpolator); 2064c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek } 2074c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 2084c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek /** 2094c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * Applies the interpolator and length to the animator, such that the fling animation is 2104c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * consistent with the finger motion for the case when the animation is making something 2114c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * disappear. 2124c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * 2134c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param animator the animator to apply 2144c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param currValue the current value 2154c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param endValue the end value of the animator 2164c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param velocity the current velocity of the motion 2174c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * @param maxDistance the maximum distance for this interaction; the maximum animation length 2184c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek * gets multiplied by the ratio between the actual distance and this value 2194c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek */ 2204c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek public void applyDismissing(ViewPropertyAnimator animator, float currValue, float endValue, 2214c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek float velocity, float maxDistance) { 2224c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity, 2234c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek maxDistance); 2244c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setDuration(properties.duration); 2254c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek animator.setInterpolator(properties.interpolator); 2264c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek } 2274c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 2284c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek private AnimatorProperties getDismissingProperties(float currValue, float endValue, 2294c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek float velocity, float maxDistance) { 2301d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi float maxLengthSeconds = (float) (mMaxLengthSeconds 2311d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * Math.pow(Math.abs(endValue - currValue) / maxDistance, 0.5f)); 2321d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi float diff = Math.abs(endValue - currValue); 2331d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi float velAbs = Math.abs(velocity); 234efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi float y2 = calculateLinearOutFasterInY2(velAbs); 235efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi 2362580a976ec93a01ed00fae51364ad872bc591d95Jorim Jaggi float startGradient = y2 / LINEAR_OUT_FASTER_IN_X2; 2372580a976ec93a01ed00fae51364ad872bc591d95Jorim Jaggi Interpolator mLinearOutFasterIn = new PathInterpolator(0, 0, LINEAR_OUT_FASTER_IN_X2, y2); 238efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi float durationSeconds = startGradient * diff / velAbs; 2391d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi if (durationSeconds <= maxLengthSeconds) { 2404c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek mAnimatorProperties.interpolator = mLinearOutFasterIn; 2411d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi } else if (velAbs >= mMinVelocityPxPerSecond) { 2421d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi 2431d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi // Cross fade between linear-out-faster-in and linear interpolator with current 2441d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi // velocity. 2451d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi durationSeconds = maxLengthSeconds; 2461d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi VelocityInterpolator velocityInterpolator 2471d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi = new VelocityInterpolator(durationSeconds, velAbs, diff); 2481d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator( 249593ee2084919a44936decd12e624625c18401347Selim Cinek velocityInterpolator, mLinearOutFasterIn, Interpolators.LINEAR_OUT_SLOW_IN); 2504c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek mAnimatorProperties.interpolator = superInterpolator; 2511d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi } else { 2521d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi 2531d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi // Just use a normal interpolator which doesn't take the velocity into account. 2541d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi durationSeconds = maxLengthSeconds; 255c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek mAnimatorProperties.interpolator = Interpolators.FAST_OUT_LINEAR_IN; 2561d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi } 2574c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek mAnimatorProperties.duration = (long) (durationSeconds * 1000); 2584c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek return mAnimatorProperties; 2591d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi } 2601d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi 2611d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi /** 262efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi * Calculates the y2 control point for a linear-out-faster-in path interpolator depending on the 263efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi * velocity. The faster the velocity, the more "linear" the interpolator gets. 264efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi * 265efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi * @param velocity the velocity of the gesture. 266efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi * @return the y2 control point for a cubic bezier path interpolator 267efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi */ 268efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi private float calculateLinearOutFasterInY2(float velocity) { 269efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi float t = (velocity - mMinVelocityPxPerSecond) 270efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi / (mHighVelocityPxPerSecond - mMinVelocityPxPerSecond); 271efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi t = Math.max(0, Math.min(1, t)); 272efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi return (1 - t) * LINEAR_OUT_FASTER_IN_Y2_MIN + t * LINEAR_OUT_FASTER_IN_Y2_MAX; 273efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi } 274efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi 275efbd7e3bb8244efae2561f0d9d7cedb36b1730bdJorim Jaggi /** 2761d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi * @return the minimum velocity a gesture needs to have to be considered a fling 2771d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi */ 2781d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi public float getMinVelocityPxPerSecond() { 2791d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi return mMinVelocityPxPerSecond; 2801d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi } 2811d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi 2821d480695df31f1c328473f32d5007cea6a03b6e0Jorim Jaggi /** 28387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * An interpolator which interpolates two interpolators with an interpolator. 28487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi */ 28587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private static final class InterpolatorInterpolator implements Interpolator { 28687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 28787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private Interpolator mInterpolator1; 28887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private Interpolator mInterpolator2; 28987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private Interpolator mCrossfader; 29087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 29187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi InterpolatorInterpolator(Interpolator interpolator1, Interpolator interpolator2, 29287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi Interpolator crossfader) { 29387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mInterpolator1 = interpolator1; 29487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mInterpolator2 = interpolator2; 29587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mCrossfader = crossfader; 29687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 29787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 29887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi @Override 29987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi public float getInterpolation(float input) { 30087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi float t = mCrossfader.getInterpolation(input); 30187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi return (1 - t) * mInterpolator1.getInterpolation(input) 30287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi + t * mInterpolator2.getInterpolation(input); 30387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 30487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 30587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 30687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi /** 30787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi * An interpolator which interpolates with a fixed velocity. 30887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi */ 30987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private static final class VelocityInterpolator implements Interpolator { 31087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 31187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private float mDurationSeconds; 31287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private float mVelocity; 31387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private float mDiff; 31487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 31587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi private VelocityInterpolator(float durationSeconds, float velocity, float diff) { 31687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mDurationSeconds = durationSeconds; 31787cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mVelocity = velocity; 31887cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi mDiff = diff; 31987cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 32087cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi 32187cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi @Override 32287cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi public float getInterpolation(float input) { 32387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi float time = input * mDurationSeconds; 32487cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi return time * mVelocity / mDiff; 32587cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 32687cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi } 3274c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 3284c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek private static class AnimatorProperties { 3294c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek Interpolator interpolator; 3304c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek long duration; 3314c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek } 3324c6969a512cd70831249ec1d07691f16fe5465f5Selim Cinek 33387cd5e71ec087e191b8baaa8913a878f92d4e10dJorim Jaggi} 334