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 startVelocityPxPerS, float minVisChange, float minValue, float maxValue, float damping, float stiffness, OnAnimationEndListener onEndListener)42 public <K> FlingSpringAnim(K object, Context context, FloatPropertyCompat<K> property, 43 float startPosition, float targetPosition, float startVelocityPxPerS, 44 float minVisChange, float minValue, float maxValue, float damping, float stiffness, 45 OnAnimationEndListener onEndListener) { 46 ResourceProvider rp = DynamicResource.provider(context); 47 float friction = rp.getFloat(R.dimen.swipe_up_rect_xy_fling_friction); 48 49 mFlingAnim = new FlingAnimation(object, property) 50 .setFriction(friction) 51 // Have the spring pull towards the target if we've slowed down too much before 52 // reaching it. 53 .setMinimumVisibleChange(minVisChange) 54 .setStartVelocity(startVelocityPxPerS) 55 .setMinValue(minValue) 56 .setMaxValue(maxValue); 57 mTargetPosition = targetPosition; 58 59 // We are already past the fling target, so skip it to avoid losing a frame of the spring. 60 mSkipFlingAnim = startPosition <= minValue && startVelocityPxPerS < 0 61 || startPosition >= maxValue && startVelocityPxPerS > 0; 62 63 mFlingAnim.addEndListener(((animation, canceled, value, velocity) -> { 64 mSpringAnim = new SpringAnimation(object, property) 65 .setStartValue(value) 66 .setStartVelocity(velocity) 67 .setSpring(new SpringForce(mTargetPosition) 68 .setStiffness(stiffness) 69 .setDampingRatio(damping)); 70 mSpringAnim.addEndListener(onEndListener); 71 mSpringAnim.animateToFinalPosition(mTargetPosition); 72 })); 73 } 74 getTargetPosition()75 public float getTargetPosition() { 76 return mTargetPosition; 77 } 78 updatePosition(float startPosition, float targetPosition)79 public void updatePosition(float startPosition, float targetPosition) { 80 mFlingAnim.setMinValue(Math.min(startPosition, targetPosition)) 81 .setMaxValue(Math.max(startPosition, targetPosition)); 82 mTargetPosition = targetPosition; 83 if (mSpringAnim != null) { 84 mSpringAnim.animateToFinalPosition(mTargetPosition); 85 } 86 } 87 start()88 public void start() { 89 mFlingAnim.start(); 90 if (mSkipFlingAnim) { 91 mFlingAnim.cancel(); 92 } 93 } 94 end()95 public void end() { 96 mFlingAnim.cancel(); 97 if (mSpringAnim.canSkipToEnd()) { 98 mSpringAnim.skipToEnd(); 99 } 100 } 101 } 102