Allow fling gesture while dragging from AllApps to dismiss drag.

Change-Id: I5eea14336579a1374aded63dda9ad1a33e8b8d4a
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index 1a9958c..039ee8a 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -725,9 +725,14 @@
         return true;
     }
 
-    private void endDragging(View target, boolean success) {
+    /**
+     * Clean up after dragging.
+     *
+     * @param target where the item was dragged to (can be null if the item was flung)
+     */
+    private void endDragging(View target, boolean isFlingToDelete, boolean success) {
         mLauncher.getWorkspace().onDragStopped(success);
-        if (!success || (target != mLauncher.getWorkspace() &&
+        if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
                 !(target instanceof DeleteDropTarget))) {
             // Exit spring loaded mode if we have not successfully dropped or have not handled the
             // drop in Workspace
@@ -763,8 +768,12 @@
     }
 
     @Override
-    public void onDropCompleted(View target, DragObject d, boolean success) {
-        endDragging(target, success);
+    public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
+            boolean success) {
+        // Return early and wait for onFlingToDeleteCompleted if this was the result of a fling
+        if (isFlingToDelete) return;
+
+        endDragging(target, false, success);
 
         // Display an error message if the drag failed due to there not being enough space on the
         // target layout we were dropping on.
@@ -791,8 +800,17 @@
         mDraggingWidget = false;
     }
 
+    @Override
+    public void onFlingToDeleteCompleted() {
+        // We just dismiss the drag when we fling, so cleanup here
+        endDragging(null, true, true);
+        cleanupWidgetPreloading();
+        mDraggingWidget = false;
+    }
+
+    @Override
     public boolean supportsFlingToDelete() {
-        return false;
+        return true;
     }
 
     @Override
diff --git a/src/com/android/launcher2/DeleteDropTarget.java b/src/com/android/launcher2/DeleteDropTarget.java
index 6f45590..7e4225b 100644
--- a/src/com/android/launcher2/DeleteDropTarget.java
+++ b/src/com/android/launcher2/DeleteDropTarget.java
@@ -105,6 +105,15 @@
         return (d.dragSource instanceof Workspace) && (d.dragInfo instanceof FolderInfo);
     }
 
+    private void setHoverColor() {
+        mCurrentDrawable.startTransition(mTransitionDuration);
+        setTextColor(mHoverColor);
+    }
+    private void resetHoverColor() {
+        mCurrentDrawable.resetTransition();
+        setTextColor(mOriginalTextColor);
+    }
+
     @Override
     public boolean acceptDrop(DragObject d) {
         // We can remove everything including App shortcuts, folders, widgets, etc.
@@ -140,8 +149,7 @@
         mCurrentDrawable = (TransitionDrawable) getCompoundDrawables()[0];
 
         mActive = isVisible;
-        mCurrentDrawable.resetTransition();
-        setTextColor(mOriginalTextColor);
+        resetHoverColor();
         ((ViewGroup) getParent()).setVisibility(isVisible ? View.VISIBLE : View.GONE);
         if (getText().length() > 0) {
             setText(isUninstall ? R.string.delete_target_uninstall_label
@@ -158,16 +166,14 @@
     public void onDragEnter(DragObject d) {
         super.onDragEnter(d);
 
-        mCurrentDrawable.startTransition(mTransitionDuration);
-        setTextColor(mHoverColor);
+        setHoverColor();
     }
 
     public void onDragExit(DragObject d) {
         super.onDragExit(d);
 
         if (!d.dragComplete) {
-            mCurrentDrawable.resetTransition();
-            setTextColor(mOriginalTextColor);
+            resetHoverColor();
         } else {
             // Restore the hover color if we are deleting
             d.dragView.setColor(mHoverColor);
@@ -349,9 +355,15 @@
     }
 
     public void onFlingToDelete(final DragObject d, int x, int y, PointF vel) {
+        final boolean isAllApps = d.dragSource instanceof AppsCustomizePagedView;
+
         // Don't highlight the icon as it's animating
         d.dragView.setColor(0);
         d.dragView.updateInitialScaleToCurrentScale();
+        // Don't highlight the target if we are flinging from AllApps
+        if (isAllApps) {
+            resetHoverColor();
+        }
 
         if (mFlingDeleteMode == MODE_FLING_DELETE_TO_TRASH) {
             // Defer animating out the drop target if we are animating to it
@@ -396,8 +408,14 @@
             @Override
             public void run() {
                 mSearchDropTargetBar.onDragEnd();
-                mLauncher.exitSpringLoadedDragMode();
-                completeDrop(d);
+
+                // If we are dragging from AllApps, then we allow AppsCustomizePagedView to clean up
+                // itself, otherwise, complete the drop to initiate the deletion process
+                if (!isAllApps) {
+                    mLauncher.exitSpringLoadedDragMode();
+                    completeDrop(d);
+                }
+                mLauncher.getDragController().onDeferredEndFling(d);
             }
         };
         dragLayer.animateView(d.dragView, updateCb, duration, tInterpolator, onAnimationEndRunnable,
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index 2a88925..5a8617c 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -366,7 +366,7 @@
             mDragObject.deferDragViewCleanupPostAnimation = false;
             mDragObject.cancelled = true;
             mDragObject.dragComplete = true;
-            mDragObject.dragSource.onDropCompleted(null, mDragObject, false);
+            mDragObject.dragSource.onDropCompleted(null, mDragObject, false, false);
         }
         endDrag();
     }
@@ -422,6 +422,10 @@
         }
     }
 
+    void onDeferredEndFling(DropTarget.DragObject d) {
+        d.dragSource.onFlingToDeleteCompleted();
+    }
+
     /**
      * Clamps the position to the drag layer bounds.
      */
@@ -665,7 +669,7 @@
                     vel);
             accepted = true;
         }
-        mDragObject.dragSource.onDropCompleted((View) mFlingToDeleteDropTarget, mDragObject,
+        mDragObject.dragSource.onDropCompleted((View) mFlingToDeleteDropTarget, mDragObject, true,
                 accepted);
     }
 
@@ -684,7 +688,7 @@
                 accepted = true;
             }
         }
-        mDragObject.dragSource.onDropCompleted((View) dropTarget, mDragObject, accepted);
+        mDragObject.dragSource.onDropCompleted((View) dropTarget, mDragObject, false, accepted);
     }
 
     private DropTarget findDropTarget(int x, int y, int[] dropCoordinates) {
diff --git a/src/com/android/launcher2/DragSource.java b/src/com/android/launcher2/DragSource.java
index a654b93..5440477 100644
--- a/src/com/android/launcher2/DragSource.java
+++ b/src/com/android/launcher2/DragSource.java
@@ -25,6 +25,21 @@
  *
  */
 public interface DragSource {
+    /**
+     * @return whether items dragged from this source supports
+     */
     boolean supportsFlingToDelete();
-    void onDropCompleted(View target, DragObject d, boolean success);
+
+    /**
+     * A callback specifically made back to the source after an item from this source has been flung
+     * to be deleted on a DropTarget.  In such a situation, this method will be called after
+     * onDropCompleted, and more importantly, after the fling animation has completed.
+     */
+    void onFlingToDeleteCompleted();
+
+    /**
+     * A callback made back to the source after an item from this source has been dropped on a
+     * DropTarget.
+     */
+    void onDropCompleted(View target, DragObject d, boolean isFlingToDelete, boolean success);
 }
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 6856a09..c502fb7 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -44,6 +44,7 @@
 import android.widget.TextView;
 
 import com.android.launcher.R;
+import com.android.launcher2.DropTarget.DragObject;
 import com.android.launcher2.FolderInfo.FolderListener;
 
 import java.util.ArrayList;
@@ -619,7 +620,8 @@
         mReorderAlarm.cancelAlarm();
     }
 
-    public void onDropCompleted(View target, DragObject d, boolean success) {
+    public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
+            boolean success) {
         if (success) {
             if (mDeleteFolderOnDropCompleted && !mItemAddedBackToSelfViaIcon) {
                 replaceFolderWithFinalItem();
@@ -653,10 +655,20 @@
         updateItemLocationsInDatabase();
     }
 
+    @Override
     public boolean supportsFlingToDelete() {
         return true;
     }
 
+    public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
+        // Do nothing
+    }
+
+    @Override
+    public void onFlingToDeleteCompleted() {
+        // Do nothing
+    }
+
     private void updateItemLocationsInDatabase() {
         ArrayList<View> list = getItemsInReadingOrder();
         for (int i = 0; i < list.size(); i++) {
@@ -928,10 +940,6 @@
         mInfo.add(item);
     }
 
-    public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
-        // Do nothing
-    }
-
     public void onAdd(ShortcutInfo item) {
         mItemsInvalidated = true;
         // If the item was dropped onto this open folder, we have done the work associated
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 8f11612..423c9ce 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -59,6 +59,7 @@
 import android.widget.TextView;
 
 import com.android.launcher.R;
+import com.android.launcher2.DropTarget.DragObject;
 import com.android.launcher2.FolderIcon.FolderRingAnimator;
 import com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
 import com.android.launcher2.LauncherSettings.Favorites;
@@ -2340,10 +2341,6 @@
         }
     }
 
-    public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
-        // Do nothing
-    }
-
     public void setFinalScrollForPageChange(int screen) {
         if (screen >= 0) {
             mSavedScrollX = getScrollX();
@@ -3279,7 +3276,8 @@
     /**
      * Called at the end of a drag which originated on the workspace.
      */
-    public void onDropCompleted(View target, DragObject d, boolean success) {
+    public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
+            boolean success) {
         if (success) {
             if (target != this) {
                 if (mDragInfo != null) {
@@ -3336,10 +3334,21 @@
         }
     }
 
+    @Override
     public boolean supportsFlingToDelete() {
         return true;
     }
 
+    @Override
+    public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
+        // Do nothing
+    }
+
+    @Override
+    public void onFlingToDeleteCompleted() {
+        // Do nothing
+    }
+
     public boolean isDropEnabled() {
         return true;
     }