summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/util/FlingAnimation.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3/util/FlingAnimation.java')
-rw-r--r--src/com/android/launcher3/util/FlingAnimation.java104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/com/android/launcher3/util/FlingAnimation.java b/src/com/android/launcher3/util/FlingAnimation.java
new file mode 100644
index 000000000..55c5d7dc2
--- /dev/null
+++ b/src/com/android/launcher3/util/FlingAnimation.java
@@ -0,0 +1,104 @@
+package com.android.launcher3.util;
+
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.view.animation.DecelerateInterpolator;
+
+import com.android.launcher3.DragLayer;
+import com.android.launcher3.DragView;
+import com.android.launcher3.DropTarget.DragObject;
+
+public class FlingAnimation implements AnimatorUpdateListener {
+
+ /**
+ * Maximum acceleration in one dimension (pixels per milliseconds)
+ */
+ private static final float MAX_ACCELERATION = 0.5f;
+ private static final int DRAG_END_DELAY = 300;
+
+ protected final DragObject mDragObject;
+ protected final Rect mIconRect;
+ protected final DragLayer mDragLayer;
+ protected final Rect mFrom;
+ protected final int mDuration;
+ protected final float mUX, mUY;
+ protected final float mAnimationTimeFraction;
+ protected final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
+
+ protected float mAX, mAY;
+
+ /**
+ * @param vel initial fling velocity in pixels per second.
+ */
+ public FlingAnimation(DragObject d, PointF vel, Rect iconRect, DragLayer dragLayer) {
+ mDragObject = d;
+ mUX = vel.x / 1000;
+ mUY = vel.y / 1000;
+ mIconRect = iconRect;
+
+ mDragLayer = dragLayer;
+ mFrom = new Rect();
+ dragLayer.getViewRectRelativeToSelf(d.dragView, mFrom);
+
+ float scale = d.dragView.getScaleX();
+ float xOffset = ((scale - 1f) * d.dragView.getMeasuredWidth()) / 2f;
+ float yOffset = ((scale - 1f) * d.dragView.getMeasuredHeight()) / 2f;
+ mFrom.left += xOffset;
+ mFrom.right -= xOffset;
+ mFrom.top += yOffset;
+ mFrom.bottom -= yOffset;
+
+ mDuration = initDuration();
+ mAnimationTimeFraction = ((float) mDuration) / (mDuration + DRAG_END_DELAY);
+ }
+
+ /**
+ * The fling animation is based on the following system
+ * - Apply a constant force in the y direction to causing the fling to decelerate.
+ * - The animation runs for the time taken by the object to go out of the screen.
+ * - Calculate a constant acceleration in x direction such that the object reaches
+ * {@link #mIconRect} in the given time.
+ */
+ protected int initDuration() {
+ float sY = -mFrom.bottom;
+
+ float d = mUY * mUY + 2 * sY * MAX_ACCELERATION;
+ if (d >= 0) {
+ // sY can be reached under the MAX_ACCELERATION. Use MAX_ACCELERATION for y direction.
+ mAY = MAX_ACCELERATION;
+ } else {
+ // sY is not reachable, decrease the acceleration so that sY is almost reached.
+ d = 0;
+ mAY = mUY * mUY / (2 * -sY);
+ }
+ double t = (-mUY - Math.sqrt(d)) / mAY;
+
+ float sX = -mFrom.exactCenterX() + mIconRect.exactCenterX();
+
+ // Find horizontal acceleration such that: u*t + a*t*t/2 = s
+ mAX = (float) ((sX - t * mUX) * 2 / (t * t));
+ return (int) Math.round(t);
+ }
+
+ public final int getDuration() {
+ return mDuration + DRAG_END_DELAY;
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float t = animation.getAnimatedFraction();
+ if (t > mAnimationTimeFraction) {
+ t = 1;
+ } else {
+ t = t / mAnimationTimeFraction;
+ }
+ final DragView dragView = (DragView) mDragLayer.getAnimatedView();
+ final float time = t * mDuration;
+ dragView.setTranslationX(time * mUX + mFrom.left + mAX * time * time / 2);
+ dragView.setTranslationY(time * mUY + mFrom.top + mAY * time * time / 2);
+ dragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
+ }
+}