Fixing up some folder-related drag and drop bugs

Change-Id: I712ffd0ccfc0154a5a9e74e3f585157a86986882
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 08907c9..d6be307 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -84,6 +84,7 @@
     private ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
     private Drawable mIconDrawable;
     boolean mItemsInvalidated = false;
+    ShortcutInfo mCurrentDragInfo;
 
     /**
      * Used to inflate the Workspace from XML.
@@ -147,7 +148,10 @@
             mDragItemPosition[0] = item.cellX;
             mDragItemPosition[1] = item.cellY;
             mIconDrawable = ((TextView) v).getCompoundDrawables()[1];
-            mInfo.remove(item);
+
+            mCurrentDragInfo = item;
+            mItemsInvalidated = true;
+            mInfo.itemsChanged();
 
             mDragItem = item;
         } else {
@@ -388,8 +392,13 @@
         } else {
             item = (ShortcutInfo) d.dragInfo;
         }
+
+        // Dragged from self onto self
+        if (item == mCurrentDragInfo) {
+            mInfo.remove(item);
+        }
+
         mInfo.add(item);
-        LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
     }
 
     protected boolean findAndSetEmptyCells(ShortcutInfo item) {
@@ -397,8 +406,6 @@
         if (mContent.findCellForSpan(emptyCell, item.spanX, item.spanY)) {
             item.cellX = emptyCell[0];
             item.cellY = emptyCell[1];
-            LauncherModel.addOrMoveItemInDatabase(
-                    mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
             return true;
         } else {
             return false;
@@ -449,6 +456,21 @@
     }
 
     public void onDropCompleted(View target, DragObject d, boolean success) {
+        if (!success) {
+            if (d.dragView != null) {
+                if (target instanceof CellLayout) {
+                    // TODO: we should animate the item back to the folder in this case
+                }
+            }
+            mCurrentDragInfo = null;
+            mItemsInvalidated = true;
+            mInfo.itemsChanged();
+        } else {
+            if (target != this) {
+                mInfo.remove(mCurrentDragInfo);
+                mCurrentDragInfo = null;
+            }
+        }
     }
 
     public boolean isDropEnabled() {
@@ -580,6 +602,8 @@
             findAndSetEmptyCells(item);
         }
         createAndAddShortcut(item);
+        LauncherModel.addOrMoveItemInDatabase(
+                mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
     }
 
     public int getItemCount() {
@@ -608,14 +632,24 @@
         }
     }
 
+    public void onItemsChanged() {
+    }
+
     public ArrayList<View> getItemsInReadingOrder() {
+        return getItemsInReadingOrder(true);
+    }
+
+    public ArrayList<View> getItemsInReadingOrder(boolean includeCurrentDragItem) {
         if (mItemsInvalidated) {
             mItemsInReadingOrder.clear();
             for (int j = 0; j < mContent.getCountY(); j++) {
                 for (int i = 0; i < mContent.getCountX(); i++) {
                     View v = mContent.getChildAt(i, j);
                     if (v != null) {
-                        mItemsInReadingOrder.add(v);
+                        ShortcutInfo info = (ShortcutInfo) v.getTag();
+                        if (info != mCurrentDragInfo || includeCurrentDragItem) {
+                            mItemsInReadingOrder.add(v);
+                        }
                     }
                 }
             }
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index 449068c..18b242b 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -316,7 +316,7 @@
         int baselineWidth = (int) (d.getIntrinsicWidth() * baselineIconScale);
         float maxPerpectiveShift = baselineHeight * PERSPECTIVE_SHIFT_FACTOR;
 
-        ArrayList<View> items = mFolder.getItemsInReadingOrder();
+        ArrayList<View> items = mFolder.getItemsInReadingOrder(false);
         int firstItemIndex = Math.max(0, items.size() - NUM_ITEMS_IN_PREVIEW);
 
         int xShift = (int) (mOriginalWidth - baselineWidth) / 2;
@@ -352,6 +352,11 @@
         canvas.restore();
     }
 
+    public void onItemsChanged() {
+        invalidate();
+        requestLayout();
+    }
+
     public void onAdd(ShortcutInfo item) {
         invalidate();
         requestLayout();
diff --git a/src/com/android/launcher2/FolderInfo.java b/src/com/android/launcher2/FolderInfo.java
index 12ed27c..805a51f 100644
--- a/src/com/android/launcher2/FolderInfo.java
+++ b/src/com/android/launcher2/FolderInfo.java
@@ -86,8 +86,15 @@
         }
     }
 
+    void itemsChanged() {
+        for (int i = 0; i < listeners.size(); i++) {
+            listeners.get(i).onItemsChanged();
+        }
+    }
+
     interface FolderListener {
         public void onAdd(ShortcutInfo item);
         public void onRemove(ShortcutInfo item);
+        public void onItemsChanged();
     }
 }
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 812763f..5c3399c 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -2350,23 +2350,11 @@
         lp.oldY = viewY - (layout.getTop() + layout.getTopPadding() - mScrollY);
     }
 
-    /*
-     * We should be careful that this method cannot result in any synchronous requestLayout()
-     * calls, as it is called from onLayout().
-     */
-    public void animateViewIntoPosition(final View view) {
-        final CellLayout parent = (CellLayout) view.getParent().getParent();
-        final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
-
-        // Convert the animation params to be relative to the Workspace, not the CellLayout
-        final int fromX = lp.oldX + parent.getLeft() + parent.getLeftPadding();
-        final int fromY = lp.oldY + parent.getTop() + parent.getTopPadding();
-
-        final int dx = lp.x - lp.oldX;
-        final int dy = lp.y - lp.oldY;
+    public void animateViewIntoPosition(final View view, final int fromX, final int fromY, 
+            final int dX, final int dY, final Runnable animationEndRunnable) {
 
         // Calculate the duration of the animation based on the object's distance
-        final float dist = (float) Math.sqrt(dx*dx + dy*dy);
+        final float dist = (float) Math.sqrt(dX*dX + dY*dY);
         final Resources res = getResources();
         final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
         int duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
@@ -2388,10 +2376,7 @@
             }
 
             public void onAnimationEnd(Animator animation) {
-                if (mDropView != null) {
-                    mDropView.setVisibility(View.VISIBLE);
-                    mDropView = null;
-                }
+                animationEndRunnable.run();
             }
         });
 
@@ -2405,8 +2390,8 @@
                 invalidate(mDropViewPos[0], mDropViewPos[1],
                         mDropViewPos[0] + view.getWidth(), mDropViewPos[1] + view.getHeight());
 
-                mDropViewPos[0] = fromX + (int) (percent * dx + 0.5f);
-                mDropViewPos[1] = fromY + (int) (percent * dy + 0.5f);
+                mDropViewPos[0] = fromX + (int) (percent * dX + 0.5f);
+                mDropViewPos[1] = fromY + (int) (percent * dY + 0.5f);
                 invalidate(mDropViewPos[0], mDropViewPos[1],
                         mDropViewPos[0] + view.getWidth(), mDropViewPos[1] + view.getHeight());
             }
@@ -2415,6 +2400,32 @@
         mDropAnim.start();
     }
 
+    /*
+     * We should be careful that this method cannot result in any synchronous requestLayout()
+     * calls, as it is called from onLayout().
+     */
+    public void animateViewIntoPosition(final View view) {
+        final CellLayout parent = (CellLayout) view.getParent().getParent();
+        final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
+
+        // Convert the animation params to be relative to the Workspace, not the CellLayout
+        final int fromX = lp.oldX + parent.getLeft() + parent.getLeftPadding();
+        final int fromY = lp.oldY + parent.getTop() + parent.getTopPadding();
+
+        final int dx = lp.x - lp.oldX;
+        final int dy = lp.y - lp.oldY;
+
+        Runnable animationEndRunnable = new Runnable() {
+            public void run() {
+                if (mDropView != null) {
+                    mDropView.setVisibility(View.VISIBLE);
+                    mDropView = null;
+                }
+            }
+        };
+        animateViewIntoPosition(view, fromX, fromY, dx, dy, animationEndRunnable);
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -2530,6 +2541,7 @@
                 scrollToNewPageWithoutMovingPages(dragTargetIndex);
             }
         }
+        CellLayout dropTargetLayout = mDragTargetLayout;
 
         if (d.dragSource != this) {
             final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],
@@ -2541,22 +2553,9 @@
                 ((ItemInfo) d.dragInfo).dropPos = touchXY;
                 return;
             }
-            onDropExternal(touchXY, d.dragInfo, mDragTargetLayout, false, d.dragView);
+            onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d.dragView);
         } else if (mDragInfo != null) {
             final View cell = mDragInfo.cell;
-            CellLayout dropTargetLayout = mDragTargetLayout;
-            boolean dropInscrollArea = false;
-
-            // Handle the case where the user drops when in the scroll area.
-            // This is treated as a drop on the adjacent page.
-            if (dropTargetLayout == null && mInScrollArea) {
-                dropInscrollArea = true;
-                if (mPendingScrollDirection == DragController.SCROLL_LEFT) {
-                    dropTargetLayout = (CellLayout) getChildAt(mCurrentPage - 1);
-                } else if (mPendingScrollDirection == DragController.SCROLL_RIGHT) {
-                    dropTargetLayout = (CellLayout) getChildAt(mCurrentPage + 1);
-                }
-            }
 
             if (dropTargetLayout != null) {
                 // Move internally
@@ -2570,8 +2569,9 @@
                 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int)
                         mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell);
                 // If the item being dropped is a shortcut and the nearest drop
-                // cell also contains
-                // a shortcut, then create a folder with the two shortcuts.
+                // cell also contains a shortcut, then create a folder with the two shortcuts.
+                boolean dropInscrollArea = mCurrentPage != screen;
+
                 if (!dropInscrollArea && createUserFolderIfNecessary(cell, dropTargetLayout,
                         mTargetCell, false)) {
                     return;
@@ -2588,7 +2588,7 @@
                         (int) mDragViewVisualCenter[1], mDragInfo.spanX, mDragInfo.spanY, cell,
                         dropTargetLayout, mTargetCell);
 
-                if (screen != mCurrentPage) {
+                if (dropInscrollArea && mShrinkState != ShrinkState.SPRING_LOADED) {
                     snapToPage(screen);
                 }
 
@@ -2600,6 +2600,7 @@
                                 mDragInfo.spanY);
                     }
 
+
                     // update the item's position after drop
                     final ItemInfo info = (ItemInfo) cell.getTag();
                     CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
@@ -2655,7 +2656,7 @@
         }
     }
 
-    private void getViewLocationRelativeToSelf(View v, int[] location) {
+    public void getViewLocationRelativeToSelf(View v, int[] location) {
         getLocationOnScreen(location);
         int x = location[0];
         int y = location[1];
@@ -3113,7 +3114,6 @@
                     if (dragOverView != mLastDragOverView) {
                         cancelFolderCreation();
                         if (mLastDragOverView != null && mLastDragOverView instanceof FolderIcon) {
-
                             ((FolderIcon) mLastDragOverView).onDragExit(d.dragInfo);
                         }
                     }
@@ -3249,6 +3249,9 @@
     private void onDropExternal(int[] touchXY, Object dragInfo,
             CellLayout cellLayout, boolean insertAtFirst, DragView dragView) {
         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
@@ -3452,7 +3455,7 @@
 
                 if (mDragTargetLayout != null) {
                     mDragTargetLayout.onDragExit();
-                    mDragTargetLayout = null;
+                    mDragTargetLayout = layout;
                 }
                 // In portrait, need to redraw the edge glow when entering the scroll area
                 if (getHeight() > getWidth()) {