Do not clear selection for non-destructive actions

Change-Id: Ie38119b1ceede61d810c354deba3348126d406f7
diff --git a/src/com/android/mail/browse/SelectedConversationsActionMenu.java b/src/com/android/mail/browse/SelectedConversationsActionMenu.java
index 1c6f42a..17e4700 100644
--- a/src/com/android/mail/browse/SelectedConversationsActionMenu.java
+++ b/src/com/android/mail/browse/SelectedConversationsActionMenu.java
@@ -100,6 +100,8 @@
 
     private Folder mFolder;
 
+    // These listeners are called at the end of the animation and they perform their actions on
+    // the conversations.
     private final ActionCompleteListener mDeleteListener =
             new DestructiveActionListener(R.id.delete);
     private final ActionCompleteListener mArchiveListener =
@@ -107,6 +109,10 @@
     private final ActionCompleteListener mMuteListener = new DestructiveActionListener(R.id.mute);
     private final ActionCompleteListener mSpamListener =
             new DestructiveActionListener(R.id.report_spam);
+    private final ActionCompleteListener mRemoveStarListener =
+            new DestructiveActionListener(R.id.remove_star);
+    private final ActionCompleteListener mRemoveImportanceListener =
+            new DestructiveActionListener(R.id.mark_not_important);
 
     private SwipeableListView mListView;
 
@@ -114,15 +120,16 @@
             ConversationSelectionSet selectionSet, AnimatedAdapter adapter,
             ActionCompleteListener listener, UndoListener undoListener, Account account,
             Folder folder, SwipeableListView list) {
-        mSelectionSet = selectionSet;
         mActivity = activity;
-        mContext = mActivity.getActivityContext();
+        mSelectionSet = selectionSet;
         mListAdapter = adapter;
         mActionCompleteListener = listener;
         mUndoListener = undoListener;
         mAccount = account;
         mFolder = folder;
         mListView = list;
+
+        mContext = mActivity.getActivityContext();
     }
 
     @Override
@@ -152,7 +159,13 @@
                 starConversations(true);
                 break;
             case R.id.remove_star:
-                starConversations(false);
+                if (mFolder.type == UIProvider.FolderType.STARRED) {
+                    LogUtils.d(LOG_TAG, "We are in a starred folder, removing the star");
+                    performDestructiveAction(R.id.remove_star, mRemoveStarListener);
+                } else {
+                    LogUtils.d(LOG_TAG, "Not in a starred folder.");
+                    starConversations(false);
+                }
                 break;
             case R.id.change_folder:
                 showChangeFoldersDialog();
@@ -161,7 +174,11 @@
                 markConversationsImportant(true);
                 break;
             case R.id.mark_not_important:
-                markConversationsImportant(false);
+                if (mFolder.supportsCapability(UIProvider.FolderCapabilities.ONLY_IMPORTANT)) {
+                    performDestructiveAction(R.id.mark_not_important, mRemoveImportanceListener);
+                } else {
+                    markConversationsImportant(false);
+                }
                 break;
             default:
                 handled = false;
@@ -179,6 +196,20 @@
         mListAdapter.notifyDataSetChanged();
     }
 
+    /**
+     * Update the underlying list adapter and redraw the menus if necessary.
+     */
+    private void updateSelection() {
+        mListAdapter.notifyDataSetChanged();
+        if (mActionMode != null) {
+            // Calling mActivity.invalidateOptionsMenu doesn't have the correct behavior, since
+            // the action mode is not refreshed when activity's options menu is invalidated.
+            // Since we need to refresh our own menu, it is easy to call onPrepareActionMode
+            // directly.
+            onPrepareActionMode(mActionMode, mActionMode.getMenu());
+        }
+    }
+
     private void performDestructiveAction(final int id, final ActionCompleteListener listener) {
         Settings settings = mActivity.getSettings();
         final Collection<Conversation> conversations = mSelectionSet.values();
@@ -217,26 +248,30 @@
     }
 
     private void markConversationsRead(boolean read) {
-        Collection<Conversation> conversations = mSelectionSet.values();
+        final Collection<Conversation> conversations = mSelectionSet.values();
         Conversation.updateBoolean(mContext, conversations, ConversationColumns.READ, read);
-        clearSelection();
+        updateSelection();
     }
 
     private void markConversationsImportant(boolean important) {
-        Collection<Conversation> conversations = mSelectionSet.values();
-        int priority = important ? UIProvider.ConversationPriority.HIGH
+        final Collection<Conversation> conversations = mSelectionSet.values();
+        final int priority = important ? UIProvider.ConversationPriority.HIGH
                 : UIProvider.ConversationPriority.LOW;
         Conversation.updateInt(mContext, conversations, ConversationColumns.PRIORITY, priority);
-        clearSelection();
+        updateSelection();
     }
 
+    /**
+     * Mark the selected conversations with the star setting provided here.
+     * @param star true if you want all the conversations to have stars, false if you want to remove
+     * stars from all conversations
+     */
     private void starConversations(boolean star) {
-        Collection<Conversation> conversations = mSelectionSet.values();
+        final Collection<Conversation> conversations = mSelectionSet.values();
         if (conversations.size() > 0) {
-            Conversation.updateBoolean(mContext, conversations,
-                    ConversationColumns.STARRED, star);
+            Conversation.updateBoolean(mContext, conversations, ConversationColumns.STARRED, star);
         }
-        clearSelection();
+        updateSelection();
     }
 
     private void showChangeFoldersDialog() {
@@ -318,7 +353,7 @@
     public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
         // Determine read/ unread
         // Star/ unstar
-        Collection<Conversation> conversations = mSelectionSet.values();
+        final Collection<Conversation> conversations = mSelectionSet.values();
         boolean showStar = false;
         boolean showMarkUnread = false;
         boolean showMarkImportant = false;
@@ -363,12 +398,6 @@
         return true;
     }
 
-    public void onPrepareActionMode() {
-        if (mActionMode != null) {
-            onPrepareActionMode(mActionMode, mActionMode.getMenu());
-        }
-    }
-
     @Override
     public void onDestroyActionMode(ActionMode mode) {
         mActionMode = null;
@@ -486,7 +515,7 @@
         @Override
         public void onActionComplete() {
             // This is where we actually delete.
-            Collection<Conversation> conversations = mSelectionSet.values();
+            final Collection<Conversation> conversations = mSelectionSet.values();
             mActionCompleteListener.onActionComplete();
             mUndoListener.onUndoAvailable(new UndoOperation(conversations.size(), mAction));
             switch (mAction) {
@@ -508,6 +537,17 @@
                 case R.id.report_spam:
                     Conversation.reportSpam(mContext, conversations);
                     break;
+                case R.id.remove_star:
+                    // Star removal is destructive in the Starred folder.
+                    Conversation.updateBoolean(mContext, conversations, ConversationColumns.STARRED,
+                            false);
+                    break;
+                case R.id.mark_not_important:
+                    // Marking not important is destructive in a mailbox containing only important
+                    // messages
+                    Conversation.updateInt(mContext, conversations, ConversationColumns.PRIORITY,
+                            UIProvider.ConversationPriority.LOW);
+                    break;
             }
             clearSelection();
         }
diff --git a/src/com/android/mail/providers/UIProvider.java b/src/com/android/mail/providers/UIProvider.java
index 5f29e03..2318e77 100644
--- a/src/com/android/mail/providers/UIProvider.java
+++ b/src/com/android/mail/providers/UIProvider.java
@@ -522,6 +522,7 @@
         public static final int SENT = 4;
         public static final int TRASH = 5;
         public static final int SPAM = 6;
+        public static final int STARRED = 7;
     }
 
     public static final class FolderCapabilities {
@@ -551,6 +552,10 @@
          * Indicates that a folder supports settings (sync lookback, etc.)
          */
         public static final int SUPPORTS_SETTINGS = 0x0080;
+        /**
+         * All the messages in this folder are important.
+         */
+        public static final int ONLY_IMPORTANT = 0x0100;
     }
 
     public static final class FolderColumns {
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 63ee61e..4b5304d 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -1319,6 +1319,11 @@
     @Override
     public void onRefreshReady() {
         ArrayList<Integer> deletedRows = mConversationListCursor.getRefreshDeletions();
+        // If we have any deletions from the server, and the conversations are in the list view,
+        // remove them from a selected set, if any
+        if (!deletedRows.isEmpty() && !mSelectedSet.isEmpty()) {
+            mSelectedSet.delete(deletedRows);
+        }
         // If we have any deletions from the server, animate them away
         if (!deletedRows.isEmpty() && mConversationListFragment != null) {
             AnimatedAdapter adapter = mConversationListFragment.getAnimatedAdapter();
diff --git a/src/com/android/mail/ui/AnimatedAdapter.java b/src/com/android/mail/ui/AnimatedAdapter.java
index c61f2ae..1943af2 100644
--- a/src/com/android/mail/ui/AnimatedAdapter.java
+++ b/src/com/android/mail/ui/AnimatedAdapter.java
@@ -24,7 +24,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
-import android.widget.ListView;
 import android.widget.SimpleCursorAdapter;
 
 import com.android.mail.browse.ConversationCursor;
@@ -154,8 +153,7 @@
      * @param conversations
      * @param listener
      */
-    public void delete(Collection<Conversation> conversations,
-            ActionCompleteListener listener) {
+    public void delete(Collection<Conversation> conversations, ActionCompleteListener listener) {
         // Animate out the positions.
         // Call when all the animations are complete.
         final ArrayList<Integer> positions = new ArrayList<Integer>();
diff --git a/src/com/android/mail/ui/ConversationSelectionSet.java b/src/com/android/mail/ui/ConversationSelectionSet.java
index 9f26fe3..45ec7b5 100644
--- a/src/com/android/mail/ui/ConversationSelectionSet.java
+++ b/src/com/android/mail/ui/ConversationSelectionSet.java
@@ -247,4 +247,13 @@
     public Collection<ConversationItemView> views() {
         return mInternalViewMap.values();
     }
+
+    /**
+     * @param deletedRows an arraylist of conversation IDs which have been deleted.
+     */
+    public void delete(ArrayList<Integer> deletedRows) {
+        for (long id : deletedRows) {
+            remove(id);
+        }
+    }
 }