Merge "Controller owns the FolderSelection Destructive Action"
diff --git a/src/com/android/mail/browse/SelectedConversationsActionMenu.java b/src/com/android/mail/browse/SelectedConversationsActionMenu.java
index 380a68c..8169ded 100644
--- a/src/com/android/mail/browse/SelectedConversationsActionMenu.java
+++ b/src/com/android/mail/browse/SelectedConversationsActionMenu.java
@@ -43,7 +43,6 @@
 import com.android.mail.ui.RestrictedActivity;
 import com.android.mail.ui.SwipeableListView;
 import com.android.mail.ui.UndoBarView.UndoListener;
-import com.android.mail.ui.UndoOperation;
 import com.android.mail.utils.LogUtils;
 import com.android.mail.utils.Utils;
 import com.google.common.annotations.VisibleForTesting;
@@ -66,10 +65,6 @@
      */
     protected final ConversationSelectionSet mSelectionSet;
     /**
-     * The set of conversations to marked for deletion
-     */
-    protected Collection<Conversation> mDeletionSet;
-    /**
      * The new folder list (after selection)
      */
     protected ArrayList<Folder> mFolderChangeList;
@@ -281,6 +276,9 @@
         new FoldersSelectionDialog(mContext, mAccount, this, mSelectionSet.values()).show();
     }
 
+    // Both this class and AbstractActivityController are listeners for folder changes and the
+    // logic is largely the same.
+    // TODO(viki): hold all this in AbstractActivityController.
     @Override
     public void onFolderChangesCommit(ArrayList<Folder> folderChangeList) {
         mFolderChangeList = folderChangeList;
@@ -295,56 +293,31 @@
             }
         }
         if (!folderUris.contains(mFolder.uri.toString())) {
+            // All these conversations are *removed* from the current folder. Animate deletion.
+            final boolean isDestructive = true;
+            // We copy the selected set because it might change as the animation starts, and we want
+            // to apply the action to the current selection.
             final Collection<Conversation> conversations = mSelectionSet.values();
             // Indicate delete on update (i.e. no longer in this folder)
-            mDeletionSet = new ArrayList<Conversation>();
+            final Collection<Conversation> deletionSet = new ArrayList<Conversation>();
             for (Conversation conv : conversations) {
                 conv.localDeleteOnUpdate = true;
                 // For Gmail, add... if (noLongerInList(conv))...
-                mDeletionSet.add(conv);
+                deletionSet.add(conv);
             }
-            // Delete the local delete items (all for now) and when done,
-            // update...
-            mListAdapter.delete(mDeletionSet, mFolderChangeListener);
+            // Delete the local delete items (all for now) and when done, update...
+            final DestructiveAction action = mController.getFolderChange(deletionSet,
+                    mFolderChangeList, isDestructive);
+            mListAdapter.delete(deletionSet, action);
         } else {
-            mFolderChangeListener.performAction();
+            // Conversations are not removed. They just have their labels changed.
+            final boolean isDestructive = false;
+            final DestructiveAction action = mController.getFolderChange(mSelectionSet.values(),
+                    mFolderChangeList, isDestructive);
+            action.performAction();
         }
     }
 
-    private final DestructiveAction mFolderChangeListener = new DestructiveAction() {
-        @Override
-        public void performAction() {
-            mController.performAction();
-            final Collection<Conversation> deletionSet = mDeletionSet;
-            final boolean isDestructive = (deletionSet != null && deletionSet.size() > 0);
-            if (isDestructive) {
-                // Only show undo if this was a destructive folder change.
-                UndoOperation undoOp = new UndoOperation(deletionSet.size(), R.id.change_folder);
-                mUndoListener.onUndoAvailable(undoOp);
-                mDeletionSet = null;
-            }
-            final StringBuilder foldersUrisString = new StringBuilder();
-            boolean first = true;
-            for (Folder f : mFolderChangeList) {
-                if (first) {
-                    first = false;
-                } else {
-                    foldersUrisString.append(',');
-                }
-                foldersUrisString.append(f.uri.toString());
-            }
-            mConversationCursor.updateString(mContext, mSelectionSet.values(),
-                    ConversationColumns.FOLDER_LIST, foldersUrisString.toString());
-            mConversationCursor.updateString(mContext, mSelectionSet.values(),
-                    ConversationColumns.RAW_FOLDERS,
-                    Folder.getSerializedFolderString(mFolder, mFolderChangeList));
-            clearSelection();
-            if (isDestructive) {
-                mListAdapter.notifyDataSetChanged();
-            }
-        }
-    };
-
     @Override
     public boolean onCreateActionMode(ActionMode mode, Menu menu) {
         mSelectionSet.addObserver(this);
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 9dbb17a..77a4144 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -1426,7 +1426,7 @@
     // Called from the FolderSelectionDialog after a user is done changing
     // folders.
     @Override
-    public void onFolderChangesCommit(ArrayList<Folder> folderChangeList) {
+    public final void onFolderChangesCommit(ArrayList<Folder> folderChangeList) {
         // Get currently active folder info and compare it to the list
         // these conversations have been given; if they no longer contain
         // the selected folder, delete them from the list.
@@ -1917,4 +1917,62 @@
         registerDestructiveAction(da);
         return da;
     }
+
+    private class FolderDestruction implements DestructiveAction {
+        private final Collection<Conversation> mTarget = new ArrayList<Conversation>();
+        private final ArrayList<Folder> mFolderList = new ArrayList<Folder>();
+        private final boolean mIsDestructive;
+
+        /**
+         * Create a new folder destruction object to act on the given conversations.
+         * @param target
+         */
+        private FolderDestruction(Collection<Conversation> target, Collection<Folder> folders,
+                boolean isDestructive) {
+            mTarget.addAll(target);
+            mFolderList.addAll(folders);
+            mIsDestructive = isDestructive;
+        }
+
+        /* (non-Javadoc)
+         * @see com.android.mail.ui.DestructiveAction#performAction()
+         */
+        @Override
+        public void performAction() {
+            AbstractActivityController.this.performAction();
+            if (mIsDestructive) {
+                // Only show undo if this was a destructive folder change.
+                UndoOperation undoOp = new UndoOperation(mTarget.size(), R.id.change_folder);
+                onUndoAvailable(undoOp);
+            }
+            final StringBuilder foldersUrisString = new StringBuilder();
+            boolean first = true;
+            for (Folder f : mFolderList) {
+                if (first) {
+                    first = false;
+                } else {
+                    foldersUrisString.append(',');
+                }
+                foldersUrisString.append(f.uri.toString());
+            }
+            mConversationListCursor.updateString(mContext, mTarget,
+                    ConversationColumns.FOLDER_LIST, foldersUrisString.toString());
+            mConversationListCursor.updateString(mContext, mTarget,
+                    ConversationColumns.RAW_FOLDERS,
+                    Folder.getSerializedFolderString(mFolder, mFolderList));
+            if (mIsDestructive) {
+                final ConversationListFragment convList = getConversationListFragment();
+                if (convList == null) {
+                    return;
+                }
+                convList.requestListRefresh();
+            }
+        }
+    }
+    public final DestructiveAction getFolderChange(Collection<Conversation> target,
+            Collection<Folder> folders, boolean isDestructive){
+        final DestructiveAction da = new FolderDestruction(target, folders, isDestructive);
+        registerDestructiveAction(da);
+        return da;
+    }
 }