1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.launcher3.anim; 17 18 import android.content.Context; 19 20 import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener; 21 import androidx.dynamicanimation.animation.FlingAnimation; 22 import androidx.dynamicanimation.animation.FloatPropertyCompat; 23 import androidx.dynamicanimation.animation.SpringAnimation; 24 import androidx.dynamicanimation.animation.SpringForce; 25 26 import com.android.launcher3.R; 27 import com.android.launcher3.util.DynamicResource; 28 import com.android.systemui.plugins.ResourceProvider; 29 30 /** 31 * Given a property to animate and a target value and starting velocity, first apply friction to 32 * the fling until we pass the target, then apply a spring force to pull towards the target. 33 */ 34 public class FlingSpringAnim { 35 36 private final FlingAnimation mFlingAnim; 37 private SpringAnimation mSpringAnim; 38 private final boolean mSkipFlingAnim; 39 40 private float mTargetPosition; 41 FlingSpringAnim(K object, Context context, FloatPropertyCompat<K> property, float startPosition, float targetPosition, float startVelocity, float minVisChange, float minValue, float maxValue, float springVelocityFactor, OnAnimationEndListener onEndListener)42 public <K> FlingSpringAnim(K object, Context context, FloatPropertyCompat<K> property, 43 float startPosition, float targetPosition, float startVelocity, float minVisChange, 44 float minValue, float maxValue, float springVelocityFactor, 45 OnAnimationEndListener onEndListener) { 46 ResourceProvider rp = DynamicResource.provider(context); 47 float damping = rp.getFloat(R.dimen.swipe_up_rect_xy_damping_ratio); 48 float stiffness = rp.getFloat(R.dimen.swipe_up_rect_xy_stiffness); 49 float friction = rp.getFloat(R.dimen.swipe_up_rect_xy_fling_friction); 50 51 mFlingAnim = new FlingAnimation(object, property) 52 .setFriction(friction) 53 // Have the spring pull towards the target if we've slowed down too much before 54 // reaching it. 55 .setMinimumVisibleChange(minVisChange) 56 .setStartVelocity(startVelocity) 57 .setMinValue(minValue) 58 .setMaxValue(maxValue); 59 mTargetPosition = targetPosition; 60 61 // We are already past the fling target, so skip it to avoid losing a frame of the spring. 62 mSkipFlingAnim = startPosition <= minValue && startVelocity < 0 63 || startPosition >= maxValue && startVelocity > 0; 64 65 mFlingAnim.addEndListener(((animation, canceled, value, velocity) -> { 66 mSpringAnim = new SpringAnimation(object, property) 67 .setStartValue(value) 68 .setStartVelocity(velocity * springVelocityFactor) 69 .setSpring(new SpringForce(mTargetPosition) 70 .setStiffness(stiffness) 71 .setDampingRatio(damping)); 72 mSpringAnim.addEndListener(onEndListener); 73 mSpringAnim.animateToFinalPosition(mTargetPosition); 74 })); 75 } 76 getTargetPosition()77 public float getTargetPosition() { 78 return mTargetPosition; 79 } 80 updatePosition(float startPosition, float targetPosition)81 public void updatePosition(float startPosition, float targetPosition) { 82 mFlingAnim.setMinValue(Math.min(startPosition, targetPosition)) 83 .setMaxValue(Math.max(startPosition, targetPosition)); 84 mTargetPosition = targetPosition; 85 if (mSpringAnim != null) { 86 mSpringAnim.animateToFinalPosition(mTargetPosition); 87 } 88 } 89 start()90 public void start() { 91 mFlingAnim.start(); 92 if (mSkipFlingAnim) { 93 mFlingAnim.cancel(); 94 } 95 } 96 end()97 public void end() { 98 mFlingAnim.cancel(); 99 if (mSpringAnim.canSkipToEnd()) { 100 mSpringAnim.skipToEnd(); 101 } 102 } 103 } 104