Loading core/java/android/widget/EdgeEffect.java +79 −43 Original line number Diff line number Diff line Loading @@ -97,12 +97,28 @@ public class EdgeEffect { */ private static final double VELOCITY_THRESHOLD = 0.01; /** * The speed at which we should start linearly interpolating to the destination. * When using a spring, as it gets closer to the destination, the speed drops off exponentially. * Instead of landing very slowly, a better experience is achieved if the final * destination is arrived at quicker. */ private static final float LINEAR_VELOCITY_TAKE_OVER = 200f; /** * The value threshold before the spring animation is considered close enough to * the destination to be settled. This should be around 0.01 pixel. */ private static final double VALUE_THRESHOLD = 0.001; /** * The maximum distance at which we should start linearly interpolating to the destination. * When using a spring, as it gets closer to the destination, the speed drops off exponentially. * Instead of landing very slowly, a better experience is achieved if the final * destination is arrived at quicker. */ private static final double LINEAR_DISTANCE_TAKE_OVER = 8.0; /** * The natural frequency of the stretch spring. */ Loading Loading @@ -587,6 +603,7 @@ public class EdgeEffect { if (mState == STATE_RECEDE) { updateSpring(); } if (mDistance != 0f) { RecordingCanvas recordingCanvas = (RecordingCanvas) canvas; if (mTmpMatrix == null) { mTmpMatrix = new Matrix(); Loading Loading @@ -637,6 +654,7 @@ public class EdgeEffect { mHeight // max vertical stretch in pixels ); } } } else { // Animations have been disabled or this is TYPE_STRETCH and drawing into a Canvas // that isn't a Recording Canvas, so no effect can be shown. Just end the effect. Loading Loading @@ -730,6 +748,26 @@ public class EdgeEffect { if (deltaT < 0.001f) { return; // Must have at least 1 ms difference } mStartTime = time; if (Math.abs(mVelocity) <= LINEAR_VELOCITY_TAKE_OVER && Math.abs(mDistance * mHeight) < LINEAR_DISTANCE_TAKE_OVER && Math.signum(mVelocity) == -Math.signum(mDistance) ) { // This is close. The spring will slowly reach the destination. Instead, we // will interpolate linearly so that it arrives at its destination quicker. mVelocity = Math.signum(mVelocity) * LINEAR_VELOCITY_TAKE_OVER; float targetDistance = mDistance + (mVelocity * deltaT / mHeight); if (Math.signum(targetDistance) != Math.signum(mDistance)) { // We have arrived mDistance = 0; mVelocity = 0; } else { mDistance = targetDistance; } return; } final double mDampedFreq = NATURAL_FREQUENCY * Math.sqrt(1 - DAMPING_RATIO * DAMPING_RATIO); // We're always underdamped, so we can use only those equations: Loading @@ -745,9 +783,7 @@ public class EdgeEffect { + mDampedFreq * sinCoeff * Math.cos(mDampedFreq * deltaT)); mDistance = (float) distance / mHeight; mVelocity = (float) velocity; mStartTime = time; if (isAtEquilibrium()) { mState = STATE_IDLE; mDistance = 0; mVelocity = 0; } Loading libs/hwui/effects/StretchEffect.h +13 −3 Original line number Diff line number Diff line Loading @@ -40,9 +40,7 @@ public: StretchEffect() {} bool isEmpty() const { return MathUtils::isZero(mStretchDirection.x()) && MathUtils::isZero(mStretchDirection.y()); } bool isEmpty() const { return isZero(mStretchDirection.x()) && isZero(mStretchDirection.y()); } void setEmpty() { *this = StretchEffect{}; Loading Loading @@ -118,6 +116,18 @@ public: } private: // The epsilon for StretchEffect is less than in MathUtils because // the range is 0-1 for an entire screen and should be significantly // less than 1 pixel for a smooth stretch animation. inline static bool isZero(float value) { // Using fabsf is more performant as ARM computes // fabsf in a single instruction. return fabsf(value) <= NON_ZERO_EPSILON; } // This should be good for 1/25,000 of a screen and should be good for // screens with less than ~8000 pixels in one dimension with only 1/4 pixel // cut-off. static constexpr float NON_ZERO_EPSILON = 0.00004f; static sk_sp<SkRuntimeEffect> getStretchEffect(); mutable SkVector mStretchDirection{0, 0}; mutable std::unique_ptr<SkRuntimeShaderBuilder> mBuilder; Loading Loading
core/java/android/widget/EdgeEffect.java +79 −43 Original line number Diff line number Diff line Loading @@ -97,12 +97,28 @@ public class EdgeEffect { */ private static final double VELOCITY_THRESHOLD = 0.01; /** * The speed at which we should start linearly interpolating to the destination. * When using a spring, as it gets closer to the destination, the speed drops off exponentially. * Instead of landing very slowly, a better experience is achieved if the final * destination is arrived at quicker. */ private static final float LINEAR_VELOCITY_TAKE_OVER = 200f; /** * The value threshold before the spring animation is considered close enough to * the destination to be settled. This should be around 0.01 pixel. */ private static final double VALUE_THRESHOLD = 0.001; /** * The maximum distance at which we should start linearly interpolating to the destination. * When using a spring, as it gets closer to the destination, the speed drops off exponentially. * Instead of landing very slowly, a better experience is achieved if the final * destination is arrived at quicker. */ private static final double LINEAR_DISTANCE_TAKE_OVER = 8.0; /** * The natural frequency of the stretch spring. */ Loading Loading @@ -587,6 +603,7 @@ public class EdgeEffect { if (mState == STATE_RECEDE) { updateSpring(); } if (mDistance != 0f) { RecordingCanvas recordingCanvas = (RecordingCanvas) canvas; if (mTmpMatrix == null) { mTmpMatrix = new Matrix(); Loading Loading @@ -637,6 +654,7 @@ public class EdgeEffect { mHeight // max vertical stretch in pixels ); } } } else { // Animations have been disabled or this is TYPE_STRETCH and drawing into a Canvas // that isn't a Recording Canvas, so no effect can be shown. Just end the effect. Loading Loading @@ -730,6 +748,26 @@ public class EdgeEffect { if (deltaT < 0.001f) { return; // Must have at least 1 ms difference } mStartTime = time; if (Math.abs(mVelocity) <= LINEAR_VELOCITY_TAKE_OVER && Math.abs(mDistance * mHeight) < LINEAR_DISTANCE_TAKE_OVER && Math.signum(mVelocity) == -Math.signum(mDistance) ) { // This is close. The spring will slowly reach the destination. Instead, we // will interpolate linearly so that it arrives at its destination quicker. mVelocity = Math.signum(mVelocity) * LINEAR_VELOCITY_TAKE_OVER; float targetDistance = mDistance + (mVelocity * deltaT / mHeight); if (Math.signum(targetDistance) != Math.signum(mDistance)) { // We have arrived mDistance = 0; mVelocity = 0; } else { mDistance = targetDistance; } return; } final double mDampedFreq = NATURAL_FREQUENCY * Math.sqrt(1 - DAMPING_RATIO * DAMPING_RATIO); // We're always underdamped, so we can use only those equations: Loading @@ -745,9 +783,7 @@ public class EdgeEffect { + mDampedFreq * sinCoeff * Math.cos(mDampedFreq * deltaT)); mDistance = (float) distance / mHeight; mVelocity = (float) velocity; mStartTime = time; if (isAtEquilibrium()) { mState = STATE_IDLE; mDistance = 0; mVelocity = 0; } Loading
libs/hwui/effects/StretchEffect.h +13 −3 Original line number Diff line number Diff line Loading @@ -40,9 +40,7 @@ public: StretchEffect() {} bool isEmpty() const { return MathUtils::isZero(mStretchDirection.x()) && MathUtils::isZero(mStretchDirection.y()); } bool isEmpty() const { return isZero(mStretchDirection.x()) && isZero(mStretchDirection.y()); } void setEmpty() { *this = StretchEffect{}; Loading Loading @@ -118,6 +116,18 @@ public: } private: // The epsilon for StretchEffect is less than in MathUtils because // the range is 0-1 for an entire screen and should be significantly // less than 1 pixel for a smooth stretch animation. inline static bool isZero(float value) { // Using fabsf is more performant as ARM computes // fabsf in a single instruction. return fabsf(value) <= NON_ZERO_EPSILON; } // This should be good for 1/25,000 of a screen and should be good for // screens with less than ~8000 pixels in one dimension with only 1/4 pixel // cut-off. static constexpr float NON_ZERO_EPSILON = 0.00004f; static sk_sp<SkRuntimeEffect> getStretchEffect(); mutable SkVector mStretchDirection{0, 0}; mutable std::unique_ptr<SkRuntimeShaderBuilder> mBuilder; Loading