Overshoot when flinging up from an app

- Use OvershootInterpolator based on velocity (consistent with swiping up
  from home)
- Scale down recents as well, to be consistent with adjacent pages scaling
  up when you launch a task

Bug: 109709720
Change-Id: Ie47309058ccf673a4b86c40c843c415beb2d8dc7
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 4bd9a9b..5355c5e 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -272,6 +272,24 @@
         return scale;
     }
 
+    /**
+     * Maps t from one range to another range.
+     * @param t The value to map.
+     * @param fromMin The lower bound of the range that t is being mapped from.
+     * @param fromMax The upper bound of the range that t is being mapped from.
+     * @param toMin The lower bound of the range that t is being mapped to.
+     * @param toMax The upper bound of the range that t is being mapped to.
+     * @return The mapped value of t.
+     */
+    public static float mapToRange(float t, float fromMin, float fromMax, float toMin, float toMax) {
+        if (fromMin == fromMax || toMin == toMax) {
+            Log.e(TAG, "mapToRange: range has 0 length");
+            return toMin;
+        }
+        float progress = Math.abs(t - fromMin) / Math.abs(fromMax - fromMin);
+        return mapRange(progress, toMin, toMax);
+    }
+
     public static float mapRange(float value, float min, float max) {
         return min + (value * (max - min));
     }
@@ -463,6 +481,13 @@
     }
 
     /**
+     * @see #boundToRange(int, int, int).
+     */
+    public static long boundToRange(long value, long lowerBound, long upperBound) {
+        return Math.max(lowerBound, Math.min(value, upperBound));
+    }
+
+    /**
      * Wraps a message with a TTS span, so that a different message is spoken than
      * what is getting displayed.
      * @param msg original message
diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
index 84085cb..50fb0a5 100644
--- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java
+++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
@@ -202,6 +202,19 @@
         }
     }
 
+    public void dispatchSetInterpolator(TimeInterpolator interpolator) {
+        dispatchSetInterpolatorRecursively(mAnim, interpolator);
+    }
+
+    private void dispatchSetInterpolatorRecursively(Animator anim, TimeInterpolator interpolator) {
+        anim.setInterpolator(interpolator);
+        if (anim instanceof AnimatorSet) {
+            for (Animator child : nonNullList(((AnimatorSet) anim).getChildAnimations())) {
+                dispatchSetInterpolatorRecursively(child, interpolator);
+            }
+        }
+    }
+
     public void setOnCancelRunnable(Runnable runnable) {
         mOnCancelRunnable = runnable;
     }
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index bace7df..d17572e 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -24,6 +24,8 @@
 import android.view.animation.OvershootInterpolator;
 import android.view.animation.PathInterpolator;
 
+import com.android.launcher3.Utilities;
+
 
 /**
  * Common interpolators used in Launcher
@@ -116,6 +118,19 @@
         return Math.abs(velocity) > FAST_FLING_PX_MS ? SCROLL : SCROLL_CUBIC;
     }
 
+    public static Interpolator overshootInterpolatorForVelocity(float velocity) {
+        return overshootInterpolatorForVelocity(velocity, 1f);
+    }
+
+    /**
+     * Create an OvershootInterpolator with tension directly related to the velocity (in px/ms).
+     * @param velocity The start velocity of the animation we want to overshoot.
+     * @param dampFactor An optional factor to reduce the amount of tension (how far we overshoot).
+     */
+    public static Interpolator overshootInterpolatorForVelocity(float velocity, float dampFactor) {
+        return new OvershootInterpolator(Math.min(Math.abs(velocity), 3f) / dampFactor);
+    }
+
     /**
      * Runs the given interpolator such that the entire progress is set between the given bounds.
      * That is, we set the interpolation to 0 until lowerBound and reach 1 by upperBound.
@@ -135,4 +150,15 @@
             return interpolator.getInterpolation((t - lowerBound) / (upperBound - lowerBound));
         };
     }
+
+    /**
+     * Runs the given interpolator such that the interpolated value is mapped to the given range.
+     * This is useful, for example, if we only use this interpolator for part of the animation,
+     * such as to take over a user-controlled animation when they let go.
+     */
+    public static Interpolator mapToProgress(Interpolator interpolator, float lowerBound,
+            float upperBound) {
+        return t -> Utilities.mapToRange(interpolator.getInterpolation(t), 0, 1,
+                lowerBound, upperBound);
+    }
 }
\ No newline at end of file