Merge "Import translations. DO NOT MERGE" into jb-ub-mail-ur10
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 24fa2b2..130700b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -111,6 +111,16 @@
             android:label="@string/app_name"
             android:theme="@style/PhotoViewTheme" >
         </activity>
+        <activity
+                android:name=".browse.EmlViewerActivity"
+                android:label="@string/app_name"
+                android:exported="false">
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="message/rfc822" />
+            </intent-filter>
+        </activity>
 
         <provider
             android:authorities="com.android.mail.mockprovider"
diff --git a/res/layout/eml_viewer_activity.xml b/res/layout/eml_viewer_activity.xml
new file mode 100644
index 0000000..751a4fa
--- /dev/null
+++ b/res/layout/eml_viewer_activity.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <WebView
+            android:id="@+id/eml_web_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+        />
+</LinearLayout>
\ No newline at end of file
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 0afe96c..a13fdad 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -24,7 +24,6 @@
 import android.content.ClipData.Item;
 import android.content.Context;
 import android.content.res.Resources;
-import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -426,13 +425,6 @@
         mAttachmentPreviewsCanvas = new DividedImageCanvas(context, this);
     }
 
-    public void bind(Cursor cursor, ControllableActivity activity, ConversationSelectionSet set,
-            Folder folder, int checkboxOrSenderImage, boolean swipeEnabled,
-            boolean priorityArrowEnabled, AnimatedAdapter adapter) {
-        bind(ConversationItemViewModel.forCursor(mAccount, cursor), activity, set, folder,
-                checkboxOrSenderImage, swipeEnabled, priorityArrowEnabled, adapter);
-    }
-
     public void bind(Conversation conversation, ControllableActivity activity,
             ConversationSelectionSet set, Folder folder, int checkboxOrSenderImage,
             boolean swipeEnabled, boolean priorityArrowEnabled, AnimatedAdapter adapter) {
diff --git a/src/com/android/mail/browse/ConversationItemViewModel.java b/src/com/android/mail/browse/ConversationItemViewModel.java
index d83ce74..fa01322 100644
--- a/src/com/android/mail/browse/ConversationItemViewModel.java
+++ b/src/com/android/mail/browse/ConversationItemViewModel.java
@@ -17,12 +17,7 @@
 
 package com.android.mail.browse;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
-import com.google.common.collect.Lists;
-
 import android.content.Context;
-import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.text.SpannableString;
@@ -39,6 +34,9 @@
 import com.android.mail.providers.Folder;
 import com.android.mail.providers.MessageInfo;
 import com.android.mail.providers.UIProvider;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -148,10 +146,6 @@
         }
     }
 
-    static ConversationItemViewModel forCursor(String account, Cursor cursor) {
-        return forConversation(account, new Conversation(cursor));
-    }
-
     static ConversationItemViewModel forConversation(String account, Conversation conv) {
         ConversationItemViewModel header = ConversationItemViewModel.forConversationId(account,
                 conv.id);
diff --git a/src/com/android/mail/browse/ConversationPagerAdapter.java b/src/com/android/mail/browse/ConversationPagerAdapter.java
index 25a7aab..56810e7 100644
--- a/src/com/android/mail/browse/ConversationPagerAdapter.java
+++ b/src/com/android/mail/browse/ConversationPagerAdapter.java
@@ -186,9 +186,7 @@
                 return null;
             }
             cursor.notifyUIPositionChange();
-            // TODO: switch to something like MessageCursor or AttachmentCursor
-            // to re-use these models
-            c = new Conversation(cursor);
+            c = cursor.getConversation();
             c.position = position;
         }
         final AbstractConversationViewFragment f = getConversationViewFragment(c);
@@ -343,7 +341,7 @@
         if (mController != null && !mDetachedMode && mPager != null) {
             final Conversation currConversation = mController.getCurrentConversation();
             final int pos = getConversationPosition(currConversation);
-            final Cursor cursor = getCursor();
+            final ConversationCursor cursor = getCursor();
             if (pos == POSITION_NONE && cursor != null && currConversation != null) {
                 // enable detached mode and do no more here. the fragment itself will figure out
                 // if the conversation is empty (using message list cursor) and back out if needed.
@@ -370,7 +368,7 @@
                         (AbstractConversationViewFragment) getFragmentAt(pos);
                 if (frag != null && cursor.moveToPosition(pos) && frag.isUserVisible()) {
                     // reload what we think is in the current position.
-                    final Conversation conv = new Conversation(cursor);
+                    final Conversation conv = cursor.getConversation();
                     conv.position = pos;
                     frag.onConversationUpdated(conv);
                     mController.setCurrentConversation(conv);
@@ -494,12 +492,12 @@
         if (mController == null) {
             return;
         }
-        final Cursor cursor = getCursor();
+        final ConversationCursor cursor = getCursor();
         if (cursor == null || !cursor.moveToPosition(position)) {
             // No valid cursor or it doesn't have the position we want. Bail.
             return;
         }
-        final Conversation c = new Conversation(cursor);
+        final Conversation c = cursor.getConversation();
         c.position = position;
         LogUtils.d(LOG_TAG, "pager adapter setting current conv: %s", c);
         mController.setCurrentConversation(c);
diff --git a/src/com/android/mail/browse/EmlViewerActivity.java b/src/com/android/mail/browse/EmlViewerActivity.java
new file mode 100644
index 0000000..a102424
--- /dev/null
+++ b/src/com/android/mail/browse/EmlViewerActivity.java
@@ -0,0 +1,65 @@
+package com.android.mail.browse;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.webkit.WebView;
+import android.widget.TextView;
+
+import com.android.mail.R;
+import com.android.mail.utils.LogTag;
+import com.android.mail.utils.LogUtils;
+import com.android.mail.utils.MimeType;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class EmlViewerActivity extends Activity {
+    private static final String LOG_TAG = LogTag.getLogTag();
+
+    private WebView mWebView;
+
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.eml_viewer_activity);
+        mWebView = (WebView) findViewById(R.id.eml_web_view);
+
+        final Intent intent = getIntent();
+        final String action = intent.getAction();
+        final String type = intent.getType();
+
+        if (Intent.ACTION_VIEW.equals(action) &&
+                MimeType.EML_ATTACHMENT_CONTENT_TYPE.equals(type)) {
+            openEmlFile(intent.getData());
+        } else {
+            LogUtils.wtf(LOG_TAG,
+                    "Entered EmlViewerActivity with wrong intent action or type: %s, %s",
+                    action, type);
+            finish(); // we should not be here. bail out. bail out.
+        }
+    }
+
+    private void openEmlFile(Uri uri) {
+        final ContentResolver resolver = getContentResolver();
+        try {
+            final InputStream stream = resolver.openInputStream(uri);
+            BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
+            StringBuilder builder = new StringBuilder(stream.available());
+            String line = reader.readLine();
+            while (line != null) {
+                builder.append(line);
+                line = reader.readLine();
+            }
+            mWebView.loadDataWithBaseURL("", builder.toString(), "text/html", "utf-8", null);
+        } catch (FileNotFoundException e) {
+            // TODO handle exceptions
+        } catch (IOException e) {
+            // TODO handle exception
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/mail/browse/SwipeableConversationItemView.java b/src/com/android/mail/browse/SwipeableConversationItemView.java
index 27730cc..a675b8d 100644
--- a/src/com/android/mail/browse/SwipeableConversationItemView.java
+++ b/src/com/android/mail/browse/SwipeableConversationItemView.java
@@ -20,7 +20,6 @@
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
 import android.content.Context;
-import android.database.Cursor;
 import android.widget.FrameLayout;
 import android.widget.ListView;
 
@@ -59,13 +58,6 @@
                 swipeEnabled, priorityArrowsEnabled, animatedAdapter);
     }
 
-    public void bind(Cursor cursor, ControllableActivity activity, ConversationSelectionSet set,
-            Folder folder, int checkboxOrSenderImage, boolean swipeEnabled,
-            boolean priorityArrowsEnabled, AnimatedAdapter animatedAdapter) {
-        mConversationItemView.bind(cursor, activity, set, folder, checkboxOrSenderImage,
-                swipeEnabled, priorityArrowsEnabled, animatedAdapter);
-    }
-
     public void startUndoAnimation(AnimatorListener listener, boolean swipe) {
         final Animator a = (swipe) ? mConversationItemView.createSwipeUndoAnimation()
                 : mConversationItemView.createUndoAnimation();
diff --git a/src/com/android/mail/compose/ComposeActivity.java b/src/com/android/mail/compose/ComposeActivity.java
index 3ee79f7..98fad35 100644
--- a/src/com/android/mail/compose/ComposeActivity.java
+++ b/src/com/android/mail/compose/ComposeActivity.java
@@ -211,6 +211,8 @@
     private static final String MIME_TYPE_PHOTO = "image/*";
     private static final String MIME_TYPE_VIDEO = "video/*";
 
+    private static final String KEY_INNER_SAVED_STATE = "compose_state";
+
     /**
      * A single thread for running tasks in the background.
      */
@@ -264,7 +266,7 @@
     private RecipientTextWatcher mBccListener;
     private Uri mRefMessageUri;
     private boolean mShowQuotedText = false;
-    private Bundle mSavedInstanceState;
+    private Bundle mInnerSavedState;
 
 
     // Array of the outstanding send or save tasks.  Access is synchronized
@@ -370,12 +372,13 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.compose);
-        mSavedInstanceState = savedInstanceState;
+        mInnerSavedState = (savedInstanceState != null) ?
+                savedInstanceState.getBundle(KEY_INNER_SAVED_STATE) : null;
         checkValidAccounts();
     }
 
     private void finishCreate() {
-        Bundle savedInstanceState = mSavedInstanceState;
+        final Bundle savedState = mInnerSavedState;
         findViews();
         Intent intent = getIntent();
         Message message;
@@ -384,13 +387,13 @@
         int action;
         // Check for any of the possibly supplied accounts.;
         Account account = null;
-        if (hadSavedInstanceStateMessage(savedInstanceState)) {
-            action = savedInstanceState.getInt(EXTRA_ACTION, COMPOSE);
-            account = savedInstanceState.getParcelable(Utils.EXTRA_ACCOUNT);
-            message = (Message) savedInstanceState.getParcelable(EXTRA_MESSAGE);
+        if (hadSavedInstanceStateMessage(savedState)) {
+            action = savedState.getInt(EXTRA_ACTION, COMPOSE);
+            account = savedState.getParcelable(Utils.EXTRA_ACCOUNT);
+            message = (Message) savedState.getParcelable(EXTRA_MESSAGE);
 
-            previews = savedInstanceState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS);
-            mRefMessage = (Message) savedInstanceState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
+            previews = savedState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS);
+            mRefMessage = (Message) savedState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
         } else {
             account = obtainAccount(intent);
             action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
@@ -439,7 +442,7 @@
         } else if (message != null && action != EDIT_DRAFT) {
             initFromDraftMessage(message);
             initQuotedTextFromRefMessage(mRefMessage, action);
-            showCcBcc(savedInstanceState);
+            showCcBcc(savedState);
             mShowQuotedText = message.appendRefMessageContent;
         } else if (action == EDIT_DRAFT) {
             initFromDraftMessage(message);
@@ -484,7 +487,7 @@
         }
 
         mComposeMode = action;
-        finishSetup(action, intent, savedInstanceState);
+        finishSetup(action, intent, savedState);
     }
 
     private void checkValidAccounts() {
@@ -593,8 +596,8 @@
         updateHideOrShowCcBcc();
         updateHideOrShowQuotedText(mShowQuotedText);
 
-        mRespondedInline = mSavedInstanceState != null ?
-                mSavedInstanceState.getBoolean(EXTRA_RESPONDED_INLINE) : false;
+        mRespondedInline = mInnerSavedState != null ?
+                mInnerSavedState.getBoolean(EXTRA_RESPONDED_INLINE) : false;
         if (mRespondedInline) {
             mQuotedTextView.setVisibility(View.GONE);
         }
@@ -710,10 +713,10 @@
             clearChangeListeners();
         }
         super.onRestoreInstanceState(savedInstanceState);
-        if (savedInstanceState != null) {
-            if (savedInstanceState.containsKey(EXTRA_FOCUS_SELECTION_START)) {
-                int selectionStart = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_START);
-                int selectionEnd = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_END);
+        if (mInnerSavedState != null) {
+            if (mInnerSavedState.containsKey(EXTRA_FOCUS_SELECTION_START)) {
+                int selectionStart = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_START);
+                int selectionEnd = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_END);
                 // There should be a focus and it should be an EditText since we
                 // only save these extras if these conditions are true.
                 EditText focusEditText = (EditText) getCurrentFocus();
@@ -731,6 +734,12 @@
     @Override
     public final void onSaveInstanceState(Bundle state) {
         super.onSaveInstanceState(state);
+        final Bundle inner = new Bundle();
+        saveState(inner);
+        state.putBundle(KEY_INNER_SAVED_STATE, inner);
+    }
+
+    private void saveState(Bundle state) {
         // We have no accounts so there is nothing to compose, and therefore, nothing to save.
         if (mAccounts == null || mAccounts.length == 0) {
             return;
@@ -1812,8 +1821,8 @@
          */
         mSave = menu.findItem(R.id.save);
         String action = getIntent() != null ? getIntent().getAction() : null;
-        enableSave(mSavedInstanceState != null ?
-                mSavedInstanceState.getBoolean(EXTRA_SAVE_ENABLED)
+        enableSave(mInnerSavedState != null ?
+                mInnerSavedState.getBoolean(EXTRA_SAVE_ENABLED)
                     : (Intent.ACTION_SEND.equals(action)
                             || Intent.ACTION_SEND_MULTIPLE.equals(action)
                             || Intent.ACTION_SENDTO.equals(action)
@@ -3169,7 +3178,7 @@
                 if (data != null && data.moveToFirst()) {
                     mRefMessage = new Message(data);
                 }
-                finishSetup(mComposeMode, getIntent(), mSavedInstanceState);
+                finishSetup(mComposeMode, getIntent(), mInnerSavedState);
                 break;
             case LOADER_ACCOUNT_CURSOR:
                 if (data != null && data.moveToFirst()) {
diff --git a/src/com/android/mail/ui/AccountController.java b/src/com/android/mail/ui/AccountController.java
index f2b36f9..3d8ab2f 100644
--- a/src/com/android/mail/ui/AccountController.java
+++ b/src/com/android/mail/ui/AccountController.java
@@ -19,6 +19,7 @@
 
 import android.database.DataSetObservable;
 import android.database.DataSetObserver;
+import android.widget.ListView;
 
 import com.android.mail.providers.Account;
 import com.android.mail.providers.AccountObserver;
@@ -108,4 +109,10 @@
      * @return <code>true</code> if the drawer pull action is enabled, <code>false</code> otherwise
      */
     boolean isDrawerPullEnabled();
+
+    /**
+     * @return the choice mode to use in the {@link ListView} in the default folder list (subclasses
+     * of {@link FolderListFragment} may override this
+     */
+    int getFolderListViewChoiceMode();
 }
diff --git a/src/com/android/mail/ui/AnimatedAdapter.java b/src/com/android/mail/ui/AnimatedAdapter.java
index 868f6d5..fd387a6 100644
--- a/src/com/android/mail/ui/AnimatedAdapter.java
+++ b/src/com/android/mail/ui/AnimatedAdapter.java
@@ -675,11 +675,8 @@
 
     @Override
     public void bindView(View view, Context context, Cursor cursor) {
-        if (! (view instanceof SwipeableConversationItemView)) {
-            return;
-        }
-        ((SwipeableConversationItemView) view).bind(cursor, mActivity, mBatchConversations, mFolder,
-                getCheckboxSetting(), mSwipeEnabled, mPriorityMarkersEnabled, this);
+        // no-op. we only get here from newConversationItemView(), which will immediately bind
+        // on its own.
     }
 
     private SwipeableConversationItemView newConversationItemView(int position, ViewGroup parent,
diff --git a/src/com/android/mail/ui/ConversationPositionTracker.java b/src/com/android/mail/ui/ConversationPositionTracker.java
index 46ca0a0..7be0f23 100644
--- a/src/com/android/mail/ui/ConversationPositionTracker.java
+++ b/src/com/android/mail/ui/ConversationPositionTracker.java
@@ -57,7 +57,7 @@
     private Conversation conversationAtPosition(int position){
         final ConversationCursor cursor = mCallbacks.getConversationListCursor();
         cursor.moveToPosition(position);
-        final Conversation conv = new Conversation(cursor);
+        final Conversation conv = cursor.getConversation();
         conv.position = position;
         return conv;
     }
diff --git a/src/com/android/mail/ui/DrawerFragment.java b/src/com/android/mail/ui/DrawerFragment.java
index 85436e4..c83a7a9 100644
--- a/src/com/android/mail/ui/DrawerFragment.java
+++ b/src/com/android/mail/ui/DrawerFragment.java
@@ -17,6 +17,8 @@
 
 package com.android.mail.ui;
 
+import android.widget.ListView;
+
 /**
  * A drawer that is shown in one pane mode, as a pull-out from the left.  All the
  * implementation is inherited from the FolderListFragment.
@@ -27,4 +29,10 @@
         // Drawer is always sectioned.
         mIsSectioned = true;
     }
+
+    @Override
+    protected int getListViewChoiceMode() {
+        // Always let one item be selected
+        return ListView.CHOICE_MODE_SINGLE;
+    }
 }
diff --git a/src/com/android/mail/ui/FolderListFragment.java b/src/com/android/mail/ui/FolderListFragment.java
index 6e10fa3..0755ae2 100644
--- a/src/com/android/mail/ui/FolderListFragment.java
+++ b/src/com/android/mail/ui/FolderListFragment.java
@@ -21,7 +21,6 @@
 import android.app.ListFragment;
 import android.app.LoaderManager;
 import android.content.Loader;
-import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
 import android.view.LayoutInflater;
@@ -75,7 +74,7 @@
     /** Object that changes folders on our behalf. */
     private FolderListSelectionListener mFolderChanger;
     /** Object that changes accounts on our behalf */
-    private AccountController mAccountChanger;
+    private AccountController mAccountController;
 
     /** The currently selected folder (the folder being viewed).  This is never null. */
     private Uri mSelectedFolderUri = Uri.EMPTY;
@@ -87,7 +86,9 @@
     /** Parent of the current folder, or null if the current folder is not a child. */
     private Folder mParentFolder;
 
-    private static final int FOLDER_LOADER_ID = 0;
+    private static final int FOLDER_LIST_LOADER_ID = 0;
+    /** Loader id for the full list of folders in the account */
+    private static final int FULL_FOLDER_LIST_LOADER_ID = 1;
     /** Key to store {@link #mParentFolder}. */
     private static final String ARG_PARENT_FOLDER = "arg-parent-folder";
     /** Key to store {@link #mIsSectioned} */
@@ -292,7 +293,7 @@
                 }
             };
             mAllAccountsObserver.initialize(accountController);
-            mAccountChanger = accountController;
+            mAccountController = accountController;
 
             // Observer for when the drawer is closed
             mDrawerObserver = new DrawerClosedObserver() {
@@ -301,12 +302,11 @@
                     // First, check if there's a folder to change to
                     if (mNextFolder != null) {
                         mFolderChanger.onFolderSelected(mNextFolder);
-                        // Wait for an update to the current folder. When we get the next folder,
-                        // then we null it out.
+                        mNextFolder = null;
                     }
                     // Next, check if there's an account to change to
                     if (mNextAccount != null) {
-                        mAccountChanger.switchToDefaultInboxOrChangeAccount(mNextAccount);
+                        mAccountController.switchToDefaultInboxOrChangeAccount(mNextAccount);
                         mNextAccount = null;
                     }
                 }
@@ -319,6 +319,8 @@
             return;
         }
 
+        mListView.setChoiceMode(getListViewChoiceMode());
+
         setListAdapter(mCursorAdapter);
     }
 
@@ -346,13 +348,10 @@
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedState) {
-        final Bundle args = getArguments();
-        if (args != null) {
-            mHideAccounts = args.getBoolean(ARG_HIDE_ACCOUNTS, false);
-        }
+        setInstanceFromBundle(getArguments());
+
         final View rootView = inflater.inflate(R.layout.folder_list, null);
         mListView = (ListView) rootView.findViewById(android.R.id.list);
-        mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
         mListView.setEmptyView(null);
         mListView.setDivider(null);
         if (savedState != null && savedState.containsKey(BUNDLE_LIST_STATE)) {
@@ -438,7 +437,7 @@
         // Switching accounts takes you to the default inbox for that account.
         mSelectedFolderType = DrawerItem.FOLDER_INBOX;
         mNextAccount = account;
-        mAccountChanger.closeDrawer(true, mNextAccount, getDefaultInbox(mNextAccount));
+        mAccountController.closeDrawer(true, mNextAccount, getDefaultInbox(mNextAccount));
     }
 
     /**
@@ -465,7 +464,7 @@
                         mListView.setItemChecked(defaultInboxPosition, true);
                     }
                     // ... and close the drawer (no new target folders/accounts)
-                    mAccountChanger.closeDrawer(false, mNextAccount,
+                    mAccountController.closeDrawer(false, mNextAccount,
                             getDefaultInbox(mNextAccount));
                 } else {
                     changeAccount(account);
@@ -502,10 +501,10 @@
             // Go to the conversation list for this folder.
             if (!folder.uri.equals(mSelectedFolderUri)) {
                 mNextFolder = folder;
-                mAccountChanger.closeDrawer(true, nextAccount, folder);
+                mAccountController.closeDrawer(true, nextAccount, folder);
             } else {
                 // Clicked on same folder, just close drawer
-                mAccountChanger.closeDrawer(false, nextAccount, folder);
+                mAccountController.closeDrawer(false, nextAccount, folder);
             }
         }
     }
@@ -514,10 +513,10 @@
     public Loader<ObjectCursor<Folder>> onCreateLoader(int id, Bundle args) {
         mListView.setEmptyView(null);
         final Uri folderListUri;
-        if (mType == TYPE_TREE) {
+        if (id == FOLDER_LIST_LOADER_ID && mType == TYPE_TREE) {
             // Folder trees, they specify a URI at construction time.
             folderListUri = mFolderListUri;
-        } else if (mType == TYPE_DRAWER) {
+        } else if (id == FOLDER_LIST_LOADER_ID && mType == TYPE_DRAWER) {
             // Drawers should have a valid account
             if (mCurrentAccount != null) {
                 folderListUri = mCurrentAccount.folderListUri;
@@ -525,6 +524,8 @@
                 LogUtils.wtf(LOG_TAG, "FLF.onCreateLoader() for Drawer with null account");
                 return null;
             }
+        } else if (id == FULL_FOLDER_LIST_LOADER_ID) {
+            folderListUri = mCurrentAccount.fullFolderListUri;
         } else {
             LogUtils.wtf(LOG_TAG, "FLF.onCreateLoader() with weird type");
             return null;
@@ -536,14 +537,22 @@
     @Override
     public void onLoadFinished(Loader<ObjectCursor<Folder>> loader, ObjectCursor<Folder> data) {
         if (mCursorAdapter != null) {
-            mCursorAdapter.setCursor(data);
+            if (loader.getId() == FOLDER_LIST_LOADER_ID) {
+                mCursorAdapter.setCursor(data);
+            } else if (loader.getId() == FULL_FOLDER_LIST_LOADER_ID) {
+                mCursorAdapter.setFullFolderListCursor(data);
+            }
         }
     }
 
     @Override
     public void onLoaderReset(Loader<ObjectCursor<Folder>> loader) {
         if (mCursorAdapter != null) {
-            mCursorAdapter.setCursor(null);
+            if (loader.getId() == FOLDER_LIST_LOADER_ID) {
+                mCursorAdapter.setCursor(null);
+            } else if (loader.getId() == FULL_FOLDER_LIST_LOADER_ID) {
+                mCursorAdapter.setFullFolderListCursor(null);
+            }
         }
     }
 
@@ -565,6 +574,8 @@
     private interface FolderListFragmentCursorAdapter extends ListAdapter {
         /** Update the folder list cursor with the cursor given here. */
         void setCursor(ObjectCursor<Folder> cursor);
+        /** Update the full folder list cursor with the cursor given here. */
+        void setFullFolderListCursor(ObjectCursor<Folder> cursor);
         /**
          * Given an item, find the type of the item, which should only be {@link
          * DrawerItem#VIEW_FOLDER} or {@link DrawerItem#VIEW_ACCOUNT}
@@ -591,7 +602,7 @@
         private final RecentFolderObserver mRecentFolderObserver = new RecentFolderObserver() {
             @Override
             public void onChanged() {
-                if (!isCursorInvalid(mCursor)) {
+                if (!isCursorInvalid()) {
                     recalculateList();
                 }
             }
@@ -606,6 +617,8 @@
         private List<DrawerItem> mItemList = new ArrayList<DrawerItem>();
         /** Cursor into the folder list. This might be null. */
         private ObjectCursor<Folder> mCursor = null;
+        /** Cursor into the full folder list. This might be null. */
+        private ObjectCursor<Folder> mFullFolderListCursor = null;
         /** Watcher for tracking and receiving unread counts for mail */
         private FolderWatcher mFolderWatcher = null;
         private boolean mRegistered = false;
@@ -630,9 +643,9 @@
 
         @Override
         public void notifyAllAccountsChanged() {
-            if (!mRegistered && mAccountChanger != null) {
+            if (!mRegistered && mAccountController != null) {
                 // TODO(viki): Round-about way of setting the watcher. http://b/8750610
-                mAccountChanger.setFolderWatcher(mFolderWatcher);
+                mAccountController.setFolderWatcher(mFolderWatcher);
                 mRegistered = true;
             }
             mFolderWatcher.updateAccountList(getAllAccounts());
@@ -764,7 +777,7 @@
             // If we are waiting for folder initialization, we don't have any kinds of folders,
             // just the "Waiting for initialization" item. Note, this should only be done
             // when we're waiting for account initialization or initial sync.
-            if (isCursorInvalid(mCursor)) {
+            if (isCursorInvalid()) {
                 if(!mCurrentAccount.isAccountReady()) {
                     itemList.add(DrawerItem.forWaitView(mActivity));
                 }
@@ -787,7 +800,6 @@
             // Otherwise, this is an adapter for a sectioned list.
             final List<DrawerItem> allFoldersList = new ArrayList<DrawerItem>();
             final List<DrawerItem> inboxFolders = new ArrayList<DrawerItem>();
-            boolean currentFolderFound = false;
             do {
                 final Folder f = mCursor.getModel();
                 if (!isFolderTypeExcluded(f)) {
@@ -798,18 +810,36 @@
                         allFoldersList.add(DrawerItem.ofFolder(
                                 mActivity, f, DrawerItem.FOLDER_OTHER, mCursor.getPosition()));
                     }
-                    if (f.equals(mCurrentFolderForUnreadCheck)) {
-                        currentFolderFound = true;
-                    }
                 }
             } while (mCursor.moveToNext());
 
-            if (!currentFolderFound && mCurrentFolderForUnreadCheck != null
-                    && mCurrentAccount != null && mAccountChanger != null
-                    && mAccountChanger.isDrawerPullEnabled()) {
-                LogUtils.d(LOG_TAG, "Current folder (%1$s) has disappeared for %2$s",
-                        mCurrentFolderForUnreadCheck.name, mCurrentAccount.name);
-                changeAccount(mCurrentAccount);
+            // If we have the full folder list, verify that the current folder exists
+            boolean currentFolderFound = false;
+            if (mFullFolderListCursor != null) {
+                final String folderName = mCurrentFolderForUnreadCheck == null
+                        ? "null" : mCurrentFolderForUnreadCheck.name;
+                LogUtils.d(LOG_TAG, "Checking if full folder list contains %s", folderName);
+
+                if (mFullFolderListCursor.moveToFirst()) {
+                    LogUtils.d(LOG_TAG, "Cursor for %s seems reasonably valid", folderName);
+                    do {
+                        final Folder f = mFullFolderListCursor.getModel();
+                        if (!isFolderTypeExcluded(f)) {
+                            if (f.equals(mCurrentFolderForUnreadCheck)) {
+                                LogUtils.d(LOG_TAG, "Found %s !", folderName);
+                                currentFolderFound = true;
+                            }
+                        }
+                    } while (mFullFolderListCursor.moveToNext());
+                }
+
+                if (!currentFolderFound && mCurrentFolderForUnreadCheck != null
+                        && mCurrentAccount != null && mAccountController != null
+                        && mAccountController.isDrawerPullEnabled()) {
+                    LogUtils.d(LOG_TAG, "Current folder (%1$s) has disappeared for %2$s",
+                            mCurrentFolderForUnreadCheck.name, mCurrentAccount.name);
+                    changeAccount(mCurrentAccount);
+                }
             }
 
             // Add all inboxes (sectioned included) before recents.
@@ -875,10 +905,9 @@
 
         /**
          * Check if the cursor provided is valid.
-         * @param mCursor
          * @return True if cursor is invalid, false otherwise
          */
-        private boolean isCursorInvalid(Cursor mCursor) {
+        private boolean isCursorInvalid() {
             return mCursor == null || mCursor.isClosed()|| mCursor.getCount() <= 0
                     || !mCursor.moveToFirst();
         }
@@ -890,6 +919,12 @@
         }
 
         @Override
+        public void setFullFolderListCursor(final ObjectCursor<Folder> cursor) {
+            mFullFolderListCursor = cursor;
+            recalculateList();
+        }
+
+        @Override
         public Object getItem(int position) {
             // Is there an attempt made to access outside of the drawer item list?
             if (position >= mItemList.size()) {
@@ -940,7 +975,7 @@
     }
 
     private class HierarchicalFolderListAdapter extends ArrayAdapter<Folder>
-            implements FolderListFragmentCursorAdapter{
+            implements FolderListFragmentCursorAdapter {
 
         private static final int PARENT = 0;
         private static final int CHILD = 1;
@@ -1015,6 +1050,11 @@
         }
 
         @Override
+        public void setFullFolderListCursor(final ObjectCursor<Folder> cursor) {
+            // Not necessary in HierarchicalFolderListAdapter
+        }
+
+        @Override
         public void destroy() {
             // Do nothing.
         }
@@ -1065,12 +1105,6 @@
             LogUtils.e(LOG_TAG, "FolderListFragment.setSelectedFolder(null) called!");
             return;
         }
-        // Is this the folder we changed to previously?  If not, ignore the update
-        if (mNextFolder != null && !folder.uri.equals(mNextFolder.uri)) {
-            // Update to a folder that we don't care about.  Ignore
-            return;
-        }
-        mNextFolder = null;
 
         final boolean viewChanged =
                 !FolderItemView.areSameViews(folder, mCurrentFolderForUnreadCheck);
@@ -1110,8 +1144,10 @@
             // comment on {@link AbstractActivityController#restartOptionalLoader} to see why we
             // don't just do restartLoader.
             final LoaderManager manager = getLoaderManager();
-            manager.destroyLoader(FOLDER_LOADER_ID);
-            manager.restartLoader(FOLDER_LOADER_ID, Bundle.EMPTY, this);
+            manager.destroyLoader(FOLDER_LIST_LOADER_ID);
+            manager.restartLoader(FOLDER_LIST_LOADER_ID, Bundle.EMPTY, this);
+            manager.destroyLoader(FULL_FOLDER_LIST_LOADER_ID);
+            manager.restartLoader(FULL_FOLDER_LIST_LOADER_ID, Bundle.EMPTY, this);
             // An updated cursor causes the entire list to refresh. No need to refresh the list.
             // But we do need to blank out the current folder, since the account might not be
             // synced.
@@ -1122,7 +1158,8 @@
             // non-null account -> null account transition.
             LogUtils.e(LOG_TAG, "FLF.setSelectedAccount(null) called! Destroying existing loader.");
             final LoaderManager manager = getLoaderManager();
-            manager.destroyLoader(FOLDER_LOADER_ID);
+            manager.destroyLoader(FOLDER_LIST_LOADER_ID);
+            manager.destroyLoader(FULL_FOLDER_LIST_LOADER_ID);
         }
     }
 
@@ -1154,4 +1191,11 @@
 
         return false;
     }
+
+    /**
+     * @return the choice mode to use for the {@link ListView}
+     */
+    protected int getListViewChoiceMode() {
+        return mAccountController.getFolderListViewChoiceMode();
+    }
 }
diff --git a/src/com/android/mail/ui/FolderSelectionActivity.java b/src/com/android/mail/ui/FolderSelectionActivity.java
index be2608e..c96ddfc 100644
--- a/src/com/android/mail/ui/FolderSelectionActivity.java
+++ b/src/com/android/mail/ui/FolderSelectionActivity.java
@@ -32,6 +32,7 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
+import android.widget.ListView;
 
 import com.android.mail.R;
 import com.android.mail.providers.Account;
@@ -149,6 +150,11 @@
             // Unsupported
             return false;
         }
+
+        @Override
+        public int getFolderListViewChoiceMode() {
+            return ListView.CHOICE_MODE_NONE;
+        }
     };
 
     @Override
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index 527513a..ed62708 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -24,6 +24,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.support.v4.widget.DrawerLayout;
+import android.widget.ListView;
 
 import com.android.mail.ConversationListContext;
 import com.android.mail.R;
@@ -374,6 +375,12 @@
             mActivity.finish();
         } else if (mViewMode.isListMode() && !inInbox(mAccount, mConvListContext)) {
             if (mLastFolderListTransactionId != INVALID_ID) {
+                // Set the hierarchy folder to what it will be once we go up
+                final Folder hierarchyFolder = getHierarchyFolder();
+                if (hierarchyFolder != null && hierarchyFolder.parent != null) {
+                    setHierarchyFolder(hierarchyFolder.parent);
+                }
+
                 // If the user got here by navigating via the folder list, back
                 // should bring them back to the folder list.
                 mViewMode.enterFolderListMode();
@@ -434,6 +441,7 @@
                     FolderListFragment.ofTree(folder, false),
                     FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_FOLDER_LIST, R.id.content_pane);
         } else {
+            setHierarchyFolder(folder);
             super.onFolderSelected(folder);
         }
     }
@@ -652,4 +660,10 @@
         // The drawer is enabled for one pane mode
         return true;
     }
+
+    @Override
+    public int getFolderListViewChoiceMode() {
+        // By default, we do not want to allow any item to be selected in the folder list
+        return ListView.CHOICE_MODE_NONE;
+    }
 }
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index da71cb4..5294a61 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -24,6 +24,7 @@
 import android.support.v4.widget.DrawerLayout;
 import android.view.Gravity;
 import android.widget.FrameLayout;
+import android.widget.ListView;
 
 import com.android.mail.ConversationListContext;
 import com.android.mail.R;
@@ -431,6 +432,15 @@
                     createFolderListFragment(FolderListFragment.ofDrawer());
                     loadAccountInbox();
                 }
+            // Otherwise, if we are in the conversation list but not in the default
+            // inbox and not on expansive layouts, we want to switch back to the default
+            // inbox. This fixes b/9006969 so that on smaller tablets where we have this
+            // hybrid one and two-pane mode, we will return to the inbox. On larger tablets,
+            // we will instead exit the app.
+            } else if (mode == ViewMode.CONVERSATION_LIST
+                    && !mAccount.settings.defaultInbox.equals(mFolder.uri)
+                    && !mLayout.isExpansiveLayout()) {
+                loadAccountInbox();
             } else if (!preventClose) {
                 // There is nothing else to pop off the stack.
                 mActivity.finish();
@@ -564,4 +574,10 @@
     public boolean isDrawerEnabled() {
         return mLayout.isDrawerEnabled();
     }
+
+    @Override
+    public int getFolderListViewChoiceMode() {
+        // By default, we want to allow one item to be selected in the folder list
+        return ListView.CHOICE_MODE_SINGLE;
+    }
 }
diff --git a/src/com/android/mail/ui/TwoPaneLayout.java b/src/com/android/mail/ui/TwoPaneLayout.java
index 29e0547..779d73e 100644
--- a/src/com/android/mail/ui/TwoPaneLayout.java
+++ b/src/com/android/mail/ui/TwoPaneLayout.java
@@ -586,4 +586,7 @@
         return !mIsExpansiveLayout && mDrawerInitialSetupComplete;
     }
 
+    public boolean isExpansiveLayout() {
+        return mIsExpansiveLayout;
+    }
 }
diff --git a/src/com/android/mail/utils/MimeType.java b/src/com/android/mail/utils/MimeType.java
index 8f0ca96..0f6a18c 100644
--- a/src/com/android/mail/utils/MimeType.java
+++ b/src/com/android/mail/utils/MimeType.java
@@ -43,7 +43,7 @@
     static final String GENERIC_MIMETYPE = "application/octet-stream";
 
     @VisibleForTesting
-    static final String EML_ATTACHMENT_CONTENT_TYPE = "application/eml";
+    public static final String EML_ATTACHMENT_CONTENT_TYPE = "message/rfc822";
     private static final String NULL_ATTACHMENT_CONTENT_TYPE = "null";
     private static final Set<String> UNACCEPTABLE_ATTACHMENT_TYPES = ImmutableSet.of(
             "application/zip", "application/x-gzip", "application/x-bzip2",
@@ -151,7 +151,7 @@
      * Returns the mime type of the attachment based on its name and
      * original mime type. This is an workaround for bugs where Gmail
      * server doesn't set content-type for certain types correctly.
-     * 1) EML files -> "application/eml".
+     * 1) EML files -> "message/rfc822".
      * @param name name of the attachment.
      * @param mimeType original mime type of the attachment.
      * @return the inferred mime type of the attachment.
@@ -174,7 +174,7 @@
             if (!TextUtils.isEmpty(type)) {
                 return type;
             } if (extension.equals("eml")) {
-                // Extension is ".eml", return mime type "application/eml"
+                // Extension is ".eml", return mime type "message/rfc822"
                 return EML_ATTACHMENT_CONTENT_TYPE;
             } else {
                 // Extension is not ".eml", just return original mime type.