Merge "Improving adding widgets animations"
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index 37abe5a..9997c29 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -178,7 +178,7 @@
         return scale;
     }
 
-    private float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
+    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
         float scale = 1.0f;
         float[] pt = {coord[0], coord[1]};
         descendant.getMatrix().mapPoints(pt);
@@ -319,6 +319,17 @@
         animateViewIntoPosition(dragView, child, null);
     }
 
+    public void animateViewIntoPosition(DragView dragView, final int[] pos, float scale,
+            Runnable onFinishRunnable) {
+        Rect r = new Rect();
+        getViewRectRelativeToSelf(dragView, r);
+        final int fromX = r.left;
+        final int fromY = r.top;
+
+        animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], scale,
+                onFinishRunnable, true);
+    }
+
     public void animateViewIntoPosition(DragView dragView, final View child,
             final Runnable onFinishAnimationRunnable) {
         ((CellLayoutChildren) child.getParent()).measureChild(child);
@@ -373,18 +384,6 @@
         animateViewIntoPosition(dragView, fromX, fromY, toX, toY, scale, onCompleteRunnable, true);
     }
 
-    /* Just fade out in place */
-    public void animateViewOut(DragView dragView, Runnable onFinishAnimationRunnable) {
-        Rect r = new Rect();
-        getViewRectRelativeToSelf(dragView, r);
-        final int fromX = r.left;
-        final int fromY = r.top;
-        final int toX = fromX;
-        final int toY = fromY;
-        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1.0f, onFinishAnimationRunnable,
-                true);
-    }
-
     private void animateViewIntoPosition(final View view, final int fromX, final int fromY,
             final int toX, final int toY, float finalScale, Runnable onCompleteRunnable,
             boolean fadeOut) {
@@ -394,6 +393,24 @@
         animateView(view, from, to, 1f, finalScale, -1, null, null, onCompleteRunnable, true);
     }
 
+    /**
+     * This method animates a view at the end of a drag and drop animation.
+     *
+     * @param view The view to be animated. This view is drawn directly into DragLayer, and so
+     *        doesn't need to be a child of DragLayer.
+     * @param from The initial location of the view. Only the left and top parameters are used.
+     * @param to The final location of the view. Only the left and top parameters are used. This
+     *        location doesn't account for scaling, and so should be centered about the desired
+     *        final location (including scaling).
+     * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
+     * @param finalScale The final scale of the view. The view is scaled about its center.
+     * @param duration The duration of the animation.
+     * @param motionInterpolator The interpolator to use for the location of the view.
+     * @param alphaInterpolator The interpolator to use for the alpha of the view.
+     * @param onCompleteRunnable Optional runnable to run on animation completion.
+     * @param fadeOut Whether or not to fade out the view once the animation completes. If true,
+     *        the runnable will execute after the view is faded out.
+     */
     public void animateView(final View view, final Rect from, final Rect to, final float finalAlpha,
             final float finalScale, int duration, final Interpolator motionInterpolator,
             final Interpolator alphaInterpolator, final Runnable onCompleteRunnable,
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index eeb5534..ec088d1 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -2834,33 +2834,72 @@
                 mLauncher.exitSpringLoadedDragModeDelayed(false);
             }
         };
+
+        ItemInfo info = (ItemInfo) dragInfo;
+        int spanX = info.spanX;
+        int spanY = info.spanY;
+        if (mDragInfo != null) {
+            spanX = mDragInfo.spanX;
+            spanY = mDragInfo.spanY;
+        }
+
         final int screen = indexOfChild(cellLayout);
         if (screen != mCurrentPage && mState != State.SPRING_LOADED) {
             snapToPage(screen);
         }
-        if (dragInfo instanceof PendingAddItemInfo) {
-            final PendingAddItemInfo info = (PendingAddItemInfo) dragInfo;
-            mLauncher.getDragLayer().animateViewOut(d.dragView, new Runnable() {
+
+        if (info instanceof PendingAddItemInfo) {
+            final PendingAddItemInfo pendingInfo = (PendingAddItemInfo) dragInfo;
+
+            Runnable onAnimationCompleteRunnable = new Runnable() {
                 @Override
                 public void run() {
                     // When dragging and dropping from customization tray, we deal with creating
                     // widgets/shortcuts/folders in a slightly different way
-                    switch (info.itemType) {
+                    switch (pendingInfo.itemType) {
                     case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
-                        mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) info, screen, touchXY);
+                        mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo,
+                                screen, touchXY);
                         break;
                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
-                        mLauncher.processShortcutFromDrop(info.componentName, screen, touchXY);
+                        mLauncher.processShortcutFromDrop(pendingInfo.componentName,
+                                screen, touchXY);
                         break;
                     default:
-                        throw new IllegalStateException("Unknown item type: " + info.itemType);
+                        throw new IllegalStateException("Unknown item type: " +
+                                pendingInfo.itemType);
                     }
                     cellLayout.onDragExit();
                 }
-            });
+            };
+
+            // Now we animate the dragView, (ie. the widget or shortcut preview) into its final
+            // location and size on the home screen.
+
+            // The target cell is also calculated later in Launcher when the widget is actually
+            // added, however, we do it here as well to find out where to animate to. The re-use
+            // of this computation required to much restructuring.
+            mTargetCell = findNearestVacantArea(touchXY[0], touchXY[1], spanX, spanY, null,
+                    cellLayout, mTargetCell);
+
+            int loc[] = new int[2];
+            cellLayout.cellToPoint(mTargetCell[0], mTargetCell[1], loc);
+
+            RectF r = new RectF();
+            cellLayout.cellToRect(mTargetCell[0], mTargetCell[1], spanX, spanY, r);
+            float cellLayoutScale =
+                    mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(cellLayout, loc);
+
+            float dragViewScale =  r.width() / d.dragView.getMeasuredWidth();
+            // The animation will scale the dragView about its center, so we need to center about
+            // the final location.
+            loc[0] -= (d.dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2;
+            loc[1] -= (d.dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2;
+
+            mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, loc,
+                    dragViewScale * cellLayoutScale, onAnimationCompleteRunnable);
         } else {
             // This is for other drag/drop cases, like dragging from All Apps
-            ItemInfo info = (ItemInfo) dragInfo;
             View view = null;
 
             switch (info.itemType) {
@@ -2881,16 +2920,6 @@
                 throw new IllegalStateException("Unknown item type: " + info.itemType);
             }
 
-            int spanX = 1;
-            int spanY = 1;
-            if (mDragInfo != null) {
-                spanX = mDragInfo.spanX;
-                spanY = mDragInfo.spanY;
-            } else {
-                spanX = info.spanX;
-                spanY = info.spanY;
-            }
-
             // First we find the cell nearest to point at which the item is
             // dropped, without any consideration to whether there is an item there.
             if (touchXY != null) {