Show spinner only when user pulls down (1/2)

1. show spinner only when user pulls down;
2. stop showing spinner if sync is not finished after 30s;
3. add max time to show spinner into Flags.

Bug: 28625097
Bug: 31993722

Test: Manually verified scenarios:
Only pulling down can trigger spinner to show up, spinner won't be
shown for any other background sync(add/remove account, edit contacts);
refresh an account with over 2000 contacts, spinner disappears after
30s;
refresh without internet connection, spinner disappears after 30s;
refresh twice within 30s, spinner disappears after 30s since the second
refreshing.

Change-Id: Ib88c14a40fc8787527baa9d5ac99da910fdd352b
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 9326b0d..0d4b4c0 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -173,9 +173,7 @@
             // the syncs is in progress.
             if (syncableAccounts != null && syncableAccounts.size() > 0) {
                 for (Account account: syncableAccounts) {
-                    if (SyncUtil.isSyncStatusPendingOrActive(account)
-                            || SyncUtil.isUnsyncableGoogleAccount(account)) {
-                        swipeRefreshLayout.setRefreshing(true);
+                    if (SyncUtil.isSyncStatusPendingOrActive(account)) {
                         return;
                     }
                 }
diff --git a/src/com/android/contacts/common/Experiments.java b/src/com/android/contacts/common/Experiments.java
index df709b3..1b739ed 100644
--- a/src/com/android/contacts/common/Experiments.java
+++ b/src/com/android/contacts/common/Experiments.java
@@ -53,6 +53,12 @@
     public static final String PULL_TO_REFRESH = "PullToRefresh__pull_to_refresh";
 
     /**
+     * Flags for maximum time to show spinner for a contacts sync.
+     */
+    public static final String PULL_TO_REFRESH_CANCEL_REFRESH_MILLIS =
+            "PullToRefresh__cancel_refresh_millis";
+
+    /**
      * Search study boolean indicating whether to inject yenta search results before CP2 results.
      */
     public static final String SEARCH_YENTA = "Search__yenta";
diff --git a/src/com/android/contacts/list/ContactBrowseListFragment.java b/src/com/android/contacts/list/ContactBrowseListFragment.java
index c8da194..bf4f891 100644
--- a/src/com/android/contacts/list/ContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/ContactBrowseListFragment.java
@@ -92,7 +92,7 @@
     private boolean mSelectionVerified;
     private int mLastSelectedPosition = -1;
     private boolean mRefreshingContactUri;
-    protected ContactListFilter mFilter;
+    private ContactListFilter mFilter;
     private String mPersistentSelectionPrefix = PERSISTENT_SELECTION_PREFIX;
 
     protected OnContactBrowserActionListener mListener;
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index a76af7f..a748c06 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -31,6 +31,7 @@
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Directory;
 import android.support.v4.widget.SwipeRefreshLayout;
@@ -104,7 +105,17 @@
     private View mEmptyHomeView;
     private View mAccountFilterContainer;
     private TextView mSearchProgressText;
+
     private SwipeRefreshLayout mSwipeRefreshLayout;
+    private final Handler mHandler = new Handler();
+    private final Runnable mCancelRefresh = new Runnable() {
+        @Override
+        public void run() {
+            if (mSwipeRefreshLayout.isRefreshing()) {
+                mSwipeRefreshLayout.setRefreshing(false);
+            }
+        }
+    };
 
     private View mAlertContainer;
     private TextView mAlertText;
@@ -536,7 +547,10 @@
         mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
             @Override
             public void onRefresh() {
-                syncContacts(mFilter);
+                mHandler.removeCallbacks(mCancelRefresh);
+                syncContacts(getFilter());
+                mHandler.postDelayed(mCancelRefresh, Flags.getInstance(getContext())
+                        .getInteger(Experiments.PULL_TO_REFRESH_CANCEL_REFRESH_MILLIS));
             }
         });
         mSwipeRefreshLayout.setColorSchemeResources(