Change the undo message for a "Move to" action

Previously, the undo bar toast could only show the currently
displayed folder, but we want to be able to say something like
"Moved to Social". So now, we can pass in any folder that we
consider the recipient of the action, and this is the folder name
that gets displayed in the toast.

Change-Id: I0b17462be86657f7d0c9a3504d15091a157a2292
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index f2f86fb..0f07ef0 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -2277,7 +2277,7 @@
                     @Override
                     public void run() {
                         onUndoAvailable(new ToastBarOperation(mTarget.size(), mAction,
-                                ToastBarOperation.UNDO, mIsSelectedSet));
+                                ToastBarOperation.UNDO, mIsSelectedSet, mFolder));
                     }
                 }, mShowUndoBarDelay);
             }
@@ -2304,7 +2304,8 @@
     // conversations to.
     @Override
     public final void assignFolder(Collection<FolderOperation> folderOps,
-            Collection<Conversation> target, boolean batch, boolean showUndo) {
+            Collection<Conversation> target, boolean batch, boolean showUndo,
+            final boolean isMoveTo) {
         // Actions are destructive only when the current folder can be assigned
         // to (which is the same as being able to un-assign a conversation from the folder) and
         // when the list of folders contains the current folder.
@@ -2321,12 +2322,40 @@
         // Update the UI elements depending no their visibility and availability
         // TODO(viki): Consolidate this into a single method requestDelete.
         if (isDestructive) {
+            /*
+             * If this is a MOVE operation, we want the action folder to be the destination folder.
+             * Otherwise, we want it to be the current folder.
+             *
+             * A set of folder operations is a move if there are exactly two operations: an add and
+             * a remove.
+             */
+            final Folder actionFolder;
+            if (folderOps.size() != 2) {
+                actionFolder = mFolder;
+            } else {
+                Folder addedFolder = null;
+                boolean hasRemove = false;
+                for (final FolderOperation folderOperation : folderOps) {
+                    if (folderOperation.mAdd) {
+                        addedFolder = folderOperation.mFolder;
+                    } else {
+                        hasRemove = true;
+                    }
+                }
+
+                if (hasRemove && addedFolder != null) {
+                    actionFolder = addedFolder;
+                } else {
+                    actionFolder = mFolder;
+                }
+            }
+
             folderChange = getDeferredFolderChange(target, folderOps, isDestructive,
-                    batch, showUndo);
+                    batch, showUndo, isMoveTo, actionFolder);
             delete(0, target, folderChange);
         } else {
             folderChange = getFolderChange(target, folderOps, isDestructive,
-                    batch, showUndo);
+                    batch, showUndo, false /* isMoveTo */, mFolder);
             requestUpdate(folderChange);
         }
     }
@@ -2602,8 +2631,9 @@
         }
         // Drag and drop is destructive: we remove conversations from the
         // current folder.
-        final DestructiveAction action = getFolderChange(conversations, dragDropOperations,
-                isDestructive, true, true);
+        final DestructiveAction action =
+                getFolderChange(conversations, dragDropOperations, isDestructive,
+                        true /* isBatch */, true /* showUndo */, true /* isMoveTo */, folder);
         if (isDestructive) {
             delete(0, conversations, action);
         } else {
@@ -2671,7 +2701,7 @@
         @Override
         public void performAction() {
             ToastBarOperation undoOp = new ToastBarOperation(mConversations.size(),
-                    R.id.change_folder, ToastBarOperation.UNDO, true);
+                    R.id.change_folder, ToastBarOperation.UNDO, true /* batch */, mInitialFolder);
             onUndoAvailable(undoOp);
             ArrayList<ConversationOperation> ops = new ArrayList<ConversationOperation>();
             ContentValues values = new ContentValues();
@@ -3132,20 +3162,23 @@
         private boolean mIsSelectedSet;
         private boolean mShowUndo;
         private int mAction;
+        private final Folder mActionFolder;
 
         /**
          * Create a new folder destruction object to act on the given conversations.
          * @param target conversations to act upon.
+         * @param actionFolder the {@link Folder} being acted upon, used for displaying the undo bar
          */
         private FolderDestruction(final Collection<Conversation> target,
                 final Collection<FolderOperation> folders, boolean isDestructive, boolean isBatch,
-                boolean showUndo, int action) {
+                boolean showUndo, int action, final Folder actionFolder) {
             mTarget = ImmutableList.copyOf(target);
             mFolderOps.addAll(folders);
             mIsDestructive = isDestructive;
             mIsSelectedSet = isBatch;
             mShowUndo = showUndo;
             mAction = action;
+            mActionFolder = actionFolder;
         }
 
         @Override
@@ -3155,7 +3188,7 @@
             }
             if (mIsDestructive && mShowUndo) {
                 ToastBarOperation undoOp = new ToastBarOperation(mTarget.size(), mAction,
-                        ToastBarOperation.UNDO, mIsSelectedSet);
+                        ToastBarOperation.UNDO, mIsSelectedSet, mActionFolder);
                 onUndoAvailable(undoOp);
             }
             // For each conversation, for each operation, add/ remove the
@@ -3207,18 +3240,18 @@
 
     public final DestructiveAction getFolderChange(Collection<Conversation> target,
             Collection<FolderOperation> folders, boolean isDestructive, boolean isBatch,
-            boolean showUndo) {
+            boolean showUndo, final boolean isMoveTo, final Folder actionFolder) {
         final DestructiveAction da = getDeferredFolderChange(target, folders, isDestructive,
-                isBatch, showUndo);
+                isBatch, showUndo, isMoveTo, actionFolder);
         registerDestructiveAction(da);
         return da;
     }
 
     public final DestructiveAction getDeferredFolderChange(Collection<Conversation> target,
             Collection<FolderOperation> folders, boolean isDestructive, boolean isBatch,
-            boolean showUndo) {
-        return new FolderDestruction(target, folders, isDestructive, isBatch,
-                showUndo, R.id.change_folder);
+            boolean showUndo, final boolean isMoveTo, final Folder actionFolder) {
+        return new FolderDestruction(target, folders, isDestructive, isBatch, showUndo,
+                isMoveTo ? R.id.move_folder : R.id.change_folder, actionFolder);
     }
 
     @Override
@@ -3228,7 +3261,7 @@
         Collection<FolderOperation> folderOps = new ArrayList<FolderOperation>();
         folderOps.add(new FolderOperation(toRemove, false));
         return new FolderDestruction(target, folderOps, isDestructive, isBatch,
-                showUndo, R.id.remove_folder);
+                showUndo, R.id.remove_folder, mFolder);
     }
 
     @Override
@@ -3315,7 +3348,7 @@
                 false, /* showActionIcon */
                 actionTextResourceId,
                 replaceVisibleToast,
-                new ToastBarOperation(1, 0, ToastBarOperation.ERROR, false));
+                new ToastBarOperation(1, 0, ToastBarOperation.ERROR, false, folder));
     }
 
     private ActionClickedListener getRetryClickedListener(final Folder folder) {
diff --git a/src/com/android/mail/ui/ConversationUpdater.java b/src/com/android/mail/ui/ConversationUpdater.java
index fe7f621..55511ac 100644
--- a/src/com/android/mail/ui/ConversationUpdater.java
+++ b/src/com/android/mail/ui/ConversationUpdater.java
@@ -23,7 +23,6 @@
 
 import com.android.mail.browse.ConfirmDialogFragment;
 import com.android.mail.browse.ConversationCursor;
-import com.android.mail.browse.ConversationItemView;
 import com.android.mail.browse.MessageCursor.ConversationMessage;
 import com.android.mail.providers.Conversation;
 import com.android.mail.providers.ConversationInfo;
@@ -142,15 +141,17 @@
             boolean showUndo);
 
     /**
-     * Assign the target conversations to the given folders, and remove them from all other
-     * folders that they might be assigned to.
+     * Assign the target conversations to the given folders, and remove them from all other folders
+     * that they might be assigned to.
      * @param folders the folders to assign the conversations to.
      * @param target the conversations to act upon.
      * @param batch whether this is a batch operation
      * @param showUndo whether to show the undo bar
+     * @param isMoveTo <code>true</code> if this is a move operation, <code>false</code> if it is
+     *        some other type of folder change operation
      */
     public void assignFolder(Collection<FolderOperation> folders, Collection<Conversation> target,
-            boolean batch, boolean showUndo);
+            boolean batch, boolean showUndo, boolean isMoveTo);
 
     /**
      * Refreshes the conversation list, if one exists.
diff --git a/src/com/android/mail/ui/MultiFoldersSelectionDialog.java b/src/com/android/mail/ui/MultiFoldersSelectionDialog.java
index 41b0778..cc95a48 100644
--- a/src/com/android/mail/ui/MultiFoldersSelectionDialog.java
+++ b/src/com/android/mail/ui/MultiFoldersSelectionDialog.java
@@ -30,7 +30,6 @@
 import com.android.mail.ui.FolderSelectorAdapter.FolderRow;
 import com.android.mail.utils.Utils;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
@@ -152,7 +151,8 @@
         switch (which) {
             case DialogInterface.BUTTON_POSITIVE:
                 if (mUpdater != null) {
-                    mUpdater.assignFolder(mOperations.values(), mTarget, mBatch, true);
+                    mUpdater.assignFolder(mOperations.values(), mTarget, mBatch,
+                            true /* showUndo */, false /* isMoveTo */);
                 }
                 break;
             case DialogInterface.BUTTON_NEGATIVE:
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index 44d7ed9..fc33b8d 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -608,7 +608,7 @@
                                     convList != null ? convList.getAnimatedAdapter() : null),
                             0,
                             Utils.convertHtmlToPlainText
-                                (op.getDescription(mActivity.getActivityContext(), mFolder)),
+                                (op.getDescription(mActivity.getActivityContext())),
                             true, /* showActionIcon */
                             R.string.undo,
                             true,  /* replaceVisibleToast */
@@ -622,7 +622,7 @@
                                 getUndoClickedListener(convList.getAnimatedAdapter()),
                                 0,
                                 Utils.convertHtmlToPlainText
-                                    (op.getDescription(mActivity.getActivityContext(), mFolder)),
+                                    (op.getDescription(mActivity.getActivityContext())),
                                 true, /* showActionIcon */
                                 R.string.undo,
                                 true,  /* replaceVisibleToast */
diff --git a/src/com/android/mail/ui/SingleFolderSelectionDialog.java b/src/com/android/mail/ui/SingleFolderSelectionDialog.java
index fd0d4eb..f7c5771 100644
--- a/src/com/android/mail/ui/SingleFolderSelectionDialog.java
+++ b/src/com/android/mail/ui/SingleFolderSelectionDialog.java
@@ -96,7 +96,7 @@
             // Remove the current folder and add the new folder.
             ops.add(new FolderOperation(mCurrentFolder, false));
             ops.add(new FolderOperation(folder, true));
-            mUpdater.assignFolder(ops, mTarget, mBatch, true);
+            mUpdater.assignFolder(ops, mTarget, mBatch, true /* showUndo */, true /* isMoveTo */);
             mDialog.dismiss();
         }
     }
diff --git a/src/com/android/mail/ui/SwipeableListView.java b/src/com/android/mail/ui/SwipeableListView.java
index 4048119..82d4d33 100644
--- a/src/com/android/mail/ui/SwipeableListView.java
+++ b/src/com/android/mail/ui/SwipeableListView.java
@@ -196,7 +196,8 @@
         final Context context = getContext();
         final ToastBarOperation undoOp;
 
-        undoOp = new ToastBarOperation(1, mSwipeAction, ToastBarOperation.UNDO, false);
+        undoOp = new ToastBarOperation(1, mSwipeAction, ToastBarOperation.UNDO, false /* batch */,
+                mFolder);
         Conversation conv = target.getConversation();
         target.getConversation().position = findConversation(target, conv);
         final AnimatedAdapter adapter = getAnimatedAdapter();
diff --git a/src/com/android/mail/ui/ToastBarOperation.java b/src/com/android/mail/ui/ToastBarOperation.java
index b56a94d..b47879f 100644
--- a/src/com/android/mail/ui/ToastBarOperation.java
+++ b/src/com/android/mail/ui/ToastBarOperation.java
@@ -33,19 +33,25 @@
     private final int mCount;
     private final boolean mBatch;
     private final int mType;
+    private final Folder mFolder;
 
     /**
      * Create a ToastBarOperation
      *
      * @param count Number of conversations this action would be applied to.
-     * @param menuId res id identifying the menu item tapped; used to determine
-     *            what action was performed
+     * @param menuId res id identifying the menu item tapped; used to determine what action was
+     *        performed
+     * @param operationFolder The {@link Folder} upon which the operation was run. This may be
+     *        <code>null</code>, but is required in {@link #getDescription(Context)} for certain
+     *        actions.
      */
-    public ToastBarOperation(int count, int menuId, int type, boolean batch) {
+    public ToastBarOperation(int count, int menuId, int type, boolean batch,
+            final Folder operationFolder) {
         mCount = count;
         mAction = menuId;
         mBatch = batch;
         mType = type;
+        mFolder = operationFolder;
     }
 
     public int getType() {
@@ -56,11 +62,12 @@
         return mBatch;
     }
 
-    public ToastBarOperation(Parcel in) {
+    public ToastBarOperation(final Parcel in, final ClassLoader loader) {
         mCount = in.readInt();
         mAction = in.readInt();
         mBatch = in.readInt() != 0;
         mType = in.readInt();
+        mFolder = in.readParcelable(loader);
     }
 
     @Override
@@ -69,35 +76,44 @@
         dest.writeInt(mAction);
         dest.writeInt(mBatch ? 1 : 0);
         dest.writeInt(mType);
+        dest.writeParcelable(mFolder, 0);
     }
 
-    public static final Creator<ToastBarOperation> CREATOR = new Creator<ToastBarOperation>() {
+    public static final ClassLoaderCreator<ToastBarOperation> CREATOR =
+            new ClassLoaderCreator<ToastBarOperation>() {
         @Override
-        public ToastBarOperation createFromParcel(Parcel source) {
-            return new ToastBarOperation(source);
+        public ToastBarOperation createFromParcel(final Parcel source) {
+            return createFromParcel(source, null);
         }
 
         @Override
-        public ToastBarOperation[] newArray(int size) {
+        public ToastBarOperation[] newArray(final int size) {
             return new ToastBarOperation[size];
         }
+
+        @Override
+        public ToastBarOperation createFromParcel(final Parcel source, final ClassLoader loader) {
+            return new ToastBarOperation(source, loader);
+        }
     };
 
     /**
      * Get a string description of the operation that will be performed
      * when the user taps the undo bar.
      */
-    public String getDescription(Context context, Folder folder) {
+    public String getDescription(Context context) {
         int resId = -1;
         switch (mAction) {
             case R.id.delete:
                 resId = R.plurals.conversation_deleted;
                 break;
             case R.id.remove_folder:
-                return context.getString(R.string.folder_removed, folder.name);
+                return context.getString(R.string.folder_removed, mFolder.name);
             case R.id.change_folder:
                 resId = R.plurals.conversation_folder_changed;
                 break;
+            case R.id.move_folder:
+                return context.getString(R.string.conversation_folder_moved, mFolder.name);
             case R.id.archive:
                 resId = R.plurals.conversation_archived;
                 break;
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index 4b45e3d..d022352 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -474,7 +474,7 @@
                             getUndoClickedListener(convList.getAnimatedAdapter()),
                             0,
                             Utils.convertHtmlToPlainText
-                                (op.getDescription(mActivity.getActivityContext(), mFolder)),
+                                (op.getDescription(mActivity.getActivityContext())),
                             true, /* showActionIcon */
                             R.string.undo,
                             true,  /* replaceVisibleToast */
@@ -486,7 +486,7 @@
                 if (convList != null) {
                     mToastBar.show(getUndoClickedListener(convList.getAnimatedAdapter()), 0,
                             Utils.convertHtmlToPlainText
-                                (op.getDescription(mActivity.getActivityContext(), mFolder)),
+                                (op.getDescription(mActivity.getActivityContext())),
                             true, /* showActionIcon */
                             R.string.undo, true, /* replaceVisibleToast */
                             op);