Merge "Swipe to refresh for empty conversation list" into jb-ub-mail-ur9
diff --git a/res/layout/conversation_list.xml b/res/layout/conversation_list.xml
index 071696e..f3ce26a 100644
--- a/res/layout/conversation_list.xml
+++ b/res/layout/conversation_list.xml
@@ -22,19 +22,6 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <!-- Note: intentionally not called "empty" because we call
-         setEmptyView programmatically-->
-    <!-- Offset by height of undo bar and action bar -->
-    <TextView
-        android:id="@+id/empty_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:gravity="center"
-        android:textAppearance="?android:attr/textAppearanceLarge"
-        android:text="@string/no_conversations"
-        android:layout_marginTop="@dimen/empty_view_top_padding"
-        android:visibility="gone" />
-
     <include layout="@layout/search_results_view"/>
 
     <com.android.mail.ui.ConversationListView
@@ -42,6 +29,19 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
+        <!-- Note: intentionally not called "empty" because we call
+             setEmptyView programmatically-->
+        <!-- Offset by height of undo bar and action bar -->
+        <com.android.mail.ui.EmptyConversationListView
+            android:id="@+id/empty_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:text="@string/no_conversations"
+            android:layout_marginTop="@dimen/empty_view_top_padding"
+            android:visibility="gone" />
+
         <com.android.mail.ui.SwipeableListView android:id="@android:id/list"
             style="@style/ConversationListFade"
             android:layout_width="match_parent"
diff --git a/res/layout/swipe_to_refresh.xml b/res/layout/swipe_to_refresh.xml
index a95d4e3..35dd7ee 100644
--- a/res/layout/swipe_to_refresh.xml
+++ b/res/layout/swipe_to_refresh.xml
@@ -26,8 +26,7 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:gravity="center"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textColor="#62b5e5"
-        android:textSize="18sp" />
+        android:textColor="#0099cc"
+        android:textSize="17sp" />
 
 </FrameLayout>
diff --git a/src/com/android/mail/ui/ConversationListFragment.java b/src/com/android/mail/ui/ConversationListFragment.java
index 9a6b22d..1cf63c9 100644
--- a/src/com/android/mail/ui/ConversationListFragment.java
+++ b/src/com/android/mail/ui/ConversationListFragment.java
@@ -261,7 +261,7 @@
                 activityContext).inflate(R.layout.conversation_list_footer_view,
                 null);
         mFooterView.setClickListener(mActivity);
-        mConversationListView.setFolderController(mActivity.getFolderController());
+        mConversationListView.setActivity(mActivity);
         final ConversationCursor conversationCursor = getConversationListCursor();
 
         final ConversationListHelper helper = mActivity.getConversationListHelper();
@@ -389,7 +389,6 @@
         mEmptyView = rootView.findViewById(R.id.empty_view);
         mConversationListView =
                 (ConversationListView) rootView.findViewById(R.id.conversation_list);
-        mConversationListView.setActivity(getActivity());
         mConversationListView.setConversationContext(mViewContext);
         mListView = (SwipeableListView) rootView.findViewById(android.R.id.list);
         mListView.setHeaderDividersEnabled(false);
diff --git a/src/com/android/mail/ui/ConversationListView.java b/src/com/android/mail/ui/ConversationListView.java
index c077b1c..d503c75 100644
--- a/src/com/android/mail/ui/ConversationListView.java
+++ b/src/com/android/mail/ui/ConversationListView.java
@@ -10,6 +10,7 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.util.TypedValue;
 
 import android.view.Gravity;
@@ -41,9 +42,7 @@
     private static final int DISTANCE_TO_TRIGGER_CANCEL = 10; // dp
     private static final int SHOW_CHECKING_FOR_MAIL_DURATION_IN_MILLIS = 1 * 1000; // 1 seconds
 
-    private static final int ACTION_BAR_FADE_DURATION_IN_MILLIS = 100;
-    private static final int SWIPE_TEXT_APPEAR_DURATION_IN_MILLIS = 100;
-    private static final int SWIPE_TEXT_FADE_DURATION_IN_MILLIS = 300;
+    private static final int SWIPE_TEXT_APPEAR_DURATION_IN_MILLIS = 200;
     private static final int SYNC_STATUS_BAR_FADE_DURATION_IN_MILLIS = 150;
     private static final int SYNC_TRIGGER_SHRINK_DURATION_IN_MILLIS = 250;
 
@@ -69,11 +68,9 @@
     private Interpolator mAccelerateInterpolator = new AccelerateInterpolator(1.5f);
     private Interpolator mDecelerateInterpolator = new DecelerateInterpolator(1.5f);
 
-    private FolderController mFolderController = null;
-
     private float mDensity;
 
-    private Activity mActivity;
+    private ControllableActivity mActivity;
     private WindowManager mWindowManager;
     private HintText mHintText;
     private boolean mHasHintTextViewBeenAdded = false;
@@ -95,7 +92,7 @@
     }
 
     public ConversationListView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, -1);
+        super(context, attrs, defStyle);
 
         mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         mHintText = new ConversationListView.HintText(context);
@@ -130,11 +127,7 @@
         };
     }
 
-    protected void setFolderController(FolderController folderController) {
-        mFolderController = folderController;
-    }
-
-    protected void setActivity(Activity activity) {
+    protected void setActivity(ControllableActivity activity) {
         mActivity = activity;
     }
 
@@ -187,6 +180,11 @@
                 if (ConversationListContext.isSearchResult(mConvListContext)) {
                     break;
                 }
+                // Disable swipe to refresh in CAB mode
+                if (mActivity.getSelectedSet() != null &&
+                        mActivity.getSelectedSet().size() > 0) {
+                    break;
+                }
                 // Only if we have reached the top of the list, any further scrolling
                 // can potentially trigger a sync.
                 if (mListView.getChildCount() == 0 || mListView.getChildAt(0).getTop() == 0) {
@@ -240,6 +238,7 @@
     }
 
     private void startMovementTracking(float y) {
+        LogUtils.d(LOG_TAG, "Start swipe to refresh tracking");
         mTrackingScrollMovement = true;
         mTrackingScrollStartY = y;
         mTrackingScrollMaxY = mTrackingScrollStartY;
@@ -263,7 +262,7 @@
         mSyncTriggerBar.setVisibility(View.GONE);
 
         // This will call back to showSyncStatusBar():
-        mFolderController.requestFolderRefresh();
+        mActivity.getFolderController().requestFolderRefresh();
 
         // Any continued dragging after this should have no effect
         mTrackingScrollMovement = false;
@@ -292,6 +291,8 @@
                     .setDuration(SYNC_STATUS_BAR_FADE_DURATION_IN_MILLIS)
                     .setListener(mSyncProgressBarFadeListener);
             mSyncTriggerBar.setVisibility(GONE);
+            // Hide the "Checking for mail" text in action bar if it isn't hidden already:
+            mHintText.hide();
             mIsSyncing = false;
         }
     }
@@ -314,8 +315,8 @@
         window.getDecorView().getWindowVisibleDisplayFrame(rect);
         int statusBarHeight = rect.top;
 
-        final TypedArray actionBarSize = mActivity.obtainStyledAttributes(
-                new int[] { android.R.attr.actionBarSize });
+        final TypedArray actionBarSize = ((Activity) mActivity).obtainStyledAttributes(
+                new int[]{android.R.attr.actionBarSize});
         int actionBarHeight = actionBarSize.getDimensionPixelSize(0, 0);
         actionBarSize.recycle();
 
@@ -332,7 +333,7 @@
     }
 
     /**
-     * A test view that covers the entire action bar, used for displaying
+     * A text view that covers the entire action bar, used for displaying
      * "Swipe down to refresh" hint text if user has initiated a downward swipe.
      */
     protected static class HintText extends FrameLayout {
@@ -347,6 +348,7 @@
         private TextView mTextView;
 
         private Interpolator mDecelerateInterpolator = new DecelerateInterpolator(1.5f);
+        private Interpolator mAccelerateInterpolator = new AccelerateInterpolator(1.5f);
 
         public HintText(final Context context) {
             this(context, null);
@@ -387,13 +389,12 @@
         private void displaySwipeToRefresh() {
             if (mDisplay != SWIPE_TO_REFRESH) {
                 mTextView.setText(getResources().getText(R.string.swipe_down_to_refresh));
+                // Covers the current action bar:
                 setVisibility(View.VISIBLE);
-                // Fade out the current action bar first:
-                setAlpha(0f);
-                animate().alpha(1f).setDuration(ACTION_BAR_FADE_DURATION_IN_MILLIS);
-                // Then animate text sliding down onto action bar:
+                setAlpha(1f);
+                // Animate text sliding down onto action bar:
                 mTextView.setY(-mTextView.getHeight());
-                mTextView.animate().y(0).setStartDelay(ACTION_BAR_FADE_DURATION_IN_MILLIS)
+                mTextView.animate().y(0)
                         .setInterpolator(mDecelerateInterpolator)
                         .setDuration(SWIPE_TEXT_APPEAR_DURATION_IN_MILLIS);
                 mDisplay = SWIPE_TO_REFRESH;
@@ -414,13 +415,20 @@
 
         private void hide() {
             if (mDisplay != NONE) {
-                animate().alpha(0f).setDuration(SWIPE_TEXT_FADE_DURATION_IN_MILLIS).start();
-                postDelayed(new Runnable() {
-                    @Override
-                    public void run() {
-                        setVisibility(View.GONE);
-                    }
-                }, SWIPE_TEXT_FADE_DURATION_IN_MILLIS);
+                // Animate text sliding up leaving behind a blank action bar
+                mTextView.animate().y(-mTextView.getHeight())
+                        .setInterpolator(mAccelerateInterpolator)
+                        .setDuration(SWIPE_TEXT_APPEAR_DURATION_IN_MILLIS)
+                        .start();
+                animate().alpha(0f)
+                        .setDuration(SWIPE_TEXT_APPEAR_DURATION_IN_MILLIS)
+                        .withEndAction(
+                                new Runnable() {
+                                    @Override
+                                    public void run() {
+                                        setVisibility(View.GONE);
+                                    }
+                                });
                 mDisplay = NONE;
             }
         }
diff --git a/src/com/android/mail/ui/EmptyConversationListView.java b/src/com/android/mail/ui/EmptyConversationListView.java
new file mode 100644
index 0000000..5943fc6
--- /dev/null
+++ b/src/com/android/mail/ui/EmptyConversationListView.java
@@ -0,0 +1,25 @@
+package com.android.mail.ui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.TextView;
+
+public class EmptyConversationListView extends TextView {
+
+    public EmptyConversationListView(Context context) {
+        this(context, null);
+    }
+
+    public EmptyConversationListView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public boolean onTouchEvent(MotionEvent e) {
+        // In order for users to perform swipe down in this text view to trigger
+        // refresh, we always return true here so that ACTION_MOVE and ACTION_UP
+        // events would be passed to parent view ConversationListView, which is
+        // where swipe to refresh detecting happens.
+        return true;
+    }
+}