am b4cb510b: Show a dialog to discover the removal setting

* commit 'b4cb510b1cef97580b0f29562aa7edc25257322b':
  Show a dialog to discover the removal setting
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 86e05e9..247a875 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -860,6 +860,8 @@
     <string name="prefDialogTitle_removal_action">Archive &amp; delete actions</string>
     <!-- The default value -->
     <string translatable="false" name="prefDefault_removal_action">archive</string>
+    <!-- Dialog title for the choosing whether to use archive or delete as remove action, displayed the first time the user archives or deletes a message [CHAR LIMIT=150] -->
+    <string name="prefDialogTitle_removal_action_first_time">Set archive &amp; delete preference\n(change in General settings)</string>
 
     <!--  Settings screen, Reply to all default setting title  [CHAR LIMIT=30] -->
     <string name="preferences_default_reply_all_title">Reply all</string>
diff --git a/src/com/android/mail/browse/SelectedConversationsActionMenu.java b/src/com/android/mail/browse/SelectedConversationsActionMenu.java
index 350088a..18bf7aa 100644
--- a/src/com/android/mail/browse/SelectedConversationsActionMenu.java
+++ b/src/com/android/mail/browse/SelectedConversationsActionMenu.java
@@ -276,7 +276,7 @@
     private void destroy(int actionId, final Collection<Conversation> target,
             final DestructiveAction action) {
         LogUtils.i(LOG_TAG, "About to remove %d converations", target.size());
-        mUpdater.delete(actionId, target, action, true);
+        mUpdater.delete(actionId, target, action, true, true /* allowDialog */);
     }
 
     /**
diff --git a/src/com/android/mail/preferences/MailPrefs.java b/src/com/android/mail/preferences/MailPrefs.java
index 2b600ae..c605fb5 100644
--- a/src/com/android/mail/preferences/MailPrefs.java
+++ b/src/com/android/mail/preferences/MailPrefs.java
@@ -57,11 +57,12 @@
          */
         public static final String CONVERSATION_LIST_SWIPE = "conversation-list-swipe";
 
-        /**
-         * A string indicating the user's removal action preference.
-         */
+        /** A string indicating the user's removal action preference. */
         public static final String REMOVAL_ACTION = "removal-action";
 
+        /** A boolean indicating that the user has seen the removal action dialog. */
+        public static final String REMOVAL_ACTION_DIALOG_SHOWN = "removal-action-dialog-shown";
+
         /** Hidden preference used to cache the active notification set */
         private static final String CACHED_ACTIVE_NOTIFICATION_SET =
                 "cache-active-notification-set";
@@ -74,6 +75,7 @@
                 .add(DEFAULT_REPLY_ALL)
                 .add(CONVERSATION_LIST_SWIPE)
                 .add(REMOVAL_ACTION)
+                .add(REMOVAL_ACTION_DIALOG_SHOWN)
                 .build();
 
     }
@@ -253,4 +255,17 @@
     public void resetConversationPhotoTeaserAlreadyShown() {
         getEditor().putBoolean(PreferenceKeys.CONVERSATION_PHOTO_TEASER_SHOWN, false).apply();
     }
+
+    /**
+     * @return <code>true</code> if the removal action dialog has been shown to the user,
+     * <code>false</code> otherwise
+     */
+    public boolean hasRemovalActionDialogShown() {
+        return getSharedPreferences().getBoolean(PreferenceKeys.REMOVAL_ACTION_DIALOG_SHOWN, false);
+    }
+
+    public void setRemovalActionDialogShown() {
+        getEditor().putBoolean(PreferenceKeys.REMOVAL_ACTION_DIALOG_SHOWN, true).apply();
+        MailIntentService.broadcastBackupDataChanged(getContext());
+    }
 }
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 8d9e5d5..c1c8808 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -91,6 +91,7 @@
 import com.android.mail.providers.UIProvider.ConversationOperations;
 import com.android.mail.providers.UIProvider.FolderCapabilities;
 import com.android.mail.ui.ActionableToastBar.ActionClickedListener;
+import com.android.mail.ui.RemovalActionPreferenceDialogFragment.RemovalActionPreferenceDialogListener;
 import com.android.mail.utils.ContentProviderTask;
 import com.android.mail.utils.LogTag;
 import com.android.mail.utils.LogUtils;
@@ -1315,7 +1316,8 @@
             }
             case R.id.remove_folder:
                 delete(R.id.remove_folder, target,
-                        getDeferredRemoveFolder(target, mFolder, true, isBatch, true), isBatch);
+                        getDeferredRemoveFolder(target, mFolder, true, isBatch, true), isBatch,
+                        true /* allowDialog */);
                 break;
             case R.id.delete: {
                 final boolean showDialog = (settings != null && settings.confirmDelete);
@@ -1335,29 +1337,34 @@
             case R.id.mark_not_important:
                 if (mFolder != null && mFolder.isImportantOnly()) {
                     delete(R.id.mark_not_important, target,
-                            getDeferredAction(R.id.mark_not_important, target, isBatch), isBatch);
+                            getDeferredAction(R.id.mark_not_important, target, isBatch), isBatch,
+                            true /* allowDialog */);
                 } else {
                     updateConversation(Conversation.listOf(mCurrentConversation),
                             ConversationColumns.PRIORITY, UIProvider.ConversationPriority.LOW);
                 }
                 break;
             case R.id.mute:
-                delete(R.id.mute, target, getDeferredAction(R.id.mute, target, isBatch), isBatch);
+                delete(R.id.mute, target, getDeferredAction(R.id.mute, target, isBatch), isBatch,
+                        true /* allowDialog */);
                 break;
             case R.id.report_spam:
                 delete(R.id.report_spam, target,
-                        getDeferredAction(R.id.report_spam, target, isBatch), isBatch);
+                        getDeferredAction(R.id.report_spam, target, isBatch), isBatch,
+                        true /* allowDialog */);
                 break;
             case R.id.mark_not_spam:
                 // Currently, since spam messages are only shown in list with
                 // other spam messages,
                 // marking a message not as spam is a destructive action
                 delete(R.id.mark_not_spam, target,
-                        getDeferredAction(R.id.mark_not_spam, target, isBatch), isBatch);
+                        getDeferredAction(R.id.mark_not_spam, target, isBatch), isBatch,
+                        true /* allowDialog */);
                 break;
             case R.id.report_phishing:
                 delete(R.id.report_phishing, target,
-                        getDeferredAction(R.id.report_phishing, target, isBatch), isBatch);
+                        getDeferredAction(R.id.report_phishing, target, isBatch), isBatch,
+                        true /* allowDialog */);
                 break;
             case android.R.id.home:
                 onUpPressed();
@@ -1570,7 +1577,8 @@
             // Conversations are neither marked read, nor viewed, and we don't want to show
             // the next conversation.
             LogUtils.d(LOG_TAG, ". . doing full mark unread");
-            markConversationsRead(Collections.singletonList(conv), false, false, false);
+            markConversationsRead(Collections.singletonList(conv), false, false, false,
+                    true /* allowDialog */);
         } else {
             if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) {
                 final ConversationInfo info = ConversationInfo.fromBlob(originalConversationInfo);
@@ -1625,28 +1633,28 @@
             mConversationListLoadFinishedCallbacks.add(new LoadFinishedCallback() {
                 @Override
                 public void onLoadFinished() {
-                    markConversationsRead(targets, read, viewed, true);
+                    markConversationsRead(targets, read, viewed, true, true /* allowDialog */);
                 }
             });
         } else {
             // We want to show the next conversation if we are marking unread.
-            markConversationsRead(targets, read, viewed, true);
+            markConversationsRead(targets, read, viewed, true, true /* allowDialog */);
         }
     }
 
     private void markConversationsRead(final Collection<Conversation> targets, final boolean read,
-            final boolean markViewed, final boolean showNext) {
+            final boolean markViewed, final boolean showNext, final boolean allowDialog) {
         LogUtils.d(LOG_TAG, "performing markConversationsRead");
         // Auto-advance if requested and the current conversation is being marked unread
         if (showNext && !read) {
             final Runnable operation = new Runnable() {
                 @Override
                 public void run() {
-                    markConversationsRead(targets, read, markViewed, showNext);
+                    markConversationsRead(targets, read, markViewed, showNext, false);
                 }
             };
 
-            if (!showNextConversation(targets, operation)) {
+            if (!showNextConversation(targets, operation, allowDialog)) {
                 // This method will be called again if the user selects an autoadvance option
                 return;
             }
@@ -1696,7 +1704,7 @@
      */
     @Override
     public void showNextConversation(final Collection<Conversation> target) {
-        showNextConversation(target, null);
+        showNextConversation(target, null, true /* allowDialog */);
     }
 
     /**
@@ -1722,7 +1730,7 @@
      * <code>true</code> otherwise.
      */
     private boolean showNextConversation(final Collection<Conversation> target,
-            final Runnable operation) {
+            final Runnable operation, final boolean allowDialog) {
         final int viewMode = mViewMode.getMode();
         final boolean currentConversationInView = (viewMode == ViewMode.CONVERSATION
                 || viewMode == ViewMode.SEARCH_RESULTS_CONVERSATION)
@@ -1731,9 +1739,11 @@
         if (currentConversationInView) {
             final int autoAdvanceSetting = mAccount.settings.getAutoAdvanceSetting();
 
-            if (autoAdvanceSetting == AutoAdvance.UNSET && mIsTablet) {
+            if (allowDialog && autoAdvanceSetting == AutoAdvance.UNSET && mIsTablet) {
                 displayAutoAdvanceDialogAndPerformAction(operation);
                 return false;
+            } else if (allowDialog && displayRemovalActionDialogAndPerformAction(operation)) {
+                return false;
             } else {
                 // If we don't have one set, but we're here, just take the default
                 final int autoAdvance = (autoAdvanceSetting == AutoAdvance.UNSET) ?
@@ -1747,6 +1757,8 @@
                 showConversation(next);
                 return (mAutoAdvanceOp == null);
             }
+        } else if (allowDialog && displayRemovalActionDialogAndPerformAction(operation)) {
+            return false;
         }
 
         return true;
@@ -1804,6 +1816,46 @@
                 .show();
     }
 
+    private Runnable mRemovalActionDialogRunnable = null;
+
+    private void attachRemovalActionDialogListener() {
+        final RemovalActionPreferenceDialogFragment fragment =
+                (RemovalActionPreferenceDialogFragment) mActivity.getFragmentManager()
+                .findFragmentByTag(RemovalActionPreferenceDialogFragment.FRAGMENT_TAG);
+
+        if (fragment != null) {
+            fragment.setListener(mRemovalActionPreferenceDialogListener);
+        }
+    }
+
+    private final RemovalActionPreferenceDialogListener mRemovalActionPreferenceDialogListener =
+            new RemovalActionPreferenceDialogListener() {
+        @Override
+        public void onDismiss() {
+            if (mRemovalActionDialogRunnable != null) {
+                mRemovalActionDialogRunnable.run();
+                mRemovalActionDialogRunnable = null;
+            }
+        }
+    };
+
+    /**
+     * Displays a the removal action dialog, and when the user makes a selection, the preference is
+     * stored, and the specified operation is run.
+     *
+     * @return <code>true</code> if the dialog was shown, <code>false</code> otherwise
+     */
+    private boolean displayRemovalActionDialogAndPerformAction(final Runnable operation) {
+        final boolean shown =  RemovalActionPreferenceDialogFragment.showIfNecessary(mContext,
+                mAccount, mActivity.getFragmentManager(), mRemovalActionPreferenceDialogListener);
+
+        if (shown) {
+            mRemovalActionDialogRunnable = operation;
+        }
+
+        return shown;
+    }
+
     @Override
     public void starMessage(ConversationMessage msg, boolean starred) {
         if (msg.starred == starred) {
@@ -1873,13 +1925,14 @@
             final ConfirmDialogFragment c = ConfirmDialogFragment.newInstance(message);
             c.displayDialog(mActivity.getFragmentManager());
         } else {
-            delete(0, target, getDeferredAction(actionId, target, isBatch), isBatch);
+            delete(0, target, getDeferredAction(actionId, target, isBatch), isBatch,
+                    true /* allowDialog */);
         }
     }
 
     @Override
     public void delete(final int actionId, final Collection<Conversation> target,
-                       final DestructiveAction action, final boolean isBatch) {
+            final DestructiveAction action, final boolean isBatch, final boolean allowDialog) {
         // Order of events is critical! The Conversation View Fragment must be
         // notified of the next conversation with showConversation(next) *before* the
         // conversation list
@@ -1890,11 +1943,11 @@
         final Runnable operation = new Runnable() {
             @Override
             public void run() {
-                delete(actionId, target, action, isBatch);
+                delete(actionId, target, action, isBatch, false);
             }
         };
 
-        if (!showNextConversation(target, operation)) {
+        if (!showNextConversation(target, operation, allowDialog)) {
             // This method will be called again if the user selects an autoadvance option
             return;
         }
@@ -1956,6 +2009,7 @@
         mSafeToModifyFragments = true;
 
         attachEmptyFolderDialogFragmentListener();
+        attachRemovalActionDialogListener();
 
         // Invalidating the options menu so that when we make changes in settings,
         // the changes will always be updated in the action bar/options menu/
@@ -2834,7 +2888,7 @@
 
             folderChange = getDeferredFolderChange(target, folderOps, isDestructive,
                     batch, showUndo, isMoveTo, actionFolder);
-            delete(0, target, folderChange, batch);
+            delete(0, target, folderChange, batch, true /* allowDialog */);
         } else {
             folderChange = getFolderChange(target, folderOps, isDestructive,
                     batch, showUndo, false /* isMoveTo */, mFolder);
@@ -3113,7 +3167,7 @@
                 getFolderChange(conversations, dragDropOperations, isDestructive,
                         true /* isBatch */, true /* showUndo */, true /* isMoveTo */, folder);
         if (isDestructive) {
-            delete(0, conversations, action, true);
+            delete(0, conversations, action, true, true /* allowDialog */);
         } else {
             action.performAction();
         }
@@ -3971,7 +4025,7 @@
         mDialogListener = new AlertDialog.OnClickListener() {
             @Override
             public void onClick(DialogInterface dialog, int which) {
-                delete(action, target, destructiveAction, isBatch);
+                delete(action, target, destructiveAction, isBatch, true /* allowDialog */);
                 // Afterwards, let's remove references to the listener and the action.
                 setListener(null, -1);
             }
diff --git a/src/com/android/mail/ui/ConversationUpdater.java b/src/com/android/mail/ui/ConversationUpdater.java
index c3b71af..cb6bad6 100644
--- a/src/com/android/mail/ui/ConversationUpdater.java
+++ b/src/com/android/mail/ui/ConversationUpdater.java
@@ -82,10 +82,11 @@
      * @param target the conversations to act upon.
      * @param action to perform after the UI has been updated to remove the conversations
      * @param isBatch true if this is a batch action, false otherwise.
+     * @param allowDialog <code>true</code> to allow dialogs to be displayed
      */
     void delete(
             int actionId, final Collection<Conversation> target, final DestructiveAction action,
-            boolean isBatch);
+            boolean isBatch, boolean allowDialog);
 
     /**
      * Mark a number of conversations as read or unread.
diff --git a/src/com/android/mail/ui/RemovalActionPreferenceDialogFragment.java b/src/com/android/mail/ui/RemovalActionPreferenceDialogFragment.java
new file mode 100644
index 0000000..c39b5df
--- /dev/null
+++ b/src/com/android/mail/ui/RemovalActionPreferenceDialogFragment.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2013 Google Inc.
+ * Licensed to The Android Open Source Project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mail.ui;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.Bundle;
+
+import com.android.mail.R;
+import com.android.mail.preferences.MailPrefs;
+import com.android.mail.providers.Account;
+import com.android.mail.providers.UIProvider.AccountCapabilities;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * This dialog is shown when a user first archives or deletes a message, and asks them what there
+ * preferred action is (archive, delete, or both).
+ */
+public class RemovalActionPreferenceDialogFragment extends DialogFragment {
+    public interface RemovalActionPreferenceDialogListener {
+        void onDismiss();
+    }
+
+    public static final String FRAGMENT_TAG = "ArchiveDeletePreferenceDialogFragment";
+
+    private static final String ARG_DEFAULT_VALUE = "defaultValue";
+
+    private String mDefaultValue;
+
+    private WeakReference<RemovalActionPreferenceDialogListener> mListener = null;
+
+    /**
+     * Create a new {@link ArchiveDeletePreferenceDialogFragment}.
+     *
+     * @param defaultValue the initial value to show as checked
+     */
+    public static RemovalActionPreferenceDialogFragment newInstance(final String defaultValue) {
+        final RemovalActionPreferenceDialogFragment fragment =
+                new RemovalActionPreferenceDialogFragment();
+
+        final Bundle args = new Bundle(1);
+        args.putString(ARG_DEFAULT_VALUE, defaultValue);
+        fragment.setArguments(args);
+
+        return fragment;
+    }
+
+    public void setListener(final RemovalActionPreferenceDialogListener listener) {
+        mListener = new WeakReference<RemovalActionPreferenceDialogListener>(listener);
+    }
+
+    @Override
+    public Dialog onCreateDialog(final Bundle savedInstanceState) {
+        final String[] entries = getResources().getStringArray(R.array.prefEntries_removal_action);
+        final String[] entryValues =
+                getResources().getStringArray(R.array.prefValues_removal_action);
+
+        final String defaultValue = getArguments().getString(ARG_DEFAULT_VALUE);
+
+        // Find the default value in the entryValues array
+        // If we can't find it, we end up on index 0, which is "archive"
+        int defaultItem;
+        for (defaultItem = entryValues.length - 1; defaultItem >= 0; defaultItem--) {
+            if (entryValues[defaultItem].equals(defaultValue)) {
+                break;
+            }
+        }
+
+        mDefaultValue = entryValues[defaultItem];
+
+        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
+                .setTitle(R.string.prefDialogTitle_removal_action_first_time)
+                .setSingleChoiceItems(entries, defaultItem, new OnClickListener() {
+                    @Override
+                    public void onClick(final DialogInterface dialog, final int which) {
+                        mDefaultValue = entryValues[which];
+                        dismiss();
+                    }
+                });
+
+        return builder.create();
+    }
+
+    @Override
+    public void onDismiss(final DialogInterface dialog) {
+        super.onDismiss(dialog);
+
+        // Use whatever was originally selected
+        saveRemovalAction(mDefaultValue);
+    }
+
+    /**
+     * Shows the dialog, if necessary.
+     *
+     * @param account The account this is being requested for
+     * @param mRemovalActionPreferenceDialogListener
+     * @param defaultValue The default removal action to show checked
+     * @return <code>true</code> if the dialog was shown, <code>false</code> otherwise
+     */
+    public static boolean showIfNecessary(final Context context, final Account account,
+            final FragmentManager fragmentManager,
+            final RemovalActionPreferenceDialogListener removalActionPreferenceDialogListener) {
+        final boolean supportsArchive = account.supportsCapability(AccountCapabilities.ARCHIVE);
+
+        if (shouldDisplayDialog(context, account, supportsArchive)) {
+            final String defaultValue = MailPrefs.get(context).getRemovalAction(supportsArchive);
+
+            final RemovalActionPreferenceDialogFragment fragment = newInstance(defaultValue);
+            fragment.setListener(removalActionPreferenceDialogListener);
+            fragment.show(fragmentManager, FRAGMENT_TAG);
+
+            return true;
+        }
+
+         return false;
+    }
+
+    /**
+     * Checks whether we should show the dialog. We show it if:
+     * <ol>
+     * <li>Archive is supported by the account</li>
+     * <li>We have not previously shown the dialog</li>
+     * </ol>
+     *
+     * @param account The account this is being requested for
+     * @param supportsArchive <code>true</code> if the current account supports
+     *            archive, <code>false</code> otherwise
+     * @return <code>true</code> if the dialog needs to be displayed (because it
+     *         hasn't been shown yet), <code>false</code> otherwise
+     */
+    private static boolean shouldDisplayDialog(final Context context, final Account account,
+            final boolean supportsArchive) {
+        return supportsArchive && !MailPrefs.get(context).hasRemovalActionDialogShown();
+    }
+
+    private void saveRemovalAction(final String removalAction) {
+        final MailPrefs mailPrefs = MailPrefs.get(getActivity());
+        mailPrefs.setRemovalAction(removalAction);
+        mailPrefs.setRemovalActionDialogShown();
+
+        if (mListener != null) {
+            final RemovalActionPreferenceDialogListener listener = mListener.get();
+            if (listener != null) {
+                listener.onDismiss();
+            }
+        }
+    }
+}