"new message from" in conversation view on update

* put the New Message bar in a new floaty layer in
  ConversationContainer. snap header can also live here.
* add left/right margin support to ConversationContainer

Send/save of a new message also generates the 'new message'
notification for now.

Bug: 6384217
Change-Id: I10a40bbf87423194214e5ded08539abaaf7fd25c
diff --git a/src/com/android/mail/browse/ConversationContainer.java b/src/com/android/mail/browse/ConversationContainer.java
index 2d4fcf2..9ce1acc 100644
--- a/src/com/android/mail/browse/ConversationContainer.java
+++ b/src/com/android/mail/browse/ConversationContainer.java
@@ -35,6 +35,9 @@
 import com.android.mail.ui.ConversationViewFragment;
 import com.android.mail.utils.DequeMap;
 import com.android.mail.utils.LogUtils;
+import com.google.common.collect.Lists;
+
+import java.util.List;
 
 /**
  * A specialized ViewGroup container for conversation view. It is designed to contain a single
@@ -61,10 +64,21 @@
 
     private static final String TAG = ConversationViewFragment.LAYOUT_TAG;
 
+    private static final int[] BOTTOM_LAYER_VIEW_IDS = {
+        R.id.webview
+    };
+
+    private static final int[] TOP_LAYER_VIEW_IDS = {
+        R.id.conversation_topmost_overlay
+    };
+    private static final int TOP_LAYER_COUNT = TOP_LAYER_VIEW_IDS.length;
+
     private ConversationViewAdapter mOverlayAdapter;
     private int[] mOverlayBottoms;
     private ConversationWebView mWebView;
 
+    private final List<View> mNonScrollingChildren = Lists.newArrayList();
+
     /**
      * Current document zoom scale per {@link WebView#getScale()}. This is the ratio of actual
      * screen pixels to logical WebView HTML pixels. We use it to convert from one to the other.
@@ -178,6 +192,13 @@
 
         mWebView = (ConversationWebView) findViewById(R.id.webview);
         mWebView.addScrollListener(this);
+
+        for (int id : BOTTOM_LAYER_VIEW_IDS) {
+            mNonScrollingChildren.add(findViewById(id));
+        }
+        for (int id : TOP_LAYER_VIEW_IDS) {
+            mNonScrollingChildren.add(findViewById(id));
+        }
     }
 
     public void setOverlayAdapter(ConversationViewAdapter a) {
@@ -378,15 +399,13 @@
      * Copied/stolen from {@link ListView}.
      */
     private void measureOverlayView(View child) {
-        ViewGroup.LayoutParams p = child.getLayoutParams();
+        MarginLayoutParams p = (MarginLayoutParams) child.getLayoutParams();
         if (p == null) {
-            p = new ViewGroup.LayoutParams(
-                    ViewGroup.LayoutParams.MATCH_PARENT,
-                    ViewGroup.LayoutParams.WRAP_CONTENT);
+            p = (MarginLayoutParams) generateDefaultLayoutParams();
         }
 
         int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
-                getPaddingLeft() + getPaddingRight(), p.width);
+                getPaddingLeft() + getPaddingRight() + p.leftMargin + p.rightMargin, p.width);
         int lpHeight = p.height;
         int childHeightSpec;
         if (lpHeight > 0) {
@@ -455,8 +474,11 @@
                     MeasureSpec.toString(heightMeasureSpec));
         }
 
-        if (mWebView.getVisibility() != GONE) {
-            measureChild(mWebView, widthMeasureSpec, heightMeasureSpec);
+        for (View nonScrollingChild : mNonScrollingChildren) {
+            if (nonScrollingChild.getVisibility() != GONE) {
+                measureChildWithMargins(nonScrollingChild, widthMeasureSpec, 0 /* widthUsed */,
+                        heightMeasureSpec, 0 /* heightUsed */);
+            }
         }
         mWidthMeasureSpec = widthMeasureSpec;
 
@@ -468,7 +490,19 @@
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         LogUtils.d(TAG, "*** IN header container onLayout");
 
-        mWebView.layout(0, 0, mWebView.getMeasuredWidth(), mWebView.getMeasuredHeight());
+        for (View nonScrollingChild : mNonScrollingChildren) {
+            if (nonScrollingChild.getVisibility() != GONE) {
+                final int w = nonScrollingChild.getMeasuredWidth();
+                final int h = nonScrollingChild.getMeasuredHeight();
+
+                final MarginLayoutParams lp =
+                        (MarginLayoutParams) nonScrollingChild.getLayoutParams();
+
+                final int childLeft = lp.leftMargin;
+                final int childTop = lp.topMargin;
+                nonScrollingChild.layout(childLeft, childTop, childLeft + w, childTop + h);
+            }
+        }
 
         if (mOverlayAdapter != null) {
             // being in a layout pass means overlay children may require measurement,
@@ -481,6 +515,26 @@
         positionOverlays(0, mOffsetY);
     }
 
+    @Override
+    protected LayoutParams generateDefaultLayoutParams() {
+        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new MarginLayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return new MarginLayoutParams(p);
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof MarginLayoutParams;
+    }
+
     private int getOverlayBottom(int spacerIndex) {
         // TODO: round or truncate?
         return (int) (mOverlayBottoms[spacerIndex] * mScale);
@@ -528,7 +582,11 @@
     private void layoutOverlay(View child, int childTop, int childBottom) {
         final int top = childTop - mOffsetY;
         final int bottom = childBottom - mOffsetY;
-        child.layout(0, top, child.getMeasuredWidth(), bottom);
+
+        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+        final int childLeft = getPaddingLeft() + lp.leftMargin;
+
+        child.layout(childLeft, top, childLeft + child.getMeasuredWidth(), bottom);
     }
 
     private View addOverlayView(int adapterIndex) {
@@ -538,15 +596,17 @@
         View view = mOverlayAdapter.getView(adapterIndex, convertView, this);
         mOverlayViews.put(adapterIndex, new OverlayView(view, itemType));
 
+        final int index = getChildCount() - TOP_LAYER_COUNT;
+
         // Only re-attach if the view had previously been added to a view hierarchy.
         // Since external components can contribute to the scrap heap (addScrapView), we can't
         // assume scrap views had already been attached.
         if (view.getRootView() != view) {
             LogUtils.d(TAG, "want to REUSE scrolled-in view: index=%d obj=%s", adapterIndex, view);
-            attachViewToParent(view, -1, view.getLayoutParams());
+            attachViewToParent(view, index, view.getLayoutParams());
         } else {
             LogUtils.d(TAG, "want to CREATE scrolled-in view: index=%d obj=%s", adapterIndex, view);
-            addViewInLayout(view, -1, view.getLayoutParams(),
+            addViewInLayout(view, index, view.getLayoutParams(),
                     true /* preventRequestLayout */);
         }
 
@@ -565,7 +625,6 @@
         mOverlayBottoms = null;
     }
 
-    // TODO: add margin support for children that want it (e.g. tablet headers?)
     public void onGeometryChange(int[] overlayBottoms) {
         traceLayout("*** got overlay spacer bottoms:");
         for (int offsetY : overlayBottoms) {
diff --git a/src/com/android/mail/browse/MessageCursor.java b/src/com/android/mail/browse/MessageCursor.java
index fa19271..6b14d20 100644
--- a/src/com/android/mail/browse/MessageCursor.java
+++ b/src/com/android/mail/browse/MessageCursor.java
@@ -19,11 +19,14 @@
 
 import android.database.Cursor;
 import android.database.CursorWrapper;
+import android.os.Bundle;
 import android.os.Parcelable;
 
 import com.android.mail.providers.Conversation;
 import com.android.mail.providers.Message;
 import com.android.mail.providers.UIProvider;
+import com.android.mail.providers.UIProvider.CursorExtraKeys;
+import com.android.mail.providers.UIProvider.CursorStatus;
 import com.android.mail.ui.ConversationUpdater;
 import com.google.common.collect.Maps;
 
@@ -39,6 +42,8 @@
     private final Conversation mConversation;
     private final ConversationUpdater mListController;
 
+    private Integer mStatus;
+
     /**
      * A message created as part of a conversation view. Sometimes, like during star/unstar, it's
      * handy to have the owning {@link MessageCursor} and {@link Conversation} for context.
@@ -100,4 +105,35 @@
         return false;
     }
 
+    public int getStatus() {
+        if (mStatus != null) {
+            return mStatus;
+        }
+
+        mStatus = CursorStatus.LOADED;
+        final Bundle extras = getExtras();
+        if (extras != null && extras.containsKey(CursorExtraKeys.EXTRA_STATUS)) {
+            mStatus = extras.getInt(CursorExtraKeys.EXTRA_STATUS);
+        }
+        return mStatus;
+    }
+
+    public boolean isLoaded() {
+        return getStatus() >= CursorStatus.LOADED || getCount() > 0; // FIXME: remove count hack
+    }
+
+    public String getDebugDump() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(String.format("conv subj='%s' status=%d messages:\n",
+                mConversation.subject, getStatus()));
+        int pos = -1;
+        while (moveToPosition(++pos)) {
+            final Message m = getMessage();
+            sb.append(String.format(
+                    "[Message #%d uri=%s id=%d serverId=%d, from='%s' draftType=%d isSending=%s]\n",
+                    pos, m.uri, m.id, m.serverId, m.from, m.draftType, m.isSending));
+        }
+        return sb.toString();
+    }
+
 }
\ No newline at end of file
diff --git a/src/com/android/mail/providers/Message.java b/src/com/android/mail/providers/Message.java
index 39fc6aa..11889b4 100644
--- a/src/com/android/mail/providers/Message.java
+++ b/src/com/android/mail/providers/Message.java
@@ -169,6 +169,10 @@
      * @see UIProvider.MessageColumns#VIA_DOMAIN
      */
     public String viaDomain;
+    /**
+     * @see UIProvider.MessageColumns#IS_SENDING
+     */
+    public boolean isSending;
 
     private transient String[] mFromAddresses = null;
     private transient String[] mToAddresses = null;
@@ -234,6 +238,7 @@
         dest.writeInt(spamWarningLevel);
         dest.writeInt(spamLinkType);
         dest.writeString(viaDomain);
+        dest.writeInt(isSending ? 1 : 0);
     }
 
     private Message(Parcel in) {
@@ -269,6 +274,7 @@
         spamWarningLevel = in.readInt();
         spamLinkType = in.readInt();
         viaDomain = in.readString();
+        isSending = in.readInt() != 0;
     }
 
     public Message() {
@@ -342,6 +348,7 @@
             spamWarningLevel = cursor.getInt(UIProvider.MESSAGE_SPAM_WARNING_LEVEL_COLUMN);
             spamLinkType = cursor.getInt(UIProvider.MESSAGE_SPAM_WARNING_LINK_TYPE_COLUMN);
             viaDomain = cursor.getString(UIProvider.MESSAGE_VIA_DOMAIN_COLUMN);
+            isSending = cursor.getInt(UIProvider.MESSAGE_IS_SENDING_COLUMN) != 0;
         }
     }
 
diff --git a/src/com/android/mail/providers/UIProvider.java b/src/com/android/mail/providers/UIProvider.java
index 7d5d506..eb1c7b5 100644
--- a/src/com/android/mail/providers/UIProvider.java
+++ b/src/com/android/mail/providers/UIProvider.java
@@ -1101,7 +1101,8 @@
         MessageColumns.SPAM_WARNING_STRING,
         MessageColumns.SPAM_WARNING_LEVEL,
         MessageColumns.SPAM_WARNING_LINK_TYPE,
-        MessageColumns.VIA_DOMAIN
+        MessageColumns.VIA_DOMAIN,
+        MessageColumns.IS_SENDING
     };
 
     /** Separates attachment info parts in strings in a message. */
@@ -1148,6 +1149,7 @@
     public static final int MESSAGE_SPAM_WARNING_LEVEL_COLUMN = 33;
     public static final int MESSAGE_SPAM_WARNING_LINK_TYPE_COLUMN = 34;
     public static final int MESSAGE_VIA_DOMAIN_COLUMN = 35;
+    public static final int MESSAGE_IS_SENDING_COLUMN = 36;
 
     public static final class CursorStatus {
         // The cursor is actively loading more data
@@ -1194,9 +1196,9 @@
 
 
     public static final class MessageFlags {
-        public static final int REPLIED =       1 << 2;
-        public static final int FORWARDED =     1 << 3;
-        public static final int CALENDAR_INVITE =     1 << 4;
+        public static final int REPLIED =           1 << 2;
+        public static final int FORWARDED =         1 << 3;
+        public static final int CALENDAR_INVITE =   1 << 4;
     }
 
     public static final class MessageColumns {
@@ -1364,6 +1366,11 @@
          * domain. This column should be null if no via domain exists.
          */
         public static final String VIA_DOMAIN = "viaDomain";
+        /**
+         * This boolean column indicates whether the message is an outgoing message in the process
+         * of being sent (will be zero for incoming messages and messages that are already sent).
+         */
+        public static final String IS_SENDING = "isSending";
 
         private MessageColumns() {}
     }
diff --git a/src/com/android/mail/ui/ConversationViewFragment.java b/src/com/android/mail/ui/ConversationViewFragment.java
index 70149c7..047c934 100644
--- a/src/com/android/mail/ui/ConversationViewFragment.java
+++ b/src/com/android/mail/ui/ConversationViewFragment.java
@@ -32,6 +32,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.provider.Browser;
+import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -43,6 +44,7 @@
 import android.webkit.WebSettings;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
+import android.widget.TextView;
 
 import com.android.mail.ContactInfo;
 import com.android.mail.ContactInfoSource;
@@ -113,6 +115,8 @@
 
     private ConversationWebView mWebView;
 
+    private View mNewMessageBar;
+
     private HtmlConversationTemplates mTemplates;
 
     private String mBaseUri;
@@ -125,6 +129,7 @@
 
     private ConversationViewAdapter mAdapter;
     private MessageCursor mCursor;
+    private MessageCursor mPendingCursor;
 
     private boolean mViewsCreated;
 
@@ -173,6 +178,7 @@
     private static final String BUNDLE_VIEW_STATE = "viewstate";
 
     private static final boolean DEBUG_DUMP_CONVERSATION_HTML = false;
+    private static final boolean DISABLE_OFFSCREEN_LOADING = false;
 
     /**
      * Constructor needs to be public to handle orientation changes and activity lifecycle events.
@@ -264,6 +270,15 @@
         View rootView = inflater.inflate(R.layout.conversation_view, container, false);
         mConversationContainer = (ConversationContainer) rootView
                 .findViewById(R.id.conversation_container);
+
+        mNewMessageBar = mConversationContainer.findViewById(R.id.new_message_notification_bar);
+        mNewMessageBar.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                onNewMessageBarClick();
+            }
+        });
+
         mWebView = (ConversationWebView) mConversationContainer.findViewById(R.id.webview);
 
         mWebView.addJavascriptInterface(mJsBridge, "mail");
@@ -445,7 +460,9 @@
      * a folder. This will initiate a data load, and hence must be called on the UI thread.
      */
     private void showConversation() {
-        if (!mUserVisible && mConversation.getNumMessages() > mMaxAutoLoadMessages) {
+        final boolean disableOffscreenLoading = DISABLE_OFFSCREEN_LOADING
+                || (mConversation.getNumMessages() > mMaxAutoLoadMessages);
+        if (!mUserVisible && disableOffscreenLoading) {
             LogUtils.v(LOG_TAG, "Fragment not user-visible, not showing conversation: %s",
                     mConversation.uri);
             mDeferredConversationLoad = true;
@@ -513,6 +530,11 @@
 
         mAdapter.clear();
 
+        // re-evaluate the message parts of the view state, since the messages may have changed
+        // since the previous render
+        final ConversationViewState prevState = mViewState;
+        mViewState = new ConversationViewState(prevState);
+
         // N.B. the units of height for spacers are actually dp and not px because WebView assumes
         // a pixel is an mdpi pixel, unless you set device-dpi.
 
@@ -533,10 +555,11 @@
             final boolean safeForImages = msg.alwaysShowImages /* || savedStateSaysSafe */;
             allowNetworkImages |= safeForImages;
 
-            final Boolean savedExpanded = mViewState.getExpandedState(msg);
+            final Boolean savedExpanded = prevState.getExpandedState(msg);
             final boolean expanded;
             if (savedExpanded != null) {
                 expanded = savedExpanded;
+                mViewState.setExpandedState(msg, expanded);
             } else {
                 expanded = !msg.read || msg.starred || messageCursor.isLast();
             }
@@ -772,6 +795,20 @@
         mWebView.loadUrl("javascript:replaceSuperCollapsedBlock(" + item.getStart() + ")");
     }
 
+    private void showNewMessageNotification(NewMessagesInfo info) {
+        final TextView descriptionView = (TextView) mNewMessageBar.findViewById(
+                R.id.new_message_description);
+        descriptionView.setText(info.getNotificationText());
+        mNewMessageBar.setVisibility(View.VISIBLE);
+    }
+
+    private void onNewMessageBarClick() {
+        mNewMessageBar.setVisibility(View.GONE);
+
+        renderConversation(mPendingCursor);
+        mPendingCursor = null;
+    }
+
     private static class MessageLoader extends CursorLoader {
         private boolean mDeliveredFirstResults = false;
         private final Conversation mConversation;
@@ -819,6 +856,16 @@
         return ints;
     }
 
+    @Override
+    public String toString() {
+        // log extra info at DEBUG level or finer
+        final String s = super.toString();
+        if (!LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG) || mConversation == null) {
+            return s;
+        }
+        return "(" + s + " subj=" + mConversation.subject + ")";
+    }
+
     private class ConversationWebViewClient extends WebViewClient {
 
         @Override
@@ -831,8 +878,8 @@
                 return;
             }
 
-            LogUtils.i(LOG_TAG, "IN CVF.onPageFinished, url=%s fragment=%s", url,
-                    ConversationViewFragment.this);
+            LogUtils.i(LOG_TAG, "IN CVF.onPageFinished, url=%s fragment=%s act=%s", url,
+                    ConversationViewFragment.this, getActivity());
 
             super.onPageFinished(view, url);
 
@@ -926,6 +973,32 @@
 
     }
 
+    private class NewMessagesInfo {
+        int count;
+        String senderAddress;
+
+        /**
+         * Return the display text for the new message notification overlay. It will be formatted
+         * appropriately for a single new message vs. multiple new messages.
+         *
+         * @return display text
+         */
+        public String getNotificationText() {
+            final Object param;
+            if (count > 1) {
+                param = count;
+            } else {
+                Address addr = mAddressCache.get(senderAddress);
+                if (addr == null) {
+                    addr = Address.getEmailAddress(senderAddress);
+                    mAddressCache.put(senderAddress, addr);
+                }
+                param = TextUtils.isEmpty(addr.getName()) ? addr.getAddress() : addr.getName();
+            }
+            return getResources().getQuantityString(R.plurals.new_incoming_messages, count, param);
+        }
+    }
+
     private class MessageLoaderCallbacks implements LoaderManager.LoaderCallbacks<Cursor> {
 
         @Override
@@ -943,22 +1016,54 @@
                 return;
             }
 
-            // TODO: handle Gmail loading states (like LOADING and ERROR)
-            if (messageCursor.getCount() == 0) {
-                if (mCursor != null) {
-                    // TODO: need to exit this view- conversation may have been deleted, or for
-                    // whatever reason is now invalid
-                } else {
-                    // ignore zero-sized cursors during initial load
-                }
+            if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) {
+                LogUtils.d(LOG_TAG, "LOADED CONVERSATION= %s", messageCursor.getDebugDump());
+            }
+
+            // ignore cursors that are still loading results
+            if (!messageCursor.isLoaded()) {
                 return;
             }
 
+            // TODO: handle ERROR status
+
+            if (messageCursor.getCount() == 0 && mCursor != null) {
+                // TODO: need to exit this view- conversation may have been deleted, or for
+                // whatever reason is now invalid (e.g. discard single draft)
+                return;
+            }
+
+            if (mCursor != null) {
+                final NewMessagesInfo info = getNewIncomingMessagesInfo(messageCursor);
+
+                if (info.count > 0) {
+                    // don't immediately render new incoming messages from other senders
+                    // (to avoid a new message from losing the user's focus)
+                    //
+                    // hold the new cursor as pending for later render
+                    mPendingCursor = messageCursor;
+                    LogUtils.i(LOG_TAG,
+                            "conversation updated, holding cursor for new incoming message");
+
+                    showNewMessageNotification(info);
+
+                    return;
+                }
+            }
+
+            if (mCursor == null) {
+                LogUtils.i(LOG_TAG, "existing cursor is null, rendering from scratch");
+            } else {
+                // re-render?
+                // or render just those messages that changed?
+                LogUtils.i(LOG_TAG,
+                        "conversation updated, but not due to incoming message. rendering.");
+            }
+            renderConversation(messageCursor);
+
             // TODO: if this is not user-visible, delay render until user-visible fragment is done.
             // This is needed in addition to the showConversation() delay to speed up rotation and
             // restoration.
-
-            renderConversation(messageCursor);
         }
 
         @Override
@@ -967,6 +1072,22 @@
             // TODO: null out all Message.mMessageCursor references
         }
 
+        private NewMessagesInfo getNewIncomingMessagesInfo(MessageCursor newCursor) {
+            final NewMessagesInfo info = new NewMessagesInfo();
+
+            int pos = -1;
+            while (newCursor.moveToPosition(++pos)) {
+                final Message m = newCursor.getMessage();
+                if (!mViewState.contains(m)) {
+                    LogUtils.i(LOG_TAG, "conversation diff: found new msg: %s", m.uri);
+                    // TODO: distinguish ours from theirs
+                    info.count++;
+                    info.senderAddress = m.from;
+                }
+            }
+            return info;
+        }
+
     }
 
     /**
diff --git a/src/com/android/mail/ui/ConversationViewState.java b/src/com/android/mail/ui/ConversationViewState.java
index 500d19c..f5795dc 100644
--- a/src/com/android/mail/ui/ConversationViewState.java
+++ b/src/com/android/mail/ui/ConversationViewState.java
@@ -47,6 +47,13 @@
 
     public ConversationViewState() {}
 
+    /**
+     * Copy constructor that will copy overall conversation state, but NOT individual message state.
+     */
+    public ConversationViewState(ConversationViewState other) {
+        mConversationInfo = other.mConversationInfo;
+    }
+
     public boolean isUnread(Message m) {
         final MessageViewState mvs = mMessageViewStates.get(m.uri);
         return (mvs != null && !mvs.read);
@@ -107,6 +114,10 @@
         return result;
     }
 
+    public boolean contains(Message m) {
+        return mMessageViewStates.containsKey(m.uri);
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/src/com/android/mail/ui/TwoPaneLayout.java b/src/com/android/mail/ui/TwoPaneLayout.java
index e6f937a..b9077c7 100644
--- a/src/com/android/mail/ui/TwoPaneLayout.java
+++ b/src/com/android/mail/ui/TwoPaneLayout.java
@@ -99,7 +99,6 @@
     private View mConversationListContainer;
 
     private View mConversationView;
-    private View mConversationViewOverlay;
     /** Left position of each fragment. */
     private int mFoldersLeft;
     private View mFoldersView;
@@ -485,7 +484,6 @@
         mConversationListContainer = findViewById(R.id.conversation_column_container);
         mListView = findViewById(R.id.conversation_list);
         mConversationView = findViewById(R.id.conversation_pane_container);
-        mConversationViewOverlay = findViewById(R.id.conversation_overlay);
 
         sAnimationSlideLeftDuration = res.getInteger(R.integer.activity_slide_left_duration);
         sAnimationSlideRightDuration = res.getInteger(R.integer.activity_slide_right_duration);
@@ -531,7 +529,6 @@
      */
     private void onFinishEnteringConversationListMode() {
         mConversationView.setVisibility(View.GONE);
-        mConversationViewOverlay.setVisibility(View.GONE);
         mFoldersView.setVisibility(View.VISIBLE);
 
         // Once animations settle, the conversation list always takes up the