Merge "Move to Inbox" into jb-ub-mail-ur10
diff --git a/res/menu-sw600dp-land/conversation_actions.xml b/res/menu-sw600dp-land/conversation_actions.xml
index f463841..3a74345 100644
--- a/res/menu-sw600dp-land/conversation_actions.xml
+++ b/res/menu-sw600dp-land/conversation_actions.xml
@@ -84,6 +84,11 @@
         android:icon="@drawable/ic_menu_folders_holo_light" />
 
     <item
+        android:id="@+id/move_to_inbox"
+        android:showAsAction="never"
+        android:title="@string/menu_move_to_inbox" />
+
+    <item
         android:id="@+id/mark_important"
         android:showAsAction="never"
         android:title="@string/mark_important" />
diff --git a/res/menu/conversation_actions.xml b/res/menu/conversation_actions.xml
index e70d6db..9d63506 100644
--- a/res/menu/conversation_actions.xml
+++ b/res/menu/conversation_actions.xml
@@ -72,6 +72,11 @@
         android:showAsAction="never"
         android:icon="@drawable/ic_menu_folders_holo_light" />
 
+    <item
+        android:id="@+id/move_to_inbox"
+        android:showAsAction="never"
+        android:title="@string/menu_move_to_inbox" />
+
     <!-- Always available -->
     <item
         android:id="@+id/mark_important"
diff --git a/res/menu/conversation_list_selection_actions_menu.xml b/res/menu/conversation_list_selection_actions_menu.xml
index f635a4f..b866497 100644
--- a/res/menu/conversation_list_selection_actions_menu.xml
+++ b/res/menu/conversation_list_selection_actions_menu.xml
@@ -78,6 +78,11 @@
         android:title="@string/menu_change_folders"
         android:icon="@drawable/ic_menu_folders_holo_light" />
 
+    <item
+        android:id="@+id/move_to_inbox"
+        android:showAsAction="never"
+        android:title="@string/menu_move_to_inbox" />
+
     <item android:id="@+id/star"
         android:title="@string/add_star"
         android:showAsAction="never" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4498192..5d01b01 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -151,6 +151,8 @@
     <string name="menu_change_folders">Change folders</string>
     <!-- Menu item: moves to folders for selected conversation(s). [CHAR LIMIT = 30] -->
     <string name="menu_move_to">Move to</string>
+    <!-- Menu item: moves current or selected conversation(s) to Inbox. [CHAR LIMIT = 30] -->
+    <string name="menu_move_to_inbox">Move to Inbox</string>
     <!-- Menu item: manages the folders for this account. [CHAR LIMIT = 30] -->
     <string name="menu_manage_folders">Folder settings</string>
     <!-- Menu item: report an email was not readable or poorly rendered -->
diff --git a/src/com/android/mail/browse/SelectedConversationsActionMenu.java b/src/com/android/mail/browse/SelectedConversationsActionMenu.java
index 6b05fbe..1d35cae 100644
--- a/src/com/android/mail/browse/SelectedConversationsActionMenu.java
+++ b/src/com/android/mail/browse/SelectedConversationsActionMenu.java
@@ -19,6 +19,7 @@
 
 import android.content.Context;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.view.ActionMode;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -43,14 +44,17 @@
 import com.android.mail.ui.ConversationSetObserver;
 import com.android.mail.ui.ConversationUpdater;
 import com.android.mail.ui.DestructiveAction;
+import com.android.mail.ui.FolderOperation;
 import com.android.mail.ui.FolderSelectionDialog;
 import com.android.mail.ui.MailActionBarView;
 import com.android.mail.utils.LogTag;
 import com.android.mail.utils.LogUtils;
 import com.android.mail.utils.Utils;
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Lists;
 
 import java.util.Collection;
+import java.util.List;
 
 /**
  * A component that displays a custom view for an {@code ActionBar}'s {@code
@@ -198,6 +202,25 @@
                     }
                 }
                 break;
+            case R.id.move_to_inbox:
+                new AsyncTask<Void, Void, Folder>() {
+                    @Override
+                    protected Folder doInBackground(final Void... params) {
+                        // Get the "move to" inbox
+                        return Utils.getFolder(mContext, mAccount.settings.moveToInbox,
+                                true /* allowHidden */);
+                    }
+
+                    @Override
+                    protected void onPostExecute(final Folder moveToInbox) {
+                        final List<FolderOperation> ops = Lists.newArrayListWithCapacity(1);
+                        // Add inbox
+                        ops.add(new FolderOperation(moveToInbox, true));
+                        mUpdater.assignFolder(ops, mSelectionSet.values(), true,
+                                true /* showUndo */, false /* isMoveTo */);
+                    }
+                }.execute((Void[]) null);
+                break;
             case R.id.mark_important:
                 markConversationsImportant(true);
                 break;
@@ -382,13 +405,18 @@
         // archive icon if the setting for that is true.
         final MenuItem removeFolder = menu.findItem(R.id.remove_folder);
         final MenuItem moveTo = menu.findItem(R.id.move_to);
+        final MenuItem moveToInbox = menu.findItem(R.id.move_to_inbox);
         final boolean showRemoveFolder = mFolder != null && mFolder.isType(FolderType.DEFAULT)
                 && mFolder.supportsCapability(FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES)
                 && !mFolder.isProviderFolder();
         final boolean showMoveTo = mFolder != null
                 && mFolder.supportsCapability(FolderCapabilities.ALLOWS_REMOVE_CONVERSATION);
+        final boolean showMoveToInbox = mFolder != null
+                && mFolder.supportsCapability(FolderCapabilities.ALLOWS_MOVE_TO_INBOX);
         removeFolder.setVisible(showRemoveFolder);
         moveTo.setVisible(showMoveTo);
+        moveToInbox.setVisible(showMoveToInbox);
+
         if (mFolder != null && showRemoveFolder) {
             removeFolder.setTitle(mActivity.getActivityContext().getString(R.string.remove_folder,
                     mFolder.name));
diff --git a/src/com/android/mail/providers/Account.java b/src/com/android/mail/providers/Account.java
index 391ffe0..256b30a 100644
--- a/src/com/android/mail/providers/Account.java
+++ b/src/com/android/mail/providers/Account.java
@@ -756,6 +756,7 @@
                 settings.conversationViewMode);
         map.put(AccountColumns.SettingsColumns.VEILED_ADDRESS_PATTERN,
                 settings.veiledAddressPattern);
+        map.put(AccountColumns.SettingsColumns.MOVE_TO_INBOX, settings.moveToInbox);
 
         return map;
     }
diff --git a/src/com/android/mail/providers/Settings.java b/src/com/android/mail/providers/Settings.java
index 9a8fddd..d07a60e 100644
--- a/src/com/android/mail/providers/Settings.java
+++ b/src/com/android/mail/providers/Settings.java
@@ -89,6 +89,12 @@
     public final Uri setupIntentUri;
     public final String veiledAddressPattern;
 
+    /**
+     * The {@link Uri} to use when moving a conversation to the inbox. May
+     * differ from {@link #defaultInbox}.
+     */
+    public final Uri moveToInbox;
+
     /** Cached value of hashCode */
     private int mHashCode;
 
@@ -114,6 +120,7 @@
         setupIntentUri = Uri.EMPTY;
         conversationViewMode = UIProvider.ConversationViewMode.UNDEFINED;
         veiledAddressPattern = null;
+        moveToInbox = Uri.EMPTY;
     }
 
     public Settings(Parcel inParcel) {
@@ -135,6 +142,7 @@
         setupIntentUri = Utils.getValidUri(inParcel.readString());
         conversationViewMode = inParcel.readInt();
         veiledAddressPattern = inParcel.readString();
+        moveToInbox = Utils.getValidUri(inParcel.readString());
     }
 
     public Settings(Cursor cursor) {
@@ -164,6 +172,8 @@
                 cursor.getInt(cursor.getColumnIndex(SettingsColumns.CONVERSATION_VIEW_MODE));
         veiledAddressPattern =
                 cursor.getString(cursor.getColumnIndex(SettingsColumns.VEILED_ADDRESS_PATTERN));
+        moveToInbox = Utils.getValidUri(
+                cursor.getString(cursor.getColumnIndex(SettingsColumns.MOVE_TO_INBOX)));
     }
 
     private Settings(JSONObject json) {
@@ -190,6 +200,7 @@
         conversationViewMode = json.optInt(SettingsColumns.CONVERSATION_VIEW_MODE,
                 UIProvider.ConversationViewMode.UNDEFINED);
         veiledAddressPattern = json.optString(SettingsColumns.VEILED_ADDRESS_PATTERN, null);
+        moveToInbox = Utils.getValidUri(json.optString(SettingsColumns.MOVE_TO_INBOX));
     }
 
     /**
@@ -232,6 +243,8 @@
             json.put(SettingsColumns.SETUP_INTENT_URI, setupIntentUri);
             json.put(SettingsColumns.CONVERSATION_VIEW_MODE, conversationViewMode);
             json.put(SettingsColumns.VEILED_ADDRESS_PATTERN, veiledAddressPattern);
+            json.put(SettingsColumns.MOVE_TO_INBOX,
+                    getNonNull(moveToInbox, sDefault.moveToInbox));
         } catch (JSONException e) {
             LogUtils.wtf(LOG_TAG, e, "Could not serialize settings");
         }
@@ -298,6 +311,7 @@
         dest.writeString(((Uri) getNonNull(setupIntentUri, sDefault.setupIntentUri)).toString());
         dest.writeInt(conversationViewMode);
         dest.writeString(veiledAddressPattern);
+        dest.writeString(((Uri) getNonNull(moveToInbox, sDefault.moveToInbox)).toString());
     }
 
     /**
@@ -403,7 +417,8 @@
                 && priorityArrowsEnabled == that.priorityArrowsEnabled
                 && setupIntentUri == that.setupIntentUri
                 && conversationViewMode == that.conversationViewMode
-                && TextUtils.equals(veiledAddressPattern, that.veiledAddressPattern));
+                && TextUtils.equals(veiledAddressPattern, that.veiledAddressPattern))
+                && Objects.equal(moveToInbox, that.moveToInbox);
     }
 
     @Override
@@ -423,6 +438,6 @@
                         snapHeaders, replyBehavior, convListIcon, confirmDelete, confirmArchive,
                         confirmSend, defaultInbox, forceReplyFromDefault, maxAttachmentSize, swipe,
                         priorityArrowsEnabled, setupIntentUri, conversationViewMode,
-                        veiledAddressPattern);
+                        veiledAddressPattern, moveToInbox);
     }
 }
diff --git a/src/com/android/mail/providers/UIProvider.java b/src/com/android/mail/providers/UIProvider.java
index 34a1355..7fd379d 100644
--- a/src/com/android/mail/providers/UIProvider.java
+++ b/src/com/android/mail/providers/UIProvider.java
@@ -170,6 +170,7 @@
             .put(AccountColumns.SettingsColumns.VEILED_ADDRESS_PATTERN, String.class)
             .put(AccountColumns.UPDATE_SETTINGS_URI, String.class)
             .put(AccountColumns.ENABLE_MESSAGE_TRANSFORMS, Integer.class)
+            .put(AccountColumns.SettingsColumns.MOVE_TO_INBOX, String.class)
             .build();
 
     public static final Map<String, Class<?>> ACCOUNTS_COLUMNS =
@@ -557,6 +558,11 @@
              * constants from  {@link ConversationViewMode}
              */
             public static final String CONVERSATION_VIEW_MODE = "conversation_view_mode";
+            /**
+             * String containing the URI for the inbox conversations should be moved to for this
+             * account.
+             */
+            public static final String MOVE_TO_INBOX = "move_to_inbox";
         }
     }
 
@@ -676,9 +682,9 @@
         public static final int STARRED = 1 << 7;
         /** Any other system label that we do not have a specific name for. */
         public static final int OTHER_PROVIDER_FOLDER = 1 << 8;
-        /** All mail folder **/
+        /** All mail folder */
         public static final int ALL_MAIL = 1 << 9;
-        /** Gmail's inbox sections **/
+        /** Gmail's inbox sections */
         public static final int INBOX_SECTION = 1 << 10;
     }
 
@@ -753,6 +759,12 @@
          * {@link com.android.mail.ui.MultiFoldersSelectionDialog}).
          */
         public static final int MULTI_MOVE = 0x8000;
+
+        /**
+         * This flag indicates that a conversation may be moved from this folder into the account's
+         * inbox.
+         */
+        public static final int ALLOWS_MOVE_TO_INBOX = 0x10000;
     }
 
     public static final class FolderColumns {
@@ -1945,6 +1957,11 @@
      */
     public static final String FORCE_UI_NOTIFICATIONS_QUERY_PARAMETER = "forceUiNotifications";
 
+    /**
+     * Parameter used to allow returning hidden folders.
+     */
+    public static final String ALLOW_HIDDEN_FOLDERS_QUERY_PARAM = "allowHiddenFolders";
+
     public static final String AUTO_ADVANCE_MODE_OLDER = "older";
     public static final String AUTO_ADVANCE_MODE_NEWER = "newer";
     public static final String AUTO_ADVANCE_MODE_LIST = "list";
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 0dae8c0..407ecfe 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -1401,6 +1401,25 @@
                     dialog.show();
                 }
                 break;
+            case R.id.move_to_inbox:
+                new AsyncTask<Void, Void, Folder>() {
+                    @Override
+                    protected Folder doInBackground(final Void... params) {
+                        // Get the "move to" inbox
+                        return Utils.getFolder(mContext, mAccount.settings.moveToInbox,
+                                true /* allowHidden */);
+                    }
+
+                    @Override
+                    protected void onPostExecute(final Folder moveToInbox) {
+                        final List<FolderOperation> ops = Lists.newArrayListWithCapacity(1);
+                        // Add inbox
+                        ops.add(new FolderOperation(moveToInbox, true));
+                        assignFolder(ops, Conversation.listOf(mCurrentConversation), true,
+                                true /* showUndo */, false /* isMoveTo */);
+                    }
+                }.execute((Void[]) null);
+                break;
             case R.id.empty_trash:
                 showEmptyDialog();
                 break;
diff --git a/src/com/android/mail/ui/MailActionBarView.java b/src/com/android/mail/ui/MailActionBarView.java
index d7bf719..c967530 100644
--- a/src/com/android/mail/ui/MailActionBarView.java
+++ b/src/com/android/mail/ui/MailActionBarView.java
@@ -894,6 +894,9 @@
                 && !mFolder.isProviderFolder());
         Utils.setMenuItemVisibility(menu, R.id.move_to, mFolder != null
                 && mFolder.supportsCapability(FolderCapabilities.ALLOWS_REMOVE_CONVERSATION));
+        Utils.setMenuItemVisibility(menu, R.id.move_to_inbox, mFolder != null
+                && mFolder.supportsCapability(FolderCapabilities.ALLOWS_MOVE_TO_INBOX));
+
         final MenuItem removeFolder = menu.findItem(R.id.remove_folder);
         if (mFolder != null && removeFolder != null) {
             removeFolder.setTitle(mActivity.getApplicationContext().getString(
diff --git a/src/com/android/mail/utils/Utils.java b/src/com/android/mail/utils/Utils.java
index 2327e1f..5516c55 100644
--- a/src/com/android/mail/utils/Utils.java
+++ b/src/com/android/mail/utils/Utils.java
@@ -1287,4 +1287,38 @@
         return uri.buildUpon().appendQueryParameter(APP_VERSION_QUERY_PARAMETER,
                 Integer.toString(appVersion)).build();
     }
+
+    /**
+     * Gets the specified {@link Folder} object.
+     *
+     * @param folderUri The {@link Uri} for the folder
+     * @param allowHidden <code>true</code> to allow a hidden folder to be returned,
+     *        <code>false</code> to return <code>null</code> instead
+     * @return the specified {@link Folder} object, or <code>null</code>
+     */
+    public static Folder getFolder(final Context context, final Uri folderUri,
+            final boolean allowHidden) {
+        final Uri uri = folderUri
+                .buildUpon()
+                .appendQueryParameter(UIProvider.ALLOW_HIDDEN_FOLDERS_QUERY_PARAM,
+                        Boolean.toString(allowHidden))
+                .build();
+
+        final Cursor cursor = context.getContentResolver().query(uri,
+                UIProvider.FOLDERS_PROJECTION, null, null, null);
+
+        if (cursor == null) {
+            return null;
+        }
+
+        try {
+            if (cursor.moveToFirst()) {
+                return new Folder(cursor);
+            } else {
+                return null;
+            }
+        } finally {
+            cursor.close();
+        }
+    }
 }