Fixing drag-n-drop for folders in hotseat.

The current drag-n-drop model assums that when a folder is open
it completely covers the folderIcon and its not possible to drop
anything on the icon. But its not true when a folder is in the
hotseat.

> When DnD finishes revert folder to the normal state
> Ensure that only one folder is open at a time
> Prevent folder icon from moving when the folder is open

Bug: 13646281,14680549
Change-Id: I016a4c3f0d9b57c388eaa28f40df9e7b7bbab5fc
diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java
index eb16861..3473747 100644
--- a/src/com/android/launcher3/DragController.java
+++ b/src/com/android/launcher3/DragController.java
@@ -377,7 +377,7 @@
 
             // Only end the drag if we are not deferred
             if (!isDeferred) {
-                for (DragListener listener : mListeners) {
+                for (DragListener listener : new ArrayList<>(mListeners)) {
                     listener.onDragEnd();
                 }
             }
@@ -394,7 +394,7 @@
 
         if (mDragObject.deferDragViewCleanupPostAnimation) {
             // If we skipped calling onDragEnd() before, do it now
-            for (DragListener listener : mListeners) {
+            for (DragListener listener : new ArrayList<>(mListeners)) {
                 listener.onDragEnd();
             }
         }
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 0eb1fd8..1163324 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -49,6 +49,7 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.android.launcher3.DragController.DragListener;
 import com.android.launcher3.FolderInfo.FolderListener;
 import com.android.launcher3.Workspace.ItemOperator;
 import com.android.launcher3.util.Thunk;
@@ -61,7 +62,7 @@
  */
 public class Folder extends LinearLayout implements DragSource, View.OnClickListener,
         View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
-        View.OnFocusChangeListener {
+        View.OnFocusChangeListener, DragListener {
     private static final String TAG = "Launcher.Folder";
 
     /**
@@ -537,6 +538,20 @@
             mScrollPauseAlarm.setAlarm(SORTED_STICKY_REORDER_DELAY);
         }
 
+        // Since this folder opened by another controller, it might not get onDrop or
+        // onDropComplete. Perform cleanup once drag-n-drop ends.
+        mDragController.addDragListener(this);
+    }
+
+    @Override
+    public void onDragStart(DragSource source, Object info, int dragAction) { }
+
+    @Override
+    public void onDragEnd() {
+        if (mIsExternalDrag && mDragInProgress) {
+            completeDragExit();
+        }
+        mDragController.removeDragListener(this);
     }
 
     @Thunk void sendCustomAccessibilityEvent(int type, String text) {
@@ -678,11 +693,15 @@
     };
 
     public void completeDragExit() {
-        mLauncher.closeFolder();
+        if (mInfo.opened) {
+            mLauncher.closeFolder();
+            mRearrangeOnClose = true;
+        } else {
+            rearrangeChildren();
+        }
         mCurrentDragInfo = null;
         mCurrentDragView = null;
         mSuppressOnAdd = false;
-        mRearrangeOnClose = true;
         mIsExternalDrag = false;
     }
 
@@ -1124,6 +1143,7 @@
         mSuppressOnAdd = false;
         // Clear the drag info, as it is no longer being dragged.
         mCurrentDragInfo = null;
+        mDragInProgress = false;
     }
 
     // This is used so the item doesn't immediately appear in the folder when added. In one case
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 42e145b..9ad87c3 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -3112,10 +3112,19 @@
      */
     public void openFolder(FolderIcon folderIcon) {
         Folder folder = folderIcon.getFolder();
+        Folder openFolder = mWorkspace != null ? mWorkspace.getOpenFolder() : null;
+        if (openFolder != null && openFolder != folder) {
+            // Close any open folder before opening a folder.
+            closeFolder();
+        }
+
         FolderInfo info = folder.mInfo;
 
         info.opened = true;
 
+        // While the folder is open, the position of the icon cannot change.
+        ((CellLayout.LayoutParams) folderIcon.getLayoutParams()).canReorder = false;
+
         // Just verify that the folder hasn't already been added to the DragLayer.
         // There was a one-off crash where the folder had a parent already.
         if (folder.getParent() == null) {
@@ -3151,6 +3160,9 @@
         if (parent != null) {
             FolderIcon fi = (FolderIcon) mWorkspace.getViewForTag(folder.mInfo);
             shrinkAndFadeInFolderIcon(fi);
+            if (fi != null) {
+                ((CellLayout.LayoutParams) fi.getLayoutParams()).canReorder = true;
+            }
         }
         folder.animateClosed();