Adding animations to Customize drawer

-When you tap to add in customize drawer the widgets
 / app shortcuts now animate to the mini screens

Change-Id: I0a5b5ae561fda3fbbf902003273477a5ed7ca5cc
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index 91a3bdb..62dcf4a 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -16,10 +16,18 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
 
 import org.xmlpull.v1.XmlPullParser;
 
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
+import android.animation.Animator.AnimatorListener;
 import android.app.WallpaperManager;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
@@ -48,13 +56,12 @@
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
+import com.android.launcher.R;
 
 
 public class CustomizePagedView extends PagedView
@@ -112,6 +119,12 @@
     private final Canvas mCanvas = new Canvas();
     private final LayoutInflater mInflater;
 
+    private final float mTmpFloatPos[] = new float[2];
+    private final float ANIMATION_SCALE = 0.5f;
+    private final int ANIMATION_DURATION = 400;
+    private TimeInterpolator mQuintEaseOutInterpolator = new DecelerateInterpolator(2.5f);
+    private ScaleAlphaInterpolator mScaleAlphaInterpolator = new ScaleAlphaInterpolator();
+
     public CustomizePagedView(Context context) {
         this(context, null, 0);
     }
@@ -318,8 +331,84 @@
     public void onDragViewVisible() {
     }
 
+    class ScaleAlphaInterpolator implements Interpolator {
+        public float getInterpolation(float input) {
+            float pivot = 0.5f;
+            if (input < pivot) {
+                return 0;
+            } else {
+                return (input - pivot)/(1 - pivot);
+            }
+        }
+    }
+
+    private void animateItemOntoScreen(View dragView,
+            final CellLayout layout, final ItemInfo info) {
+        mTmpFloatPos[0] = layout.getWidth() / 2;
+        mTmpFloatPos[1] = layout.getHeight() / 2;
+        mLauncher.getWorkspace().mapPointFromChildToSelf(layout, mTmpFloatPos);
+
+        final DragLayer dragLayer = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+        final View dragCopy = dragLayer.createDragView(dragView);
+        dragCopy.setAlpha(1.0f);
+
+        int dragViewWidth = dragView.getMeasuredWidth();
+        int dragViewHeight = dragView.getMeasuredHeight();
+        float heightOffset = 0;
+        float widthOffset = 0;
+
+        if (dragView instanceof ImageView) {
+            Drawable d = ((ImageView) dragView).getDrawable();
+            int width = d.getIntrinsicWidth();
+            int height = d.getIntrinsicHeight();
+
+            if ((1.0 * width / height) >= (1.0f * dragViewWidth) / dragViewHeight) {
+                float f = (dragViewWidth / (width * 1.0f));
+                heightOffset = ANIMATION_SCALE * (dragViewHeight - f * height) / 2;
+            } else {
+                float f = (dragViewHeight / (height * 1.0f));
+                widthOffset = ANIMATION_SCALE * (dragViewWidth - f * width) / 2;
+            }
+        }
+
+        float toX = mTmpFloatPos[0] - dragView.getMeasuredWidth() / 2 + widthOffset;
+        float toY = mTmpFloatPos[1] - dragView.getMeasuredHeight() / 2 + heightOffset;
+
+        ObjectAnimator posAnim = ObjectAnimator.ofPropertyValuesHolder(dragCopy,
+                PropertyValuesHolder.ofFloat("x", toX),
+                PropertyValuesHolder.ofFloat("y", toY));
+        posAnim.setInterpolator(mQuintEaseOutInterpolator);
+        posAnim.setDuration(ANIMATION_DURATION);
+
+        posAnim.addListener(new AnimatorListener() {
+            public void onAnimationCancel(Animator animation) {}
+            public void onAnimationRepeat(Animator animation) {}
+            public void onAnimationStart(Animator animation) {}
+
+            public void onAnimationEnd(Animator animation) {
+                dragLayer.removeView(dragCopy);
+                mLauncher.addExternalItemToScreen(info, layout);
+                post(new Runnable() {
+                    public void run() {
+                        layout.animateDrop();
+                    }
+                });
+            }
+        });
+
+        ObjectAnimator scaleAlphaAnim = ObjectAnimator.ofPropertyValuesHolder(dragCopy,
+                PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.0f),
+                PropertyValuesHolder.ofFloat("scaleX", ANIMATION_SCALE),
+                PropertyValuesHolder.ofFloat("scaleY", ANIMATION_SCALE));
+        scaleAlphaAnim.setInterpolator(mScaleAlphaInterpolator);
+        scaleAlphaAnim.setDuration(ANIMATION_DURATION);
+
+        posAnim.start();
+        scaleAlphaAnim.start();
+    }
+
     @Override
-    public void onClick(View v) {
+    public void onClick(final View v) {
         // Return early if this is not initiated from a touch
         if (!v.isInTouchMode()) return;
         // Return early if we are still animating the pages
@@ -351,11 +440,12 @@
             Workspace w = mLauncher.getWorkspace();
             int currentWorkspaceScreen = mLauncher.getCurrentWorkspaceScreen();
             final CellLayout cl = (CellLayout)w.getChildAt(currentWorkspaceScreen);
+            final View dragView = getDragView(v);
 
             animateClickFeedback(v, new Runnable() {
                 @Override
                 public void run() {
-                    mLauncher.addExternalItemToScreen(itemInfo, cl);
+                    animateItemOntoScreen(dragView, cl, itemInfo);
                 }
             });
             return;
@@ -484,6 +574,11 @@
         return b;
     }
 
+    private View getDragView(View v) {
+        return (mCustomizationType == CustomizationType.WidgetCustomization) ?
+                v.findViewById(R.id.widget_preview) : v;
+    }
+
     private boolean beginDragging(View v) {
         // End the current choice mode before we start dragging anything
         if (isChoiceMode(CHOICE_MODE_SINGLE)) {
@@ -491,24 +586,19 @@
         }
         mIsDragging = true;
 
-        PendingAddItemInfo createItemInfo;
         switch (mCustomizationType) {
         case WidgetCustomization:
-            // Get the icon as the drag representation
-            final LinearLayout l = (LinearLayout) v;
-            final Drawable icon = ((ImageView) l.findViewById(R.id.widget_preview)).getDrawable();
-            Bitmap b = drawableToBitmap(icon);
+            // Get the widget preview as the drag representation
             PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) v.getTag();
+            final View dragView = v.findViewById(R.id.widget_preview);
 
             mLauncher.getWorkspace().onDragStartedWithItemMinSize(
                     createWidgetInfo.minWidth, createWidgetInfo.minHeight);
-            mDragController.startDrag(v, b, this, createWidgetInfo, DragController.DRAG_ACTION_COPY, null);
+            mDragController.startDrag(dragView, this, createWidgetInfo, DragController.DRAG_ACTION_COPY, null);
 
-            // Cleanup the icon
-            b.recycle();
             return true;
         case ShortcutCustomization:
-            createItemInfo = (PendingAddItemInfo) v.getTag();
+            PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
             mDragController.startDrag(v, this, createItemInfo, DragController.DRAG_ACTION_COPY);
             mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1);
             return true;
@@ -881,7 +971,7 @@
             PagedViewIcon icon = (PagedViewIcon) mInflater.inflate(
                     R.layout.customize_paged_view_item, layout, false);
             icon.applyFromResolveInfo(info, mPackageManager, mPageViewIconCache,
-                    ((LauncherApplication)mLauncher.getApplication()).getIconCache());
+                    ((LauncherApplication) mLauncher.getApplication()).getIconCache());
             switch (mCustomizationType) {
             case WallpaperCustomization:
                 icon.setOnClickListener(this);
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index a0a44a5..876ad87 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -16,7 +16,7 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
+import java.util.ArrayList;
 
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -34,7 +34,7 @@
 import android.view.WindowManager;
 import android.view.inputmethod.InputMethodManager;
 
-import java.util.ArrayList;
+import com.android.launcher.R;
 
 /**
  * Class for initiating a drag within a view or across multiple views.
@@ -340,7 +340,7 @@
     /**
      * Draw the view into a bitmap.
      */
-    private Bitmap getViewBitmap(View v) {
+    Bitmap getViewBitmap(View v) {
         v.clearFocus();
         v.setPressed(false);
 
@@ -351,6 +351,8 @@
         // for the duration of this operation
         int color = v.getDrawingCacheBackgroundColor();
         v.setDrawingCacheBackgroundColor(0);
+        float alpha = v.getAlpha();
+        v.setAlpha(1.0f);
 
         if (color != 0) {
             v.destroyDrawingCache();
@@ -366,6 +368,7 @@
 
         // Restore the view
         v.destroyDrawingCache();
+        v.setAlpha(alpha);
         v.setWillNotCacheDrawing(willNotCache);
         v.setDrawingCacheBackgroundColor(color);
 
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index ab71670..b418a79 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -17,17 +17,20 @@
 package com.android.launcher2;
 
 import android.content.Context;
+import android.graphics.Bitmap;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
+import android.widget.ImageView;
 
 /**
  * A ViewGroup that coordinates dragging across its descendants
  */
 public class DragLayer extends FrameLayout {
-    DragController mDragController;
+    private DragController mDragController;
+    private int[] mTmpXY = new int[2];
 
     /**
      * Used to create a new DragLayer from XML.
@@ -62,4 +65,19 @@
     public boolean dispatchUnhandledMove(View focused, int direction) {
         return mDragController.dispatchUnhandledMove(focused, direction);
     }
+
+    public View createDragView(Bitmap b, int xPos, int yPos) {
+        ImageView imageView = new ImageView(mContext);
+        imageView.setImageBitmap(b);
+        imageView.setX(xPos);
+        imageView.setY(yPos);
+        addView(imageView, b.getWidth(), b.getHeight());
+
+        return imageView;
+    }
+
+    public View createDragView(View v) {
+        v.getLocationOnScreen(mTmpXY);
+        return createDragView(mDragController.getViewBitmap(v), mTmpXY[0], mTmpXY[1]);
+    }
 }
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index 947184f..a8dad7a 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -17,8 +17,6 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
-
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
@@ -36,6 +34,8 @@
 import android.view.WindowManagerImpl;
 import android.view.animation.DecelerateInterpolator;
 
+import com.android.launcher.R;
+
 public class DragView extends View {
     private Bitmap mBitmap;
     private Paint mPaint;
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 4203277..239f6f6 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -16,8 +16,9 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
-import com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
@@ -63,9 +64,8 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
+import com.android.launcher.R;
+import com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
 
 /**
  * The workspace is a wide area with a wallpaper and a finite number of pages.
@@ -1518,9 +1518,9 @@
             if (mIsSmall) {
                 // if we drag and drop to small screens, don't pass the touch x/y coords (when we
                 // enable spring-loaded adding, however, we do want to pass the touch x/y coords)
-                onDropExternal(-1, -1, dragInfo, mDragTargetLayout);
+                onDropExternal(-1, -1, dragInfo, mDragTargetLayout, false);
             } else {
-                onDropExternal(originX, originY, dragInfo, mDragTargetLayout);
+                onDropExternal(originX, originY, dragInfo, mDragTargetLayout, false);
             }
         } else if (mDragInfo != null) {
             final View cell = mDragInfo.cell;
@@ -1730,7 +1730,7 @@
                 if (isShortcut) {
                     final Intent intent = data.getItem(index).getIntent();
                     Object info = model.infoFromShortcutIntent(mContext, intent, data.getIcon());
-                    onDropExternal(x, y, info, layout);
+                    onDropExternal(x, y, info, layout, false);
                 } else {
                     if (widgets.size() == 1) {
                         // If there is only one item, then go ahead and add and configure
@@ -1997,11 +1997,6 @@
         clearAllHovers();
     }
 
-    private void onDropExternal(int x, int y, Object dragInfo,
-            CellLayout cellLayout) {
-        onDropExternal(x, y, dragInfo, cellLayout, false);
-    }
-
     @Override
     public void getHitRect(Rect outRect) {
         // We want the workspace to have the whole area of the display (it will find the correct
@@ -2012,25 +2007,25 @@
 
     /**
      * Add the item specified by dragInfo to the given layout.
-     * This is basically the equivalent of onDropExternal, except it's not initiated
-     * by drag and drop.
      * @return true if successful
      */
-    public boolean addExternalItemToScreen(Object dragInfo, View layout) {
-        CellLayout cl = (CellLayout) layout;
-        ItemInfo info = (ItemInfo) dragInfo;
-
-        if (cl.findCellForSpan(mTempEstimate, info.spanX, info.spanY)) {
-            onDropExternal(-1, -1, dragInfo, cl, false);
+    public boolean addExternalItemToScreen(ItemInfo dragInfo, CellLayout layout) {
+        if (layout.findCellForSpan(mTempEstimate, dragInfo.spanX, dragInfo.spanY)) {
+            onDropExternal(-1, -1, (ItemInfo) dragInfo, (CellLayout) layout, false);
             return true;
         }
         mLauncher.showOutOfSpaceMessage();
         return false;
     }
 
-    // Drag from somewhere else
-    // NOTE: This can also be called when we are outside of a drag event, when we want
-    // to add an item to one of the workspace screens.
+    /**
+     * Drop an item that didn't originate on one of the workspace screens.
+     * It may have come from Launcher (e.g. from all apps or customize), or it may have
+     * come from another app altogether.
+     *
+     * NOTE: This can also be called when we are outside of a drag event, when we want
+     * to add an item to one of the workspace screens.
+     */
     private void onDropExternal(int x, int y, Object dragInfo,
             CellLayout cellLayout, boolean insertAtFirst) {
         int screen = indexOfChild(cellLayout);
@@ -2056,11 +2051,9 @@
                     throw new IllegalStateException("Unknown item type: " + info.itemType);
             }
             cellLayout.onDragExit();
-            cellLayout.animateDrop();
         } else {
             // This is for other drag/drop cases, like dragging from All Apps
             ItemInfo info = (ItemInfo) dragInfo;
-
             View view = null;
 
             switch (info.itemType) {
@@ -2091,7 +2084,6 @@
             addInScreen(view, indexOfChild(cellLayout), mTargetCell[0],
                     mTargetCell[1], info.spanX, info.spanY, insertAtFirst);
             cellLayout.onDropChild(view);
-            cellLayout.animateDrop();
             CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
 
             LauncherModel.addOrMoveItemInDatabase(mLauncher, info,