• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.launcher3.util;
2 
3 import android.animation.TimeInterpolator;
4 import android.animation.ValueAnimator;
5 import android.animation.ValueAnimator.AnimatorUpdateListener;
6 import android.graphics.PointF;
7 import android.graphics.Rect;
8 import android.view.animation.DecelerateInterpolator;
9 
10 import com.android.launcher3.DragLayer;
11 import com.android.launcher3.DragView;
12 import com.android.launcher3.DropTarget.DragObject;
13 
14 public class FlingAnimation implements AnimatorUpdateListener {
15 
16     /**
17      * Maximum acceleration in one dimension (pixels per milliseconds)
18      */
19     private static final float MAX_ACCELERATION = 0.5f;
20     private static final int DRAG_END_DELAY = 300;
21 
22     protected final DragObject mDragObject;
23     protected final Rect mIconRect;
24     protected final DragLayer mDragLayer;
25     protected final Rect mFrom;
26     protected final int mDuration;
27     protected final float mUX, mUY;
28     protected final float mAnimationTimeFraction;
29     protected final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
30 
31     protected float mAX, mAY;
32 
33     /**
34      * @param vel initial fling velocity in pixels per second.
35      */
FlingAnimation(DragObject d, PointF vel, Rect iconRect, DragLayer dragLayer)36     public FlingAnimation(DragObject d, PointF vel, Rect iconRect, DragLayer dragLayer) {
37         mDragObject = d;
38         mUX = vel.x / 1000;
39         mUY = vel.y / 1000;
40         mIconRect = iconRect;
41 
42         mDragLayer = dragLayer;
43         mFrom = new Rect();
44         dragLayer.getViewRectRelativeToSelf(d.dragView, mFrom);
45 
46         float scale = d.dragView.getScaleX();
47         float xOffset = ((scale - 1f) * d.dragView.getMeasuredWidth()) / 2f;
48         float yOffset = ((scale - 1f) * d.dragView.getMeasuredHeight()) / 2f;
49         mFrom.left += xOffset;
50         mFrom.right -= xOffset;
51         mFrom.top += yOffset;
52         mFrom.bottom -= yOffset;
53 
54         mDuration = initDuration();
55         mAnimationTimeFraction = ((float) mDuration) / (mDuration + DRAG_END_DELAY);
56     }
57 
58     /**
59      * The fling animation is based on the following system
60      *   - Apply a constant force in the y direction to causing the fling to decelerate.
61      *   - The animation runs for the time taken by the object to go out of the screen.
62      *   - Calculate a constant acceleration in x direction such that the object reaches
63      *     {@link #mIconRect} in the given time.
64      */
initDuration()65     protected int initDuration() {
66         float sY = -mFrom.bottom;
67 
68         float d = mUY * mUY + 2 * sY * MAX_ACCELERATION;
69         if (d >= 0) {
70             // sY can be reached under the MAX_ACCELERATION. Use MAX_ACCELERATION for y direction.
71             mAY = MAX_ACCELERATION;
72         } else {
73             // sY is not reachable, decrease the acceleration so that sY is almost reached.
74             d = 0;
75             mAY = mUY * mUY / (2 * -sY);
76         }
77         double t = (-mUY - Math.sqrt(d)) / mAY;
78 
79         float sX = -mFrom.exactCenterX() + mIconRect.exactCenterX();
80 
81         // Find horizontal acceleration such that: u*t + a*t*t/2 = s
82         mAX = (float) ((sX - t * mUX) * 2 / (t * t));
83         return (int) Math.round(t);
84     }
85 
getDuration()86     public final int getDuration() {
87         return mDuration + DRAG_END_DELAY;
88     }
89 
90     @Override
onAnimationUpdate(ValueAnimator animation)91     public void onAnimationUpdate(ValueAnimator animation) {
92         float t = animation.getAnimatedFraction();
93         if (t > mAnimationTimeFraction) {
94             t = 1;
95         } else {
96             t = t / mAnimationTimeFraction;
97         }
98         final DragView dragView = (DragView) mDragLayer.getAnimatedView();
99         final float time = t * mDuration;
100         dragView.setTranslationX(time * mUX + mFrom.left + mAX * time * time / 2);
101         dragView.setTranslationY(time * mUY + mFrom.top + mAY * time * time / 2);
102         dragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
103     }
104 }
105