Home | History | Annotate | Download | only in util
      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      */
     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      */
     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 
     86     public final int getDuration() {
     87         return mDuration + DRAG_END_DELAY;
     88     }
     89 
     90     @Override
     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