Merge "Import translations. DO NOT MERGE" into jb-ub-mail
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7414b36..7fc9f0b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -601,7 +601,7 @@
         <item>Couldn\'t sign in.</item>
         <item>Security error.</item>
         <item>Couldn\'t sync.</item>
-        <item>Error</item>
+        <item>Internal Error</item>
     </string-array>
 
     <!-- Widget strings -->
diff --git a/src/com/android/mail/browse/ConversationCursor.java b/src/com/android/mail/browse/ConversationCursor.java
index cc03604..5ba886d 100644
--- a/src/com/android/mail/browse/ConversationCursor.java
+++ b/src/com/android/mail/browse/ConversationCursor.java
@@ -28,11 +28,11 @@
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.database.CursorWrapper;
-import android.database.DataSetObservable;
 import android.database.DataSetObserver;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.util.Log;
@@ -79,8 +79,6 @@
     @VisibleForTesting
     static ConversationProvider sProvider;
 
-    // The cursor instantiator's activity
-    private Activity mActivity;
     // The cursor underlying the caching cursor
     @VisibleForTesting
     Wrapper mUnderlyingCursor;
@@ -140,14 +138,13 @@
 
     public ConversationCursor(Activity activity, Uri uri, boolean initialConversationLimit,
             String name) {
-        //sActivity = activity;
         mInitialConversationLimit = initialConversationLimit;
         sResolver = activity.getContentResolver();
         sUriColumnIndex = UIProvider.CONVERSATION_URI_COLUMN;
         qUri = uri;
         mName = name;
         qProjection = UIProvider.CONVERSATION_PROJECTION;
-        mCursorObserver = new CursorObserver();
+        mCursorObserver = new CursorObserver(new Handler(Looper.getMainLooper()));
     }
 
     /**
@@ -271,9 +268,6 @@
     }
 
     private Wrapper doQuery(boolean withLimit) {
-        if (sResolver == null) {
-            sResolver = mActivity.getContentResolver();
-        }
         Uri uri = qUri;
         if (withLimit) {
             uri = uri.buildUpon().appendQueryParameter(ConversationListQueryParameters.LIMIT,
@@ -353,21 +347,21 @@
                     iter.remove();
                 }
             }
-        }
 
-        // Swap cursor
-        if (mUnderlyingCursor != null) {
-            close();
-        }
-        mUnderlyingCursor = newCursor;
+            // Swap cursor
+            if (mUnderlyingCursor != null) {
+                close();
+            }
+            mUnderlyingCursor = newCursor;
 
-        mPosition = -1;
-        mUnderlyingCursor.moveToPosition(mPosition);
-        if (!mCursorObserverRegistered) {
-            mUnderlyingCursor.registerContentObserver(mCursorObserver);
-            mCursorObserverRegistered = true;
+            mPosition = -1;
+            mUnderlyingCursor.moveToPosition(mPosition);
+            if (!mCursorObserverRegistered) {
+                mUnderlyingCursor.registerContentObserver(mCursorObserver);
+                mCursorObserverRegistered = true;
+            }
+            mRefreshRequired = false;
         }
-        mRefreshRequired = false;
     }
 
     /**
@@ -539,15 +533,15 @@
      * When the underlying cursor changes, we want to alert the listener
      */
     private void underlyingChanged() {
-        if (mCursorObserverRegistered) {
-            try {
-                mUnderlyingCursor.unregisterContentObserver(mCursorObserver);
-            } catch (IllegalStateException e) {
-                // Maybe the cursor was GC'd?
-            }
-            mCursorObserverRegistered = false;
-        }
         synchronized(mCacheMapLock) {
+            if (mCursorObserverRegistered) {
+                try {
+                    mUnderlyingCursor.unregisterContentObserver(mCursorObserver);
+                } catch (IllegalStateException e) {
+                    // Maybe the cursor was GC'd?
+                }
+                mCursorObserverRegistered = false;
+            }
             mRefreshRequired = true;
             if (!mPaused) {
                 notifyRefreshRequired();
@@ -604,8 +598,7 @@
      * Put the refreshed cursor in place (called by the UI)
      */
     public void sync() {
-        final Wrapper requeryCursor = mRequeryCursor;
-        if (requeryCursor == null) {
+        if (mRequeryCursor == null) {
             // This can happen during an animated deletion, if the UI isn't keeping track, or
             // if a new query intervened (i.e. user changed folders)
             if (DEBUG) {
@@ -613,16 +606,15 @@
             }
             return;
         }
-        if (DEBUG) {
-            LogUtils.i(TAG, "[sync() %s]", mName);
-        }
         synchronized(mCacheMapLock) {
+            if (DEBUG) {
+                LogUtils.i(TAG, "[sync() %s]", mName);
+            }
+            resetCursor(mRequeryCursor);
             mRequeryCursor = null;
             mRefreshTask = null;
             mRefreshReady = false;
         }
-        resetCursor(requeryCursor);
-
         notifyDataChanged();
     }
 
@@ -896,14 +888,14 @@
      * Observer of changes to underlying data
      */
     private class CursorObserver extends ContentObserver {
-        public CursorObserver() {
-            super(null);
+        public CursorObserver(Handler handler) {
+            super(handler);
         }
 
         @Override
         public void onChange(boolean selfChange) {
             // If we're here, then something outside of the UI has changed the data, and we
-            // must query the underlying provider for that data
+            // must query the underlying provider for that data;
             ConversationCursor.this.underlyingChanged();
         }
     }
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 6800ca2..4a7cc0d 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -1205,7 +1205,10 @@
 
     @Override
     public void dismiss() {
-        getListView().dismissChild(this);
+        SwipeableListView listView = this.getListView();
+        if (listView != null) {
+            getListView().dismissChild(this);
+        }
     }
 
     /**
@@ -1261,7 +1264,12 @@
     }
 
     private SwipeableListView getListView() {
-        return (SwipeableListView)((SwipeableConversationItemView) getParent()).getListView();
+        SwipeableListView v = (SwipeableListView) ((SwipeableConversationItemView) getParent())
+                .getListView();
+        if (v == null) {
+            v = mAdapter.getListView();
+        }
+        return v;
     }
 
     private boolean onTouchEventNoSwipe(MotionEvent event) {
diff --git a/src/com/android/mail/browse/ConversationListFooterView.java b/src/com/android/mail/browse/ConversationListFooterView.java
index b64cbed..0fb7418 100644
--- a/src/com/android/mail/browse/ConversationListFooterView.java
+++ b/src/com/android/mail/browse/ConversationListFooterView.java
@@ -17,8 +17,6 @@
 
 package com.android.mail.browse;
 
-import android.app.DialogFragment;
-import android.app.FragmentManager;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -32,22 +30,25 @@
 import com.android.mail.R;
 import com.android.mail.providers.Folder;
 import com.android.mail.providers.UIProvider;
-import com.android.mail.ui.AbstractActivityController;
-import com.android.mail.ui.AsyncRefreshTask;
 import com.android.mail.ui.ViewMode;
 import com.android.mail.utils.Utils;
 
 public class ConversationListFooterView extends LinearLayout implements View.OnClickListener {
+
+    public interface FooterViewClickListener {
+        void onFooterViewErrorActionClick(Folder folder, int errorStatus);
+        void onFooterViewLoadMoreClick(Folder folder);
+    }
+
     private View mLoading;
     private View mNetworkError;
     private View mLoadMore;
     private Button mErrorActionButton;
     private TextView mErrorText;
-    private AsyncRefreshTask mFolderSyncTask;
     private Folder mFolder;
     private Uri mLoadMoreUri;
     private int mErrorStatus;
-    private FragmentManager mFragmentManager;
+    private FooterViewClickListener mClickListener;
     private boolean mTabletDevice;
     // Backgrounds for different states.
     private static Drawable sWideBackground;
@@ -71,8 +72,8 @@
         mErrorText = (TextView)findViewById(R.id.error_text);
     }
 
-    public void setFragmentManager(FragmentManager manager) {
-        mFragmentManager = manager;
+    public void setClickListener(FooterViewClickListener listener) {
+        mClickListener = listener;
     }
 
     public void onClick(View v) {
@@ -81,47 +82,12 @@
         Uri uri = null;
         switch (id) {
             case R.id.error_action_button:
-                switch (mErrorStatus) {
-                    case UIProvider.LastSyncResult.CONNECTION_ERROR:
-                        if (f != null && f.refreshUri != null) {
-                            uri = f.refreshUri;
-                        }
-                        break;
-                    case UIProvider.LastSyncResult.AUTH_ERROR:
-                        // TODO - open sign-in page here
-                        return;
-                    case UIProvider.LastSyncResult.SECURITY_ERROR:
-                        return; // Currently we do nothing for security errors.
-                    case UIProvider.LastSyncResult.STORAGE_ERROR:
-                        DialogFragment fragment = (DialogFragment)
-                        mFragmentManager.findFragmentByTag(
-                                AbstractActivityController.SYNC_ERROR_DIALOG_FRAGMENT_TAG);
-                        if (fragment == null) {
-                            fragment = SyncErrorDialogFragment.newInstance();
-                        }
-                        fragment.show(mFragmentManager,
-                                AbstractActivityController.SYNC_ERROR_DIALOG_FRAGMENT_TAG);
-                        return;
-                    case UIProvider.LastSyncResult.INTERNAL_ERROR:
-                        // TODO - open report feedback code
-                        return;
-                    default:
-                        return;
-                }
+                mClickListener.onFooterViewErrorActionClick(f, mErrorStatus);
                 break;
             case R.id.load_more:
-                if (f != null && f.loadMoreUri != null) {
-                    uri = f.loadMoreUri;
-                }
+                mClickListener.onFooterViewLoadMoreClick(f);
                 break;
         }
-        if (uri != null) {
-            if (mFolderSyncTask != null) {
-                mFolderSyncTask.cancel(true);
-            }
-            mFolderSyncTask = new AsyncRefreshTask(getContext(), uri);
-            mFolderSyncTask.execute();
-        }
     }
 
     public void setFolder(Folder folder) {
diff --git a/src/com/android/mail/browse/SelectedConversationsActionMenu.java b/src/com/android/mail/browse/SelectedConversationsActionMenu.java
index 82b472b..39654d1 100644
--- a/src/com/android/mail/browse/SelectedConversationsActionMenu.java
+++ b/src/com/android/mail/browse/SelectedConversationsActionMenu.java
@@ -377,7 +377,7 @@
         final MenuItem archive = menu.findItem(R.id.archive);
         boolean showArchive =
                 mAccount.supportsCapability(UIProvider.AccountCapabilities.ARCHIVE)
-                && mFolder.supportsCapability(FolderCapabilities.ARCHIVE) && !mFolder.isTrash();
+                && mFolder.supportsCapability(FolderCapabilities.ARCHIVE);
         if (archive == null) {
             showArchive = false;
         } else {
@@ -413,7 +413,8 @@
         markNotImportant.setVisible(!showMarkImportant
                 && mAccount.supportsCapability(UIProvider.AccountCapabilities.MARK_IMPORTANT));
         final MenuItem trash = menu.findItem(R.id.delete);
-        trash.setVisible(!mFolder.isTrash());
+        trash.setVisible(mFolder != null
+                && mFolder.supportsCapability(UIProvider.FolderCapabilities.DELETE));
         return true;
     }
 
diff --git a/src/com/android/mail/compose/ComposeActivity.java b/src/com/android/mail/compose/ComposeActivity.java
index 9d62881..f42f997 100644
--- a/src/com/android/mail/compose/ComposeActivity.java
+++ b/src/com/android/mail/compose/ComposeActivity.java
@@ -1643,7 +1643,7 @@
                 Utils.showHelp(this, mAccount, getString(R.string.compose_help_context));
                 break;
             case R.id.feedback_menu_item:
-                Utils.sendFeedback(this, mAccount);
+                Utils.sendFeedback(this, mAccount, false);
                 break;
             default:
                 handled = false;
diff --git a/src/com/android/mail/providers/UIProvider.java b/src/com/android/mail/providers/UIProvider.java
index 8cd8256..993e46d 100644
--- a/src/com/android/mail/providers/UIProvider.java
+++ b/src/com/android/mail/providers/UIProvider.java
@@ -1700,4 +1700,11 @@
          */
         public static final String EXTRA_MANAGE_FOLDERS = "extra_manage_folders";
     }
+
+    public static final class SendFeedbackExtras {
+        /**
+         * Optional boolean extras which indicates that the user is reporting a problem.
+         */
+        public static final String EXTRA_REPORTING_PROBLEM = "reporting_problem";
+    }
 }
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index bb657c4..ce24a08 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -544,12 +544,11 @@
                 // However, if there was an existing folder AND we have changed
                 // folders, we want to restart the loader to get the information
                 // for the newly selected folder
-                lm.restartLoader(LOADER_CONVERSATION_LIST, null, mListCursorCallbacks);
+                lm.destroyLoader(LOADER_CONVERSATION_LIST);
+                lm.initLoader(LOADER_CONVERSATION_LIST, null, mListCursorCallbacks);
             }
         } else if (!folder.isInitialized()) {
             LogUtils.e(LOG_TAG, new Error(), "Uninitialized Folder %s in setFolder.", folder);
-        } else if (folder == null) {
-            LogUtils.wtf(LOG_TAG, "Folder in setFolder is null");
         }
     }
 
@@ -744,7 +743,7 @@
                 Utils.showHelp(mActivity.getActivityContext(), mAccount, getHelpContext());
                 break;
             case R.id.feedback_menu_item:
-                Utils.sendFeedback(mActivity.getActivityContext(), mAccount);
+                Utils.sendFeedback(mActivity.getActivityContext(), mAccount, false);
                 break;
             case R.id.manage_folders_item:
                 Utils.showManageFolder(mActivity.getActivityContext(), mAccount);
@@ -1119,6 +1118,12 @@
         }
     }
 
+    /**
+     * Set the account, and carry out all the account-related changes that rely on this.
+     * @param account
+     */
+    // TODO(viki): Two different methods do the same thing. Resolve
+    // {@link #setAccount(Account)} and {@link #switchAccount(Account, boolean)}
     private void setAccount(Account account) {
         if (account == null) {
             LogUtils.w(LOG_TAG, new Error(),
@@ -1127,6 +1132,14 @@
         }
         LogUtils.d(LOG_TAG, "AbstractActivityController.setAccount(): account = %s", account.uri);
         mAccount = account;
+        // Only change AAC state here. Do *not* modify any other object's state. The object
+        // should listen on account changes.
+        restartOptionalLoader(LOADER_RECENT_FOLDERS);
+        mActivity.invalidateOptionsMenu();
+        disableNotificationsOnAccountChange(mAccount);
+        restartOptionalLoader(LOADER_ACCOUNT_UPDATE_CURSOR);
+        MailAppProvider.getInstance().setLastViewedAccount(mAccount.uri.toString());
+
         if (account.settings == null) {
             LogUtils.w(LOG_TAG, new Error(), "AAC ignoring account with null settings.");
             return;
@@ -1983,12 +1996,12 @@
     @Override
     public void onAnimationEnd(AnimatedAdapter animatedAdapter) {
         if (mConversationListCursor.isRefreshReady()) {
-            LogUtils.d(LOG_TAG, "Stop scrolling: try sync");
+            LogUtils.d(LOG_TAG, "Stopped animating: try sync");
             onRefreshReady();
         }
 
         if (mConversationListCursor.isRefreshRequired()) {
-            LogUtils.d(LOG_TAG, "Stop scrolling: refresh");
+            LogUtils.d(LOG_TAG, "Stopped animating: refresh");
             mConversationListCursor.refresh();
         }
     }
@@ -2408,11 +2421,7 @@
                 final Uri uri = folder.refreshUri;
 
                 if (uri != null) {
-                    if (mFolderSyncTask != null) {
-                        mFolderSyncTask.cancel(true);
-                    }
-                    mFolderSyncTask = new AsyncRefreshTask(mActivity.getActivityContext(), uri);
-                    mFolderSyncTask.execute();
+                    startAsyncRefreshTask(uri);
                 }
             }
         };
@@ -2433,23 +2442,72 @@
         return new ActionClickedListener() {
             @Override
             public void onActionClicked() {
-                DialogFragment fragment = (DialogFragment)
-                        mFragmentManager.findFragmentByTag(SYNC_ERROR_DIALOG_FRAGMENT_TAG);
-                if (fragment == null) {
-                    fragment = SyncErrorDialogFragment.newInstance();
-                }
-                fragment.show(mFragmentManager, SYNC_ERROR_DIALOG_FRAGMENT_TAG);
+                showStorageErrorDialog();
             }
         };
     }
 
+    private void showStorageErrorDialog() {
+        DialogFragment fragment = (DialogFragment)
+                mFragmentManager.findFragmentByTag(SYNC_ERROR_DIALOG_FRAGMENT_TAG);
+        if (fragment == null) {
+            fragment = SyncErrorDialogFragment.newInstance();
+        }
+        fragment.show(mFragmentManager, SYNC_ERROR_DIALOG_FRAGMENT_TAG);
+    }
+
     private ActionClickedListener getInternalErrorClickedListener() {
         return new ActionClickedListener() {
             @Override
             public void onActionClicked() {
-                // TODO - have pressing report actually do something
-                // Needs to also be done in ConversationListFooterView
+                Utils.sendFeedback(
+                        mActivity.getActivityContext(), mAccount, true /* reportingProblem */);
             }
         };
     }
+
+    @Override
+    public void onFooterViewErrorActionClick(Folder folder, int errorStatus) {
+        Uri uri = null;
+        switch (errorStatus) {
+            case UIProvider.LastSyncResult.CONNECTION_ERROR:
+                if (folder != null && folder.refreshUri != null) {
+                    uri = folder.refreshUri;
+                }
+                break;
+            case UIProvider.LastSyncResult.AUTH_ERROR:
+                // TODO - open sign-in page here
+                return;
+            case UIProvider.LastSyncResult.SECURITY_ERROR:
+                return; // Currently we do nothing for security errors.
+            case UIProvider.LastSyncResult.STORAGE_ERROR:
+                showStorageErrorDialog();
+                return;
+            case UIProvider.LastSyncResult.INTERNAL_ERROR:
+                Utils.sendFeedback(
+                        mActivity.getActivityContext(), mAccount, true /* reportingProblem */);
+                return;
+            default:
+                return;
+        }
+
+        if (uri != null) {
+            startAsyncRefreshTask(uri);
+        }
+    }
+
+    @Override
+    public void onFooterViewLoadMoreClick(Folder folder) {
+        if (folder != null && folder.loadMoreUri != null) {
+            startAsyncRefreshTask(folder.loadMoreUri);
+        }
+    }
+
+    private void startAsyncRefreshTask(Uri uri) {
+        if (mFolderSyncTask != null) {
+            mFolderSyncTask.cancel(true);
+        }
+        mFolderSyncTask = new AsyncRefreshTask(mActivity.getActivityContext(), uri);
+        mFolderSyncTask.execute();
+    }
 }
diff --git a/src/com/android/mail/ui/ActivityController.java b/src/com/android/mail/ui/ActivityController.java
index 55bc047..524ad76 100644
--- a/src/com/android/mail/ui/ActivityController.java
+++ b/src/com/android/mail/ui/ActivityController.java
@@ -30,6 +30,7 @@
 
 import com.android.mail.ConversationListContext;
 import com.android.mail.browse.ConversationCursor.ConversationListener;
+import com.android.mail.browse.ConversationListFooterView;
 import com.android.mail.providers.Account;
 import com.android.mail.providers.Conversation;
 import com.android.mail.providers.Folder;
@@ -46,7 +47,7 @@
         ConversationSetObserver, ConversationListener,
         FolderListFragment.FolderListSelectionListener, HelpCallback, UndoListener,
         ConversationUpdater, ErrorListener, FolderController, AccountController,
-        ConversationPositionTracker.Callbacks{
+        ConversationPositionTracker.Callbacks, ConversationListFooterView.FooterViewClickListener {
 
     // As far as possible, the methods here that correspond to Activity lifecycle have the same name
     // as their counterpart in the Activity lifecycle.
diff --git a/src/com/android/mail/ui/AnimatedAdapter.java b/src/com/android/mail/ui/AnimatedAdapter.java
index 8d46ac9..25c3abc 100644
--- a/src/com/android/mail/ui/AnimatedAdapter.java
+++ b/src/com/android/mail/ui/AnimatedAdapter.java
@@ -342,6 +342,7 @@
             if (conv.position >= startPosition && conv.position <= endPosition) {
                 mFadeLeaveBehindItems.put(conv.id, mLeaveBehindItem);
             }
+            mLeaveBehindItem.commit();
             clearLeaveBehind(conv.id);
         }
         if (!mLastDeletingItems.isEmpty()) {
@@ -350,15 +351,24 @@
         notifyDataSetChanged();
     }
 
+    public SwipeableListView getListView() {
+        return mListView;
+    }
+
     public void commitLeaveBehindItems() {
         // Remove any previously existing leave behinds.
+        boolean changed = false;
         if (hasLeaveBehinds()) {
             mLeaveBehindItem.dismiss();
+            changed = true;
         }
         if (!mLastDeletingItems.isEmpty()) {
             mLastDeletingItems.clear();
+            changed = true;
         }
-        notifyDataSetChanged();
+        if (changed) {
+            notifyDataSetChanged();
+        }
     }
 
     private LeaveBehindItem getLeaveBehindItem(Conversation target) {
diff --git a/src/com/android/mail/ui/ControllableActivity.java b/src/com/android/mail/ui/ControllableActivity.java
index 9ad5cab..d4046a6 100644
--- a/src/com/android/mail/ui/ControllableActivity.java
+++ b/src/com/android/mail/ui/ControllableActivity.java
@@ -17,6 +17,7 @@
 
 package com.android.mail.ui;
 
+import com.android.mail.browse.ConversationListFooterView;
 import com.android.mail.providers.Conversation;
 import com.android.mail.providers.Folder;
 import com.android.mail.ui.ViewMode.ModeChangeListener;
@@ -26,7 +27,8 @@
  * able to attach the various view fragments and delegate the method calls between them.
  */
 public interface ControllableActivity extends HelpCallback, RestrictedActivity,
-        FolderItemView.DropHandler, UndoListener, AnimatedAdapter.Listener {
+        FolderItemView.DropHandler, UndoListener, AnimatedAdapter.Listener,
+        ConversationListFooterView.FooterViewClickListener {
     /**
      * Returns the ViewMode the activity is updating.
      * @see com.android.mail.ui.ViewMode
diff --git a/src/com/android/mail/ui/ConversationListFragment.java b/src/com/android/mail/ui/ConversationListFragment.java
index 97a7ebb..6f9922c 100644
--- a/src/com/android/mail/ui/ConversationListFragment.java
+++ b/src/com/android/mail/ui/ConversationListFragment.java
@@ -249,7 +249,7 @@
         mFooterView = (ConversationListFooterView) LayoutInflater.from(
                 mActivity.getActivityContext()).inflate(R.layout.conversation_list_footer_view,
                 null);
-        mFooterView.setFragmentManager(getFragmentManager());
+        mFooterView.setClickListener(mActivity);
         mListAdapter = new AnimatedAdapter(mActivity.getApplicationContext(), -1,
                 getConversationListCursor(), mActivity.getSelectedSet(), mActivity, mListView);
         mListAdapter.addFooter(mFooterView);
@@ -336,7 +336,7 @@
         mEmptyView = rootView.findViewById(R.id.empty_view);
         mListView = (SwipeableListView) rootView.findViewById(android.R.id.list);
         mListView.setHeaderDividersEnabled(false);
-        mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
+        mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
         mListView.setOnItemLongClickListener(this);
         mListView.enableSwipe(mAccount.supportsCapability(AccountCapabilities.UNDO));
         // Note - we manually save/restore the listview state.
@@ -513,6 +513,8 @@
      */
     protected final void setSelected(int position) {
         mListView.smoothScrollToPosition(position);
+        mListView.clearChoices();
+        mListView.setItemChecked(position, true);
     }
 
     private ConversationCursor getConversationListCursor() {
diff --git a/src/com/android/mail/ui/ConversationViewFragment.java b/src/com/android/mail/ui/ConversationViewFragment.java
index 6710b33..1d0c692 100644
--- a/src/com/android/mail/ui/ConversationViewFragment.java
+++ b/src/com/android/mail/ui/ConversationViewFragment.java
@@ -398,7 +398,9 @@
                 && mAccount.supportsCapability(UIProvider.AccountCapabilities.MARK_IMPORTANT));
         Utils.setMenuItemVisibility(menu, R.id.mark_not_important, !showMarkImportant
                 && mAccount.supportsCapability(UIProvider.AccountCapabilities.MARK_IMPORTANT));
-        Utils.setMenuItemVisibility(menu, R.id.delete, mFolder != null && !mFolder.isTrash());
+        Utils.setMenuItemVisibility(menu, R.id.delete,
+                mFolder != null && mFolder.supportsCapability(
+                        UIProvider.FolderCapabilities.DELETE));
         final boolean archiveVisible = mAccount.supportsCapability(AccountCapabilities.ARCHIVE)
                 && mFolder != null && mFolder.supportsCapability(FolderCapabilities.ARCHIVE)
                 && !mFolder.isTrash();
diff --git a/src/com/android/mail/ui/FolderSelectionActivity.java b/src/com/android/mail/ui/FolderSelectionActivity.java
index 9c7cd80..1843d65 100644
--- a/src/com/android/mail/ui/FolderSelectionActivity.java
+++ b/src/com/android/mail/ui/FolderSelectionActivity.java
@@ -331,4 +331,14 @@
         // Unsupported
         return null;
     }
+
+    @Override
+    public void onFooterViewErrorActionClick(Folder folder, int errorStatus) {
+        // Unsupported
+    }
+
+    @Override
+    public void onFooterViewLoadMoreClick(Folder folder) {
+        // Unsupported
+    }
 }
diff --git a/src/com/android/mail/ui/MailActivity.java b/src/com/android/mail/ui/MailActivity.java
index 125c3a4..0418f8d 100644
--- a/src/com/android/mail/ui/MailActivity.java
+++ b/src/com/android/mail/ui/MailActivity.java
@@ -413,4 +413,14 @@
     public AccountController getAccountController() {
         return mController;
     }
+
+    @Override
+    public void onFooterViewErrorActionClick(Folder folder, int errorStatus) {
+        mController.onFooterViewErrorActionClick(folder, errorStatus);
+    }
+
+    @Override
+    public void onFooterViewLoadMoreClick(Folder folder) {
+        mController.onFooterViewLoadMoreClick(folder);
+    }
 }
diff --git a/src/com/android/mail/ui/SwipeableListView.java b/src/com/android/mail/ui/SwipeableListView.java
index 9632809..4af5515 100644
--- a/src/com/android/mail/ui/SwipeableListView.java
+++ b/src/com/android/mail/ui/SwipeableListView.java
@@ -26,6 +26,8 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewParent;
+import android.widget.AbsListView;
+import android.widget.AbsListView.OnScrollListener;
 import android.widget.ListView;
 
 import com.android.mail.R;
@@ -42,7 +44,7 @@
 import java.util.Collection;
 import java.util.HashMap;
 
-public class SwipeableListView extends ListView implements Callback {
+public class SwipeableListView extends ListView implements Callback, OnScrollListener {
     private SwipeHelper mSwipeHelper;
     private boolean mEnableSwipe = false;
 
@@ -68,6 +70,7 @@
         float pagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
         mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale,
                 pagingTouchSlop);
+        setOnScrollListener(this);
     }
     @Override
     protected void onAttachedToWindow() {
@@ -322,4 +325,17 @@
         commitDestructiveActions();
         return handled;
     }
+
+    @Override
+    public void onScroll(AbsListView view, int arg1, int arg2, int arg3) {
+        // Do nothing; we only care about going from not scrolling to scrolling.
+    }
+
+    @Override
+    public void onScrollStateChanged(AbsListView view, int state) {
+        if (state == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL
+                || state == OnScrollListener.SCROLL_STATE_FLING) {
+            commitDestructiveActions();
+        }
+    }
 }
diff --git a/src/com/android/mail/utils/Utils.java b/src/com/android/mail/utils/Utils.java
index 6d99bd1..a541d43 100644
--- a/src/com/android/mail/utils/Utils.java
+++ b/src/com/android/mail/utils/Utils.java
@@ -599,7 +599,7 @@
      * Get text matching the last sync status.
      */
     public static CharSequence getSyncStatusText(Context context, int status) {
-        String[] errors = context.getResources().getStringArray(R.array.sync_status);
+        final String[] errors = context.getResources().getStringArray(R.array.sync_status);
         if (status >= errors.length) {
             return "";
         }
@@ -666,7 +666,7 @@
             builder = builder.appendQueryParameter(SMART_HELP_LINK_PARAMETER_NAME, fromWhere);
         }
 
-        openUrl(context, builder.build());
+        openUrl(context, builder.build(), null);
     }
 
     /**
@@ -675,13 +675,18 @@
      * @param context Context
      * @param uri Uri to open.
      */
-    private static void openUrl(Context context, Uri uri) {
+    private static void openUrl(Context context, Uri uri, Bundle optionalExtras) {
         if(uri == null || TextUtils.isEmpty(uri.toString())) {
             LogUtils.wtf(LOG_TAG, "invalid url in Utils.openUrl(): %s", uri);
             return;
         }
-        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+        final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+        // Fill in any of extras that have been requested.
+        if (optionalExtras != null) {
+            intent.putExtras(optionalExtras);
+        }
         intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
+
         context.startActivity(intent);
     }
 
@@ -780,9 +785,12 @@
     /**
      * Show the feedback screen for the supplied account.
      */
-    public static void sendFeedback(Context context, Account account) {
+    public static void sendFeedback(Context context, Account account, boolean reportingProblem) {
         if (account != null && account.sendFeedbackIntentUri != null) {
-            openUrl(context, account.sendFeedbackIntentUri);
+            final Bundle optionalExtras = new Bundle(1);
+            optionalExtras.putBoolean(
+                    UIProvider.SendFeedbackExtras.EXTRA_REPORTING_PROBLEM, reportingProblem);
+            openUrl(context, account.sendFeedbackIntentUri, optionalExtras);
         }
     }