Fixing issues with spring loaded adding.

- Delaying until items are added
- Showing bg when going into spring loaded mode
- Fixing regression where dropping widgets on full page would not trigger a notification
- Fixing regression on tablet where pages were no longer being rotated or shown

Change-Id: Iadc0c406f0c065c5029addea1abfee395eed81b9
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index 33472ea..f5874bf 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -472,9 +472,13 @@
         }
         return true;
     }
-    private void endDragging(boolean success) {
+    private void endDragging(View target, boolean success) {
         mLauncher.getWorkspace().onDragStopped(success);
-        mLauncher.exitSpringLoadedDragMode();
+        if (!success || target != mLauncher.getWorkspace()) {
+            // Exit spring loaded mode if we have not successfully dropped or have not handled the
+            // drop in Workspace
+            mLauncher.exitSpringLoadedDragMode();
+        }
         mLauncher.unlockScreenOrientation();
 
     }
@@ -486,7 +490,7 @@
     public void onDragViewVisible() {}
     @Override
     public void onDropCompleted(View target, DragObject d, boolean success) {
-        endDragging(success);
+        endDragging(target, success);
 
         // Display an error message if the drag failed due to there not being enough space on the
         // target layout we were dropping on.
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index dfd8160..0bdfec1 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -175,16 +175,25 @@
                 mTmpXY[0] + descendant.getWidth(), mTmpXY[1] + descendant.getHeight());
     }
 
-    private void getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
-        coord[0] += descendant.getLeft();
-        coord[1] += descendant.getTop();
+    private float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
+        float scale = 1.0f;
+        float[] pt = {coord[0], coord[1]};
+        descendant.getMatrix().mapPoints(pt);
+        scale *= descendant.getScaleX();
+        pt[0] += descendant.getLeft();
+        pt[1] += descendant.getTop();
         ViewParent viewParent = descendant.getParent();
         while (viewParent instanceof View && viewParent != this) {
             final View view = (View)viewParent;
-            coord[0] += view.getLeft() + (int) (view.getTranslationX() + 0.5f) - view.getScrollX();
-            coord[1] += view.getTop() + (int) (view.getTranslationY() + 0.5f) - view.getScrollY();
+            view.getMatrix().mapPoints(pt);
+            scale *= view.getScaleX();
+            pt[0] += view.getLeft() - view.getScrollX();
+            pt[1] += view.getTop() - view.getScrollY();
             viewParent = view.getParent();
         }
+        coord[0] = (int) pt[0];
+        coord[1] = (int) pt[1];
+        return scale;
     }
 
     public void getLocationInDragLayer(View child, int[] loc) {
@@ -304,6 +313,10 @@
     }
 
     public void animateViewIntoPosition(DragView dragView, final View child) {
+        animateViewIntoPosition(dragView, child, null);
+    }
+    public void animateViewIntoPosition(DragView dragView, final View child,
+            final Runnable onFinishAnimationRunnable) {
         ((CellLayoutChildren) child.getParent()).measureChild(child);
         CellLayout.LayoutParams lp =  (CellLayout.LayoutParams) child.getLayoutParams();
 
@@ -311,13 +324,15 @@
         getViewRectRelativeToSelf(dragView, r);
 
         int coord[] = new int[2];
-        coord[0] = lp.x;
-        coord[1] = lp.y;
+        coord[0] = lp.x + (lp.width / 2);
+        coord[1] = lp.y + (lp.height / 2);
         // Since the child hasn't necessarily been laid out, we force the lp to be updated with
         // the correct coordinates and use these to determine the final location
-        getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
-        int toX = coord[0] - (dragView.getWidth() - child.getMeasuredWidth()) / 2;
-        int toY = coord[1] - (dragView.getHeight() - child.getMeasuredHeight()) / 2;
+        float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
+        int toX = coord[0] - lp.width / 2;
+        int toY = coord[1] - lp.height / 2;
+        toX -= (dragView.getWidth() - child.getMeasuredWidth()) / 2;
+        toY -= (dragView.getHeight() - child.getMeasuredHeight()) / 2;
 
         final int fromX = r.left + (dragView.getWidth() - child.getMeasuredWidth())  / 2;
         final int fromY = r.top + (dragView.getHeight() - child.getMeasuredHeight())  / 2;
@@ -328,19 +343,39 @@
                 child.setVisibility(VISIBLE);
                 ObjectAnimator oa = ObjectAnimator.ofFloat(child, "alpha", 0f, 1f);
                 oa.setDuration(60);
+                oa.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(android.animation.Animator animation) {
+                        if (onFinishAnimationRunnable != null) {
+                            onFinishAnimationRunnable.run();
+                        }
+                    }
+                });
                 oa.start();
             }
         };
-        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, onCompleteRunnable, true);
+        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, Runnable onCompleteRunnable, boolean fadeOut) {
+            final int toX, final int toY, float finalScale, Runnable onCompleteRunnable,
+            boolean fadeOut) {
         Rect from = new Rect(fromX, fromY, fromX +
                 view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
         Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
-        animateView(view, from, to, 1f, 1.0f, -1, null, null, onCompleteRunnable, true);
-
+        animateView(view, from, to, 1f, finalScale, -1, null, null, onCompleteRunnable, true);
     }
 
     public void animateView(final View view, final Rect from, final Rect to, final float finalAlpha,
diff --git a/src/com/android/launcher2/DropTarget.java b/src/com/android/launcher2/DropTarget.java
index 0712420..34fa893 100644
--- a/src/com/android/launcher2/DropTarget.java
+++ b/src/com/android/launcher2/DropTarget.java
@@ -49,6 +49,9 @@
         /** Where the drag originated */
         public DragSource dragSource = null;
 
+        /** Post drag animation runnable */
+        public Runnable postAnimationRunnable = null;
+
         public DragObject() {
         }
     }
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index 4978e98..283c295 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -286,12 +286,13 @@
     }
 
     public void performCreateAnimation(final ShortcutInfo destInfo, final View destView,
-            final ShortcutInfo srcInfo, final View srcView, Rect dstRect) {
+            final ShortcutInfo srcInfo, final View srcView, Rect dstRect,
+            Runnable postAnimationRunnable) {
 
         Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1];
         computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), destView.getMeasuredWidth());
         // This will animate the dragView (srcView) into the new folder
-        onDrop(srcInfo, srcView, dstRect, 1);
+        onDrop(srcInfo, srcView, dstRect, 1, postAnimationRunnable);
 
         // This will animate the first item from it's position as an icon into its
         // position as the first item in the preview
@@ -309,7 +310,8 @@
         mFolderRingAnimator.animateToNaturalState();
     }
 
-    private void onDrop(final ShortcutInfo item, View animateView, Rect finalRect, int index) {
+    private void onDrop(final ShortcutInfo item, View animateView, Rect finalRect, int index,
+            Runnable postAnimationRunnable) {
         item.cellX = -1;
         item.cellY = -1;
         DragLayer dragLayer = mLauncher.getDragLayer();
@@ -332,7 +334,8 @@
         float finalAlpha = index < NUM_ITEMS_IN_PREVIEW ? 0.5f : 0f;
 
         dragLayer.animateView(animateView, from, to, finalAlpha, scale, DROP_IN_ANIMATION_DURATION,
-                new DecelerateInterpolator(2), new AccelerateInterpolator(2), null, false);
+                new DecelerateInterpolator(2), new AccelerateInterpolator(2), postAnimationRunnable,
+                false);
         postDelayed(new Runnable() {
             public void run() {
                 addItem(item);
@@ -348,7 +351,7 @@
         } else {
             item = (ShortcutInfo) d.dragInfo;
         }
-        onDrop(item, d.dragView, null, mInfo.contents.size());
+        onDrop(item, d.dragView, null, mInfo.contents.size(), d.postAnimationRunnable);
     }
 
     public DropTarget getDropTargetDelegate(DragObject d) {
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 76866a7..530f49c 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -167,6 +167,8 @@
     private AnimatorSet mStateAnimation;
 
     static final int APPWIDGET_HOST_ID = 1024;
+    private static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT = 300;
+    private static final int EXIT_SPRINGLOADED_MODE_LONG_TIMEOUT = 600;
 
     private static final Object sLock = new Object();
     private static int sScreen = DEFAULT_SCREEN;
@@ -592,7 +594,11 @@
         }
     }
 
-    private void completeAdd(PendingAddArguments args) {
+    /**
+     * Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have
+     * a configuration step, this allows the proper animations to run after other transitions.
+     */
+    private boolean completeAdd(PendingAddArguments args) {
         switch (args.requestCode) {
             case REQUEST_PICK_APPLICATION:
                 completeAddApplication(args.intent, args.screen, args.cellX, args.cellY);
@@ -602,22 +608,24 @@
                 break;
             case REQUEST_CREATE_SHORTCUT:
                 completeAddShortcut(args.intent, args.screen, args.cellX, args.cellY);
-                break;
+                return true;
             case REQUEST_PICK_APPWIDGET:
                 addAppWidgetFromPick(args.intent);
                 break;
             case REQUEST_CREATE_APPWIDGET:
                 int appWidgetId = args.intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
                 completeAddAppWidget(appWidgetId, args.screen);
-                break;
+                return true;
             case REQUEST_PICK_WALLPAPER:
                 // We just wanted the activity result here so we can clear mWaitingForResult
                 break;
         }
+        return false;
     }
 
     @Override
     protected void onActivityResult(final int requestCode, int resultCode, final Intent data) {
+        boolean delayExitSpringLoadedMode = false;
         mWaitingForResult = false;
 
         // The pattern used here is that a user PICKs a specific application,
@@ -638,17 +646,21 @@
             if (isWorkspaceLocked()) {
                 sPendingAddList.add(args);
             } else {
-                completeAdd(args);
+                delayExitSpringLoadedMode = completeAdd(args);
             }
         } else if ((requestCode == REQUEST_PICK_APPWIDGET ||
-                requestCode == REQUEST_CREATE_APPWIDGET) && resultCode == RESULT_CANCELED &&
-                data != null) {
-            // Clean up the appWidgetId if we canceled
-            int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
-            if (appWidgetId != -1) {
-                mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+                requestCode == REQUEST_CREATE_APPWIDGET) && resultCode == RESULT_CANCELED) {
+            if (data != null) {
+                // Clean up the appWidgetId if we canceled
+                int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
+                if (appWidgetId != -1) {
+                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+                }
             }
         }
+
+        // Exit spring loaded mode if necessary after cancelling the configuration of a widget
+        exitSpringLoadedDragModeDelayed(delayExitSpringLoadedMode);
     }
 
     @Override
@@ -1549,6 +1561,9 @@
         } else {
             // Otherwise just add it
             completeAddAppWidget(appWidgetId, mAddScreen);
+
+            // Exit spring loaded mode if necessary after adding the widget
+            exitSpringLoadedDragModeDelayed(false);
         }
     }
 
@@ -2541,7 +2556,16 @@
         }
         // Otherwise, we are not in spring loaded mode, so don't do anything.
     }
-
+    void exitSpringLoadedDragModeDelayed(boolean extendedDelay) {
+        mWorkspace.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                exitSpringLoadedDragMode();
+            }
+        }, (extendedDelay ?
+                EXIT_SPRINGLOADED_MODE_LONG_TIMEOUT :
+                EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT));
+    }
     void exitSpringLoadedDragMode() {
         if (mState == State.APPS_CUSTOMIZE_SPRING_LOADED) {
             mWorkspace.exitSpringLoadedDragMode(Workspace.ShrinkState.BOTTOM_VISIBLE);
@@ -2673,10 +2697,6 @@
         }
     }
 
-    void onWorkspaceClick(CellLayout layout) {
-        showWorkspace(true, layout);
-    }
-
     private Drawable getExternalPackageToolbarIcon(ComponentName activityName) {
         try {
             PackageManager packageManager = getPackageManager();
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 81e876f..8c74c42 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -368,8 +368,11 @@
     // we moved this functionality to a helper function so SmoothPagedView can reuse it
     protected boolean computeScrollHelper() {
         if (mScroller.computeScrollOffset()) {
-            mDirtyPageAlpha = true;
-            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
+            // Don't bother scrolling if the page does not need to be moved
+            if (mScrollX != mScroller.getCurrX() || mScrollY != mScroller.getCurrY()) {
+                mDirtyPageAlpha = true;
+                scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
+            }
             invalidate();
             return true;
         } else if (mNextPage != INVALID_PAGE) {
@@ -652,7 +655,7 @@
         if (pageCount > 0) {
             final int pageWidth = getScaledMeasuredWidth(getChildAt(0));
             final int screenWidth = getMeasuredWidth();
-            int x = getRelativeChildOffset(0) + pageWidth;
+            int x = getScaledRelativeChildOffset(0) + pageWidth;
             int leftScreen = 0;
             int rightScreen = 0;
             while (x <= mScrollX) {
@@ -1255,6 +1258,10 @@
         return (getMeasuredWidth() - getChildWidth(index)) / 2;
     }
 
+    protected int getScaledRelativeChildOffset(int index) {
+        return (getMeasuredWidth() - getScaledMeasuredWidth(getChildAt(index))) / 2;
+    }
+
     protected int getChildOffset(int index) {
         if (getChildCount() == 0)
             return 0;
diff --git a/src/com/android/launcher2/SearchDropTargetBar.java b/src/com/android/launcher2/SearchDropTargetBar.java
index 943bd00..4bfb40a 100644
--- a/src/com/android/launcher2/SearchDropTargetBar.java
+++ b/src/com/android/launcher2/SearchDropTargetBar.java
@@ -62,7 +62,6 @@
         dragController.addDropTarget(mDeleteDropTarget);
         mInfoDropTarget.setLauncher(launcher);
         mDeleteDropTarget.setLauncher(launcher);
-        mDropTargetBar.setBackgroundColor(0x33000000);
     }
 
     @Override
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index ad00d4f..1e32ec0 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -74,8 +74,7 @@
  * interact with. A workspace is meant to be used with a fixed width only.
  */
 public class Workspace extends SmoothPagedView
-        implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
-        View.OnClickListener {
+        implements DropTarget, DragSource, DragScroller, View.OnTouchListener {
     @SuppressWarnings({"UnusedDeclaration"})
     private static final String TAG = "Launcher.Workspace";
 
@@ -338,7 +337,6 @@
         }
         CellLayout cl = ((CellLayout) child);
         cl.setOnInterceptTouchListener(this);
-        cl.setOnClickListener(this);
         cl.setClickable(true);
         cl.enableHardwareLayers();
     }
@@ -506,17 +504,6 @@
         return (mIsSmall || mIsInUnshrinkAnimation);
     }
 
-    /**
-     * Handle a click event on a CellLayout.
-     */
-    @Override
-    public void onClick(View cellLayout) {
-        // Only allow clicks on a CellLayout if it is shrunken and visible.
-        if ((mIsSmall || mIsInUnshrinkAnimation) && mShrinkState != ShrinkState.BOTTOM_HIDDEN) {
-            mLauncher.onWorkspaceClick((CellLayout) cellLayout);
-        }
-    }
-
     protected void onWindowVisibilityChanged (int visibility) {
         mLauncher.onWindowVisibilityChanged(visibility);
     }
@@ -945,11 +932,11 @@
         mBackgroundFadeInAnimation.start();
     }
 
-    private void hideBackgroundGradient() {
+    private void hideBackgroundGradient(float finalAlpha) {
         if (mBackground == null) return;
         if (mBackgroundFadeInAnimation != null) mBackgroundFadeInAnimation.cancel();
         if (mBackgroundFadeOutAnimation != null) mBackgroundFadeOutAnimation.cancel();
-        mBackgroundFadeOutAnimation = ValueAnimator.ofFloat(getBackgroundAlpha(), 0f);
+        mBackgroundFadeOutAnimation = ValueAnimator.ofFloat(getBackgroundAlpha(), finalAlpha);
         mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {
             public void onAnimationUpdate(ValueAnimator animation) {
                 setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue());
@@ -1113,40 +1100,27 @@
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
-        if (mIsSmall || mIsInUnshrinkAnimation) {
-            // Draw all the workspaces if we're small
-            final int pageCount = getChildCount();
-            final long drawingTime = getDrawingTime();
-            for (int i = 0; i < pageCount; i++) {
-                final CellLayout page = (CellLayout) getChildAt(i);
-                if (page.getVisibility() == VISIBLE
-                        && (page.getAlpha() != 0f || page.getBackgroundAlpha() != 0f)) {
-                    drawChild(canvas, page, drawingTime);
-                }
-            }
-        } else {
-            super.dispatchDraw(canvas);
+        super.dispatchDraw(canvas);
 
-            if (mInScrollArea && !LauncherApplication.isScreenLarge()) {
-                final int width = getWidth();
-                final int height = getHeight();
-                final int pageHeight = getChildAt(0).getHeight();
+        if (mInScrollArea && !LauncherApplication.isScreenLarge()) {
+            final int width = getWidth();
+            final int height = getHeight();
+            final int pageHeight = getChildAt(0).getHeight();
 
-                // This determines the height of the glowing edge: 90% of the page height
-                final int padding = (int) ((height - pageHeight) * 0.5f + pageHeight * 0.1f);
+            // This determines the height of the glowing edge: 90% of the page height
+            final int padding = (int) ((height - pageHeight) * 0.5f + pageHeight * 0.1f);
 
-                final CellLayout leftPage = (CellLayout) getChildAt(mCurrentPage - 1);
-                final CellLayout rightPage = (CellLayout) getChildAt(mCurrentPage + 1);
+            final CellLayout leftPage = (CellLayout) getChildAt(mCurrentPage - 1);
+            final CellLayout rightPage = (CellLayout) getChildAt(mCurrentPage + 1);
 
-                if (leftPage != null && leftPage.getIsDragOverlapping()) {
-                    final Drawable d = getResources().getDrawable(R.drawable.page_hover_left_holo);
-                    d.setBounds(mScrollX, padding, mScrollX + d.getIntrinsicWidth(), height - padding);
-                    d.draw(canvas);
-                } else if (rightPage != null && rightPage.getIsDragOverlapping()) {
-                    final Drawable d = getResources().getDrawable(R.drawable.page_hover_right_holo);
-                    d.setBounds(mScrollX + width - d.getIntrinsicWidth(), padding, mScrollX + width, height - padding);
-                    d.draw(canvas);
-                }
+            if (leftPage != null && leftPage.getIsDragOverlapping()) {
+                final Drawable d = getResources().getDrawable(R.drawable.page_hover_left_holo);
+                d.setBounds(mScrollX, padding, mScrollX + d.getIntrinsicWidth(), height - padding);
+                d.draw(canvas);
+            } else if (rightPage != null && rightPage.getIsDragOverlapping()) {
+                final Drawable d = getResources().getDrawable(R.drawable.page_hover_right_holo);
+                d.setBounds(mScrollX + width - d.getIntrinsicWidth(), padding, mScrollX + width, height - padding);
+                d.draw(canvas);
             }
         }
     }
@@ -1833,9 +1807,8 @@
             }
         }
 
-        if (!springLoaded) {
-            hideBackgroundGradient();
-        }
+        hideBackgroundGradient(springLoaded ? getResources().getInteger(
+                R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f : 0f);
     }
 
     /**
@@ -2034,9 +2007,19 @@
             mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,
                     d.dragView, mDragViewVisualCenter);
 
-            final CellLayout.CellInfo dragCellInfo = mDragInfo;
-            final int spanX = dragCellInfo == null ? 1 : dragCellInfo.spanX;
-            final int spanY = dragCellInfo == null ? 1 : dragCellInfo.spanY;
+            int spanX = 1;
+            int spanY = 1;
+            View ignoreView = null;
+            if (mDragInfo != null) {
+                final CellLayout.CellInfo dragCellInfo = mDragInfo;
+                spanX = dragCellInfo.spanX;
+                spanY = dragCellInfo.spanY;
+                ignoreView = dragCellInfo.cell;
+            } else {
+                final ItemInfo dragInfo = (ItemInfo) d.dragInfo;
+                spanX = dragInfo.spanX;
+                spanY = dragInfo.spanY;
+            }
 
             mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
                     (int) mDragViewVisualCenter[1], spanX, spanY, mDragTargetLayout, mTargetCell);
@@ -2049,7 +2032,6 @@
                 return true;
             }
 
-            final View ignoreView = dragCellInfo == null ? null : dragCellInfo.cell;
 
             // Don't accept the drop if there's no room for the item
             if (!mDragTargetLayout.findCellForSpanIgnoring(null, spanX, spanY, ignoreView)) {
@@ -2091,7 +2073,7 @@
     }
 
     boolean createUserFolderIfNecessary(View newView, CellLayout target,
-            int[] targetCell, boolean external, DragView dragView) {
+            int[] targetCell, boolean external, DragView dragView, Runnable postAnimationRunnable) {
         View v = target.getChildAt(targetCell[0], targetCell[1]);
         boolean hasntMoved = mDragInfo != null
                 && (mDragInfo.cellX == targetCell[0] && mDragInfo.cellY == targetCell[1]);
@@ -2123,7 +2105,8 @@
             sourceInfo.cellX = -1;
             sourceInfo.cellY = -1;
 
-            fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation);
+            fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation,
+                    postAnimationRunnable);
             return true;
         }
         return false;
@@ -2191,7 +2174,7 @@
                 boolean dropInscrollArea = mCurrentPage != screen;
 
                 if (!dropInscrollArea && createUserFolderIfNecessary(cell, dropTargetLayout,
-                        mTargetCell, false, d.dragView)) {
+                        mTargetCell, false, d.dragView, null)) {
                     return;
                 }
 
@@ -2369,8 +2352,7 @@
                 if (isShortcut) {
                     // Check if we have enough space on this screen to add a new shortcut
                     if (!layout.findCellForSpan(pos, 1, 1)) {
-                        Toast.makeText(mContext, mContext.getString(R.string.out_of_space),
-                                Toast.LENGTH_SHORT).show();
+                        mLauncher.showOutOfSpaceMessage();
                         return false;
                     }
                 }
@@ -2809,27 +2791,38 @@
      * 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[] touchXY, Object dragInfo,
-            CellLayout cellLayout, boolean insertAtFirst, DragObject d) {
-        int screen = indexOfChild(cellLayout);
+    private void onDropExternal(final int[] touchXY, final Object dragInfo,
+            final CellLayout cellLayout, boolean insertAtFirst, DragObject d) {
+        final Runnable exitSpringLoadedRunnable = new Runnable() {
+            @Override
+            public void run() {
+                mLauncher.exitSpringLoadedDragModeDelayed(false);
+            }
+        };
+        final int screen = indexOfChild(cellLayout);
         if (screen != mCurrentPage && mShrinkState != ShrinkState.SPRING_LOADED) {
             snapToPage(screen);
         }
         if (dragInfo instanceof PendingAddItemInfo) {
-            PendingAddItemInfo info = (PendingAddItemInfo) dragInfo;
-            // When dragging and dropping from customization tray, we deal with creating
-            // widgets/shortcuts/folders in a slightly different way
-            switch (info.itemType) {
-                case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
-                    mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) info, screen, touchXY);
-                    break;
-                case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
-                    mLauncher.processShortcutFromDrop(info.componentName, screen, touchXY);
-                    break;
-                default:
-                    throw new IllegalStateException("Unknown item type: " + info.itemType);
-            }
-            cellLayout.onDragExit();
+            final PendingAddItemInfo info = (PendingAddItemInfo) dragInfo;
+            mLauncher.getDragLayer().animateViewOut(d.dragView, 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) {
+                    case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+                        mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) info, screen, touchXY);
+                        break;
+                    case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+                        mLauncher.processShortcutFromDrop(info.componentName, screen, touchXY);
+                        break;
+                    default:
+                        throw new IllegalStateException("Unknown item type: " + info.itemType);
+                    }
+                    cellLayout.onDragExit();
+                }
+            });
         } else {
             // This is for other drag/drop cases, like dragging from All Apps
             ItemInfo info = (ItemInfo) dragInfo;
@@ -2853,14 +2846,24 @@
                 throw new IllegalStateException("Unknown item type: " + info.itemType);
             }
 
-            int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
-            int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
+            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) {
                 mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,
                         cellLayout, mTargetCell);
-                if (createUserFolderIfNecessary(view, cellLayout, mTargetCell, true, d.dragView)) {
+                d.postAnimationRunnable = exitSpringLoadedRunnable;
+                if (createUserFolderIfNecessary(view, cellLayout, mTargetCell, true, d.dragView,
+                        d.postAnimationRunnable)) {
                     return;
                 }
                 if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, d, true)) {
@@ -2887,7 +2890,8 @@
                     lp.cellX, lp.cellY);
 
             if (d.dragView != null) {
-                mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view);
+                mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view,
+                    exitSpringLoadedRunnable);
             }
         }
     }