Merge "Remove more unused resources" into jb-ub-mail-ur10
diff --git a/assets/script.js b/assets/script.js
index b30305a..0449d00 100644
--- a/assets/script.js
+++ b/assets/script.js
@@ -592,7 +592,7 @@
     }
     // add an extra one to mark the top/bottom of the last message footer spacer
     overlayTops[i] = "" + prevBodyBottom;
-    overlayBottoms[i] = "" + document.body.offsetHeight;
+    overlayBottoms[i] = "" + document.documentElement.scrollHeight;
 
     window.mail.onWebContentGeometryChange(overlayTops, overlayBottoms);
 }
diff --git a/res/drawable-hdpi/snap_header_gradient.9.png b/res/drawable-hdpi/snap_header_gradient.9.png
index 08d4ff1..1216021 100644
--- a/res/drawable-hdpi/snap_header_gradient.9.png
+++ b/res/drawable-hdpi/snap_header_gradient.9.png
Binary files differ
diff --git a/res/drawable-mdpi/snap_header_gradient.9.png b/res/drawable-mdpi/snap_header_gradient.9.png
index f847fb7..288e677 100644
--- a/res/drawable-mdpi/snap_header_gradient.9.png
+++ b/res/drawable-mdpi/snap_header_gradient.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/snap_header_gradient.9.png b/res/drawable-xhdpi/snap_header_gradient.9.png
index 05a2af8..135c10d 100644
--- a/res/drawable-xhdpi/snap_header_gradient.9.png
+++ b/res/drawable-xhdpi/snap_header_gradient.9.png
Binary files differ
diff --git a/res/layout/conversation_outbox_tip_view.xml b/res/layout/conversation_outbox_tip_view.xml
new file mode 100644
index 0000000..8a1951f
--- /dev/null
+++ b/res/layout/conversation_outbox_tip_view.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2013 Google Inc. -->
+<com.android.mail.ui.ConversationsInOutboxTipView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@color/swiped_bg_color" >
+
+    <LinearLayout
+        android:id="@+id/swipeable_content"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@drawable/conversation_read_selector"
+        android:orientation="horizontal" >
+
+        <TextView
+            android:id="@+id/outbox"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginBottom="12dp"
+            android:layout_marginTop="12dp"
+            android:layout_marginLeft="16dp"
+            android:layout_marginStart="16dp"
+            android:layout_weight="1"
+            android:duplicateParentState="true"
+            android:fontFamily="sans-serif-light"
+            android:textColor="@color/teaser_main_text"
+            android:textSize="16sp" />
+
+        <View
+            android:id="@+id/dismiss_separator"
+            android:layout_width="1dip"
+            android:layout_height="match_parent"
+            android:background="@color/teaser_main_text"
+            android:layout_marginTop="16dp"
+            android:layout_marginBottom="16dp"
+            android:layout_marginLeft="16dp"
+            android:layout_marginStart="16dp" />
+
+        <ImageButton
+            android:id="@+id/dismiss_button"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:background="?android:attr/selectableItemBackground"
+            android:clickable="true"
+            android:paddingLeft="20dip"
+            android:paddingStart="20dip"
+            android:paddingRight="28dip"
+            android:paddingEnd="28dip"
+            android:scaleType="center"
+            android:contentDescription="@string/dismiss_tip_hover_text"
+            android:src="@drawable/ic_cancel_holo_light" />
+    </LinearLayout>
+
+</com.android.mail.ui.ConversationsInOutboxTipView>
diff --git a/res/layout/conversation_pager.xml b/res/layout/conversation_pager.xml
index 623d35d..a85ece6 100644
--- a/res/layout/conversation_pager.xml
+++ b/res/layout/conversation_pager.xml
@@ -22,14 +22,4 @@
     android:layout_height="match_parent"
     android:visibility="gone">
 
-    <android.support.v4.view.PagerTitleStrip
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom"
-        android:paddingLeft="16dp"
-        android:paddingRight="16dp"
-        android:textAppearance="?android:attr/textAppearanceSmallInverse"
-        android:includeFontPadding="false"
-        android:background="@color/position_bar_background" />
-
 </com.android.mail.browse.ConversationPager>
\ No newline at end of file
diff --git a/res/values/dimen.xml b/res/values/dimen.xml
index 0ca763c..28fe4f4 100644
--- a/res/values/dimen.xml
+++ b/res/values/dimen.xml
@@ -90,8 +90,6 @@
     <dimen name="widget_margin_right">0dip</dimen>
     <dimen name="widget_margin_bottom">0dip</dimen>
     <dimen name="search_view_width">400dip</dimen>
-    <dimen name="toast_bar_bottom_margin">4dip</dimen>
-    <dimen name="toast_bar_bottom_margin_in_conversation">24dip</dimen>
     <dimen name="wait_padding">16dp</dimen>
     <integer name="chips_max_lines">2</integer>
     <dimen name="tile_letter_font_size">33dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 20c2108..0128e4f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -939,4 +939,9 @@
     <!-- This is used as a parameter to another string and combined reads
          "Turn on in Account settings." [CHAR LIMIT=250] -->
     <string name="account_settings_param">Account settings</string>
+
+    <!-- Hint text that there are X number of unsent messages users
+    Outbox. [CHAR LIMIT=250] -->
+    <string name="unsent_messages_in_outbox"><xliff:g id="number">%1$s</xliff:g>
+    unsent in <xliff:g id="outbox">%2$s</xliff:g></string>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index f33247a..c354d3a 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -396,6 +396,7 @@
         <item name="android:layout_gravity">bottom</item>
         <item name="android:layout_marginLeft">4dip</item>
         <item name="android:layout_marginRight">4dip</item>
+        <item name="android:layout_marginBottom">4dip</item>
         <item name="android:orientation">horizontal</item>
         <item name="android:gravity">center_vertical</item>
         <item name="android:background">@drawable/panel_undo_holo</item>
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 7ae9534..b6e8af4 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -590,6 +590,11 @@
                 // reset the grid, as the newly bound item may have a different attachment count
                 mAttachmentsView.setCount(0);
             }
+
+            if (header.conversation.id != mHeader.conversation.id) {
+                // Stop the photo flip animation
+                mPhotoFlipAnimator.stopAnimation();
+            }
         }
         mCoordinates = null;
         mHeader = header;
diff --git a/src/com/android/mail/browse/ConversationPagerAdapter.java b/src/com/android/mail/browse/ConversationPagerAdapter.java
index e3b5712..70620b4 100644
--- a/src/com/android/mail/browse/ConversationPagerAdapter.java
+++ b/src/com/android/mail/browse/ConversationPagerAdapter.java
@@ -27,7 +27,6 @@
 import android.support.v4.view.ViewPager;
 import android.view.ViewGroup;
 
-import com.android.mail.R;
 import com.android.mail.providers.Account;
 import com.android.mail.providers.Conversation;
 import com.android.mail.providers.Folder;
@@ -242,29 +241,6 @@
     }
 
     @Override
-    public CharSequence getPageTitle(int position) {
-        final String title;
-        final int currentPosition = mPager.getCurrentItem();
-        final Cursor cursor = getCursor();
-        if (isPagingDisabled(cursor)) {
-            title = null;
-        } else if (position == currentPosition) {
-            int total = getCount();
-            if (mController != null) {
-                final Folder f = mController.getFolder();
-                if (f != null && f.totalCount > total) {
-                    total = f.totalCount;
-                }
-            }
-            title = mResources.getString(R.string.conversation_count, position + 1, total);
-        } else {
-            title = mResources.getString(position < currentPosition ?
-                    R.string.conversation_newer : R.string.conversation_older);
-        }
-        return title;
-    }
-
-    @Override
     public Parcelable saveState() {
         LogUtils.d(LOG_TAG, "IN PagerAdapter.saveState. this=%s", this);
         Bundle state = (Bundle) super.saveState(); // superclass uses a Bundle
diff --git a/src/com/android/mail/preferences/AccountPreferences.java b/src/com/android/mail/preferences/AccountPreferences.java
index 7746330..b71b212 100644
--- a/src/com/android/mail/preferences/AccountPreferences.java
+++ b/src/com/android/mail/preferences/AccountPreferences.java
@@ -48,6 +48,11 @@
          */
         public static final String ACCOUNT_SYNC_OFF_DISMISSES = "num-of-dismisses-account-sync-off";
 
+        /**
+         * The count reported last time the "X unseen in Outbox" tip was displayed.
+         */
+        public static final String LAST_SEEN_OUTBOX_COUNT = "last-seen-outbox-count";
+
         public static final ImmutableSet<String> BACKUP_KEYS =
                 new ImmutableSet.Builder<String>().add(NOTIFICATIONS_ENABLED).build();
     }
@@ -128,4 +133,12 @@
                 PreferenceKeys.ACCOUNT_SYNC_OFF_DISMISSES, 0);
         getEditor().putInt(PreferenceKeys.ACCOUNT_SYNC_OFF_DISMISSES, value + 1).apply();
     }
+
+    public int getLastSeenOutboxCount() {
+        return getSharedPreferences().getInt(PreferenceKeys.LAST_SEEN_OUTBOX_COUNT, 0);
+    }
+
+    public void setLastSeenOutboxCount(final int count) {
+        getEditor().putInt(PreferenceKeys.LAST_SEEN_OUTBOX_COUNT, count).apply();
+    }
 }
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 43bcd74..edc1e33 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -3850,7 +3850,6 @@
      * @param replaceVisibleToast if true, this should replace any currently visible toast.
      */
     protected final void showErrorToast(final Folder folder, boolean replaceVisibleToast) {
-        mToastBar.setConversationMode(false);
 
         final ActionClickedListener listener;
         final int actionTextResourceId;
diff --git a/src/com/android/mail/ui/ActionableToastBar.java b/src/com/android/mail/ui/ActionableToastBar.java
index 4cdcd20..5beade7 100644
--- a/src/com/android/mail/ui/ActionableToastBar.java
+++ b/src/com/android/mail/ui/ActionableToastBar.java
@@ -23,7 +23,6 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -39,8 +38,6 @@
     private Animator mHideAnimation;
     private final Runnable mRunnable;
     private final Handler mFadeOutHandler;
-    private final int mBottomMarginSizeInConversation;
-    private final int mBottomMarginSize;
 
     /** How long toast will last in ms */
     private static final long TOAST_LIFETIME = 15*1000L;
@@ -76,10 +73,6 @@
                 }
             }
         };
-        mBottomMarginSize = context.getResources()
-                .getDimensionPixelSize(R.dimen.toast_bar_bottom_margin);
-        mBottomMarginSizeInConversation = context.getResources().getDimensionPixelSize(
-                R.dimen.toast_bar_bottom_margin_in_conversation);
         LayoutInflater.from(context).inflate(R.layout.actionable_toast_row, this, true);
     }
 
@@ -95,18 +88,6 @@
     }
 
     /**
-     * Tells the view that it will be appearing in the conversation pane
-     * and should adjust its layout parameters accordingly.
-     * @param isInConversationMode true if the view will be shown in the conversation view
-     */
-    public void setConversationMode(boolean isInConversationMode) {
-        final FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
-        params.bottomMargin = isInConversationMode ? mBottomMarginSizeInConversation
-                : mBottomMarginSize;
-        setLayoutParams(params);
-    }
-
-    /**
      * Displays the toast bar and makes it visible. Allows the setting of
      * parameters to customize the display.
      * @param listener Performs some action when the action button is clicked.
diff --git a/src/com/android/mail/ui/ConversationListHelper.java b/src/com/android/mail/ui/ConversationListHelper.java
index 6f93f4e..aa2a122 100644
--- a/src/com/android/mail/ui/ConversationListHelper.java
+++ b/src/com/android/mail/ui/ConversationListHelper.java
@@ -33,27 +33,35 @@
      */
     public ArrayList<ConversationSpecialItemView> makeConversationListSpecialViews(
             final Context context, final ControllableActivity activity, final Account account) {
+        final ConversationSyncDisabledTipView conversationSyncDisabledTipView =
+                (ConversationSyncDisabledTipView) LayoutInflater.from(context)
+                        .inflate(R.layout.conversation_sync_disabled_tip_view, null);
+        conversationSyncDisabledTipView.bindAccount(account);
+
+        final ConversationsInOutboxTipView conversationsInOutboxTipView =
+                (ConversationsInOutboxTipView) LayoutInflater.from(context)
+                        .inflate(R.layout.conversation_outbox_tip_view, null);
+        conversationsInOutboxTipView.bind(account, activity.getFolderSelector());
+
         // Conversation photo teaser view
         final ConversationPhotoTeaserView conversationPhotoTeaser =
                 (ConversationPhotoTeaserView) LayoutInflater.from(context)
                         .inflate(R.layout.conversation_photo_teaser_view, null);
 
-
         // Long press to select tip
         final ConversationLongPressTipView conversationLongPressTipView =
                 (ConversationLongPressTipView) LayoutInflater.from(context)
                         .inflate(R.layout.conversation_long_press_to_select_tip_view, null);
 
-        // Sync is off warning tip
-        final ConversationSyncDisabledTipView conversationSyncDisabledTipView =
-                (ConversationSyncDisabledTipView) LayoutInflater.from(context)
-                        .inflate(R.layout.conversation_sync_disabled_tip_view, null);
-        conversationSyncDisabledTipView.bindAccount(account);
-
+        // Order matters.  If a and b are added in order itemViews.add(a), itemViews.add(b),
+        // they will appear in conversation list as:
+        // b
+        // a
         final ArrayList<ConversationSpecialItemView> itemViews = Lists.newArrayList();
         itemViews.add(conversationPhotoTeaser);
         itemViews.add(conversationLongPressTipView);
         itemViews.add(conversationSyncDisabledTipView);
+        itemViews.add(conversationsInOutboxTipView);
         return itemViews;
     }
 }
diff --git a/src/com/android/mail/ui/ConversationLongPressTipView.java b/src/com/android/mail/ui/ConversationLongPressTipView.java
index a6f5f7b..ee7d67c 100644
--- a/src/com/android/mail/ui/ConversationLongPressTipView.java
+++ b/src/com/android/mail/ui/ConversationLongPressTipView.java
@@ -22,7 +22,9 @@
 import com.android.mail.preferences.MailPrefs;
 import com.android.mail.providers.Folder;
 
+import android.animation.Animator;
 import android.animation.ObjectAnimator;
+import android.animation.Animator.AnimatorListener;
 import android.app.LoaderManager;
 import android.content.Context;
 import android.content.res.Resources;
@@ -112,8 +114,7 @@
     @Override
     public int getPosition() {
         // We want this teaser to go before the first real conversation
-        // If another teaser wants position 0, we will want position 1
-        return mAdapter.getPositionOffset(0);
+        return 0;
     }
 
     @Override
@@ -191,6 +192,28 @@
                 ObjectAnimator.ofInt(this, "animatedHeight", start, end);
         heightAnimator.setInterpolator(new DecelerateInterpolator(2.0f));
         heightAnimator.setDuration(sShrinkAnimationDuration);
+        heightAnimator.addListener(new AnimatorListener() {
+            @Override
+            public void onAnimationStart(final Animator animation) {
+                // Do nothing
+            }
+
+            @Override
+            public void onAnimationRepeat(final Animator animation) {
+                // Do nothing
+            }
+
+            @Override
+            public void onAnimationEnd(final Animator animation) {
+                // We should no longer exist, so notify the adapter
+                mAdapter.notifyDataSetChanged();
+            }
+
+            @Override
+            public void onAnimationCancel(final Animator animation) {
+                // Do nothing
+            }
+        });
         heightAnimator.start();
     }
 
diff --git a/src/com/android/mail/ui/ConversationPhotoTeaserView.java b/src/com/android/mail/ui/ConversationPhotoTeaserView.java
index 84e6bc1..c358028 100644
--- a/src/com/android/mail/ui/ConversationPhotoTeaserView.java
+++ b/src/com/android/mail/ui/ConversationPhotoTeaserView.java
@@ -1,6 +1,8 @@
 package com.android.mail.ui;
 
+import android.animation.Animator;
 import android.animation.ObjectAnimator;
+import android.animation.Animator.AnimatorListener;
 import android.app.LoaderManager;
 import android.content.Context;
 import android.content.res.Resources;
@@ -203,6 +205,28 @@
                 ObjectAnimator.ofInt(this, "animatedHeight", start, end);
         heightAnimator.setInterpolator(new DecelerateInterpolator(2.0f));
         heightAnimator.setDuration(sShrinkAnimationDuration);
+        heightAnimator.addListener(new AnimatorListener() {
+            @Override
+            public void onAnimationStart(final Animator animation) {
+                // Do nothing
+            }
+
+            @Override
+            public void onAnimationRepeat(final Animator animation) {
+                // Do nothing
+            }
+
+            @Override
+            public void onAnimationEnd(final Animator animation) {
+                // We should no longer exist, so notify the adapter
+                mAdapter.notifyDataSetChanged();
+            }
+
+            @Override
+            public void onAnimationCancel(final Animator animation) {
+                // Do nothing
+            }
+        });
         heightAnimator.start();
     }
 
diff --git a/src/com/android/mail/ui/ConversationSyncDisabledTipView.java b/src/com/android/mail/ui/ConversationSyncDisabledTipView.java
index f462b06..1203e4e 100644
--- a/src/com/android/mail/ui/ConversationSyncDisabledTipView.java
+++ b/src/com/android/mail/ui/ConversationSyncDisabledTipView.java
@@ -16,7 +16,9 @@
 
 package com.android.mail.ui;
 
+import android.animation.Animator;
 import android.animation.ObjectAnimator;
+import android.animation.Animator.AnimatorListener;
 import android.app.LoaderManager;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -267,8 +269,7 @@
     @Override
     public int getPosition() {
         // We want this teaser to go before the first real conversation
-        // If another teaser wants position 0, we will want position 1
-        return mAdapter.getPositionOffset(0);
+        return 0;
     }
 
     @Override
@@ -291,7 +292,6 @@
 
     @Override
     public void onCabModeEntered() {
-        dismiss();
     }
 
     @Override
@@ -351,6 +351,28 @@
                 ObjectAnimator.ofInt(this, "animatedHeight", start, end);
         heightAnimator.setInterpolator(new DecelerateInterpolator(2.0f));
         heightAnimator.setDuration(sShrinkAnimationDuration);
+        heightAnimator.addListener(new AnimatorListener() {
+            @Override
+            public void onAnimationStart(final Animator animation) {
+                // Do nothing
+            }
+
+            @Override
+            public void onAnimationRepeat(final Animator animation) {
+                // Do nothing
+            }
+
+            @Override
+            public void onAnimationEnd(final Animator animation) {
+                // We should no longer exist, so notify the adapter
+                mAdapter.notifyDataSetChanged();
+            }
+
+            @Override
+            public void onAnimationCancel(final Animator animation) {
+                // Do nothing
+            }
+        });
         heightAnimator.start();
     }
 
diff --git a/src/com/android/mail/ui/ConversationsInOutboxTipView.java b/src/com/android/mail/ui/ConversationsInOutboxTipView.java
new file mode 100644
index 0000000..fb492c1
--- /dev/null
+++ b/src/com/android/mail/ui/ConversationsInOutboxTipView.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mail.ui;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.Animator.AnimatorListener;
+import android.app.LoaderManager;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.Context;
+import android.content.Loader;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.text.SpannableString;
+import android.text.style.TextAppearanceSpan;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import com.android.mail.R;
+import com.android.mail.browse.ConversationCursor;
+import com.android.mail.content.ObjectCursor;
+import com.android.mail.content.ObjectCursorLoader;
+import com.android.mail.preferences.AccountPreferences;
+import com.android.mail.providers.Account;
+import com.android.mail.providers.Folder;
+import com.android.mail.providers.UIProvider;
+
+/**
+ * Tip that is displayed in conversation list of 'Sent' folder whenever there are
+ * one or more messages in the Outbox.
+ */
+public class ConversationsInOutboxTipView extends FrameLayout
+        implements ConversationSpecialItemView, SwipeableItemView {
+
+    private static int sScrollSlop = 0;
+    private static int sShrinkAnimationDuration;
+
+    private Account mAccount = null;
+    private AccountPreferences mAccountPreferences;
+    private AnimatedAdapter mAdapter;
+    private LoaderManager mLoaderManager;
+    private FolderSelector mFolderSelector;
+    private Folder mOutbox;
+    private int mOutboxCount = -1;
+
+    private View mSwipeableContent;
+    private TextView mText;
+
+    private int mAnimatedHeight = -1;
+
+    private static final int LOADER_FOLDER_LIST =
+            AbstractActivityController.LAST_FRAGMENT_LOADER_ID + 100;
+
+    public ConversationsInOutboxTipView(final Context context) {
+        this(context, null);
+    }
+
+    public ConversationsInOutboxTipView(final Context context, final AttributeSet attrs) {
+        this(context, attrs, -1);
+    }
+
+    public ConversationsInOutboxTipView(
+            final Context context, final AttributeSet attrs, final int defStyle) {
+        super(context, attrs, defStyle);
+
+        final Resources resources = context.getResources();
+
+        if (sScrollSlop == 0) {
+            sScrollSlop = resources.getInteger(R.integer.swipeScrollSlop);
+            sShrinkAnimationDuration = resources.getInteger(
+                    R.integer.shrink_animation_duration);
+        }
+    }
+
+    public void bind(final Account account, final FolderSelector folderSelector) {
+        mAccount = account;
+        mAccountPreferences = AccountPreferences.get(getContext(), account.name);
+        mFolderSelector = folderSelector;
+    }
+
+    @Override
+    public void onGetView() {
+        // Do nothing
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        mSwipeableContent = findViewById(R.id.swipeable_content);
+
+        mText = (TextView) findViewById(R.id.outbox);
+
+        findViewById(R.id.outbox).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                goToOutbox();
+            }
+        });
+
+        findViewById(R.id.dismiss_button).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                dismiss();
+            }
+        });
+    }
+
+    private void goToOutbox() {
+        if (mOutbox != null) {
+            mFolderSelector.onFolderSelected(mOutbox);
+        }
+    }
+
+    @Override
+    public void onUpdate(String account, Folder folder, ConversationCursor cursor) {
+        if (mLoaderManager != null && folder != null) {
+            if ((folder.type & UIProvider.FolderType.SENT) > 0) {
+                // Only display this tip if user is viewing the Sent folder
+                mLoaderManager.initLoader(LOADER_FOLDER_LIST, null, mFolderListLoaderCallbacks);
+            }
+        }
+    }
+
+    private final LoaderCallbacks<ObjectCursor<Folder>> mFolderListLoaderCallbacks =
+            new LoaderManager.LoaderCallbacks<ObjectCursor<Folder>>() {
+        @Override
+        public void onLoaderReset(final Loader<ObjectCursor<Folder>> loader) {
+            // Do nothing
+        }
+
+        @Override
+        public void onLoadFinished(final Loader<ObjectCursor<Folder>> loader,
+                final ObjectCursor<Folder> data) {
+            if (data != null && data.moveToFirst()) {
+                do {
+                    final Folder folder = data.getModel();
+                    if ((folder.type & UIProvider.FolderType.OUTBOX) > 0) {
+                        mOutbox = folder;
+                        onOutboxTotalCount(folder.totalCount);
+                    }
+                } while (data.moveToNext());
+            }
+        }
+
+        @Override
+        public Loader<ObjectCursor<Folder>> onCreateLoader(final int id, final Bundle args) {
+            // This loads all folders in order to find 'Outbox'.  We could consider adding a new
+            // query to load folders of a given type to make this more efficient, but should be
+            // okay for now since this is triggered infrequently (only when user visits the
+            // 'Sent' folder).
+            final ObjectCursorLoader<Folder> loader = new ObjectCursorLoader<Folder>(getContext(),
+                    mAccount.folderListUri, UIProvider.FOLDERS_PROJECTION, Folder.FACTORY);
+            return loader;
+        }
+    };
+
+    private void onOutboxTotalCount(int outboxCount) {
+        if (mOutboxCount != outboxCount) {
+            mOutboxCount = outboxCount;
+            if (outboxCount > 0) {
+                if (mText != null) {
+                    updateText();
+                }
+            }
+        }
+        if (outboxCount == 0) {
+            // Clear the last seen count, so that new messages in Outbox will always cause this
+            // tip to appear again.
+            mAccountPreferences.setLastSeenOutboxCount(0);
+        }
+    }
+
+    private void updateText() {
+        // Update the display text to reflect current mOutboxCount
+        final Resources resources = getContext().getResources();
+        final String subString = mOutbox.name;
+        final String entireString = resources.getString(
+                R.string.unsent_messages_in_outbox,
+                String.valueOf(mOutboxCount), subString);
+        final SpannableString text = new SpannableString(entireString);
+        final int index = entireString.indexOf(subString);
+        text.setSpan(
+                new TextAppearanceSpan(getContext(), R.style.LinksInTipTextAppearance),
+                index,
+                index + subString.length(),
+                0);
+        mText.setText(text);
+    }
+
+    @Override
+    public boolean getShouldDisplayInList() {
+        return (mOutboxCount > 0 && mOutboxCount != mAccountPreferences.getLastSeenOutboxCount());
+    }
+
+    @Override
+    public int getPosition() {
+        // We want this teaser to go before the first real conversation
+        return 0;
+    }
+
+    @Override
+    public void setAdapter(AnimatedAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    @Override
+    public void bindLoaderManager(LoaderManager loaderManager) {
+        mLoaderManager = loaderManager;
+    }
+
+    @Override
+    public void cleanup() {
+    }
+
+    @Override
+    public void onConversationSelected() {
+        // DO NOTHING
+    }
+
+    @Override
+    public void onCabModeEntered() {
+    }
+
+    @Override
+    public void onCabModeExited() {
+    }
+
+    @Override
+    public boolean acceptsUserTaps() {
+        return true;
+    }
+
+    @Override
+    public void dismiss() {
+        // Do not show this tip again until we have a new count.  Note this is not quite
+        // ideal behavior since after a user dismisses an "1 unsent in outbox" tip,
+        // the message stuck in Outbox could get sent, and a new one gets stuck.
+        // If the user checks back on on Sent folder then, we don't reshow the message since count
+        // itself hasn't changed, but ideally we should since it's a different message than before.
+        // However if user checks the Sent folder in between (when there were 0 messages
+        // in Outbox), the preference is cleared (see {@link onOutboxTotalCount}).
+        mAccountPreferences.setLastSeenOutboxCount(mOutboxCount);
+
+        startDestroyAnimation();
+    }
+
+    @Override
+    public SwipeableView getSwipeableView() {
+        return SwipeableView.from(mSwipeableContent);
+    }
+
+    @Override
+    public boolean canChildBeDismissed() {
+        return true;
+    }
+
+    @Override
+    public float getMinAllowScrollDistance() {
+        return sScrollSlop;
+    }
+
+    private void startDestroyAnimation() {
+        final int start = getHeight();
+        final int end = 0;
+        mAnimatedHeight = start;
+        final ObjectAnimator heightAnimator =
+                ObjectAnimator.ofInt(this, "animatedHeight", start, end);
+        heightAnimator.setInterpolator(new DecelerateInterpolator(2.0f));
+        heightAnimator.setDuration(sShrinkAnimationDuration);
+        heightAnimator.addListener(new AnimatorListener() {
+            @Override
+            public void onAnimationStart(final Animator animation) {
+                // Do nothing
+            }
+
+            @Override
+            public void onAnimationRepeat(final Animator animation) {
+                // Do nothing
+            }
+
+            @Override
+            public void onAnimationEnd(final Animator animation) {
+                // We should no longer exist, so notify the adapter
+                mAdapter.notifyDataSetChanged();
+            }
+
+            @Override
+            public void onAnimationCancel(final Animator animation) {
+                // Do nothing
+            }
+        });
+        heightAnimator.start();
+    }
+
+    /**
+     * This method is used by the animator.  It is explicitly kept in proguard.flags to prevent it
+     * from being removed, inlined, or obfuscated.
+     * Edit ./vendor/unbundled/packages/apps/UnifiedGmail/proguard.flags
+     * In the future, we want to use @Keep
+     */
+    public void setAnimatedHeight(final int height) {
+        mAnimatedHeight = height;
+        requestLayout();
+    }
+
+    @Override
+    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
+        if (mAnimatedHeight == -1) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        } else {
+            setMeasuredDimension(View.MeasureSpec.getSize(widthMeasureSpec), mAnimatedHeight);
+        }
+    }
+}
diff --git a/src/com/android/mail/ui/MailActionBarView.java b/src/com/android/mail/ui/MailActionBarView.java
index c952010..2d4f7cd 100644
--- a/src/com/android/mail/ui/MailActionBarView.java
+++ b/src/com/android/mail/ui/MailActionBarView.java
@@ -364,10 +364,6 @@
         // that are possible.
         LogUtils.d(LOG_TAG, "ActionBarView.onPrepareOptionsMenu().");
 
-        if (mController.shouldHideMenuItems()) {
-            setMenuItemsToHiddenForOpenDrawer(menu);
-            return false;
-        }
         if (mHelpItem != null) {
             mHelpItem.setVisible(mAccount != null
                     && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
@@ -376,6 +372,21 @@
             mSendFeedbackItem.setVisible(mAccount != null
                     && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
         }
+        if (mController.shouldHideMenuItems()) {
+            // Shortcut: hide all remaining menu items if the drawer is shown
+            final int size = menu.size();
+
+            for (int i = 0; i < size; i++) {
+                final MenuItem item = menu.getItem(i);
+                final int id = item.getItemId();
+                if (id != R.id.settings
+                        && id != R.id.feedback_menu_item
+                        && id != R.id.help_info_menu_item) {
+                    item.setVisible(false);
+                }
+            }
+            return false;
+        }
         if (mFolderSettingsItem != null) {
             mFolderSettingsItem.setVisible(mFolder != null
                     && mFolder.supportsCapability(FolderCapabilities.SUPPORTS_SETTINGS));
@@ -520,22 +531,6 @@
     }
 
     /**
-     * Hides menu items while the drawer is open.
-     */
-    private static void setMenuItemsToHiddenForOpenDrawer(Menu menu) {
-        final int size = menu.size();
-
-        for (int i = 0; i < size; i++) {
-            final MenuItem item = menu.getItem(i);
-
-            final int id = item.getItemId();
-            item.setVisible(id == R.id.settings ||
-                    id == R.id.feedback_menu_item ||
-                    id == R.id.help_info_menu_item);
-        }
-    }
-
-    /**
      * Put the ActionBar in List navigation mode.
      */
     private void showNavList() {
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index 51a91d4..ffd1a04 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -510,7 +510,6 @@
             switch (mode) {
                 case ViewMode.SEARCH_RESULTS_CONVERSATION:
                 case ViewMode.CONVERSATION:
-                    mToastBar.setConversationMode(true);
                     mToastBar.show(getUndoClickedListener(
                             convList != null ? convList.getAnimatedAdapter() : null),
                             0,
@@ -524,7 +523,6 @@
                 case ViewMode.SEARCH_RESULTS_LIST:
                 case ViewMode.CONVERSATION_LIST:
                     if (convList != null) {
-                        mToastBar.setConversationMode(false);
                         mToastBar.show(
                                 getUndoClickedListener(convList.getAnimatedAdapter()),
                                 0,
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index e71ec7b..1127956 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -508,7 +508,6 @@
                         - params.rightMargin;
                 params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
                 mToastBar.setLayoutParams(params);
-                mToastBar.setConversationMode(false);
                 break;
             case ViewMode.SEARCH_RESULTS_CONVERSATION:
             case ViewMode.CONVERSATION:
@@ -518,14 +517,12 @@
                     params.width = mLayout.computeConversationListWidth() - params.leftMargin
                             - params.rightMargin;
                     mToastBar.setLayoutParams(params);
-                    mToastBar.setConversationMode(false);
                 } else {
                     // Show undo bar in the conversation.
                     params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
                     params.width = mLayout.computeConversationWidth() - params.leftMargin
                             - params.rightMargin;
                     mToastBar.setLayoutParams(params);
-                    mToastBar.setConversationMode(true);
                 }
                 break;
         }
diff --git a/src/org/apache/commons/io/FileUtils.java b/src/org/apache/commons/io/FileUtils.java
index d5de771..8715eea 100644
--- a/src/org/apache/commons/io/FileUtils.java
+++ b/src/org/apache/commons/io/FileUtils.java
@@ -16,6 +16,8 @@
  */

 package org.apache.commons.io;

 

+import com.google.common.annotations.VisibleForTesting;

+

 import java.io.File;

 import java.io.FileFilter;

 import java.io.FileInputStream;

@@ -77,6 +79,7 @@
  * @author Sandy McArthur

  * @version $Id: FileUtils.java 610810 2008-01-10 15:04:49Z niallp $

  */

+@VisibleForTesting

 public class FileUtils {

 

     /**

@@ -741,6 +744,7 @@
      * @throws IOException if an IO error occurs during copying

      * @since Commons IO 1.1

      */

+    @VisibleForTesting

     public static void copyDirectory(File srcDir, File destDir) throws IOException {

         copyDirectory(srcDir, destDir, true);

     }