Replace AccountTypeManager usages in PeopleActivity

Changed usages of getAccounts to other methods that are safe to call
synchronously from UI thread (getAccounts may require DB query and
parsing).

Test manually verify that sync loading spinner disappears after
doing pull-to-refresh

Bug 33627801
Change-Id: I1ec162e0fd5214d36e96d1746ee26150caecab25
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 113121b..426dcd7 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -68,6 +68,7 @@
 import com.android.contacts.logging.Logger;
 import com.android.contacts.logging.ScreenEvent.ScreenType;
 import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.account.AccountType;
 import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.util.AccountFilterUtil;
 import com.android.contacts.util.Constants;
@@ -77,6 +78,7 @@
 import com.android.contactsbind.FeatureHighlightHelper;
 import com.android.contactsbind.ObjectFactory;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -100,6 +102,7 @@
 
     private ContactsIntentResolver mIntentResolver;
     private ContactsRequest mRequest;
+    private AccountTypeManager mAccountTypeManager;
 
     private FloatingActionButtonController mFloatingActionButtonController;
     private View mFloatingActionButtonContainer;
@@ -163,17 +166,18 @@
                 return;
             }
 
-            final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(this)
-                    .getAccounts(/* contactsWritableOnly */ true);
-            final List<Account> syncableAccounts = filter.getSyncableAccounts(accounts);
-            // If one of the accounts is active or pending, use spinning circle to indicate one of
-            // the syncs is in progress.
-            if (syncableAccounts != null && syncableAccounts.size() > 0) {
-                for (Account account: syncableAccounts) {
-                    if (SyncUtil.isSyncStatusPendingOrActive(account)) {
-                        return;
-                    }
-                }
+            final List<AccountWithDataSet> accounts;
+            if (filter.filterType == ContactListFilter.FILTER_TYPE_ACCOUNT &&
+                    filter.isGoogleAccountType()) {
+                accounts = Collections.singletonList(new AccountWithDataSet(filter.accountName,
+                        filter.accountType, null));
+            } else if (filter.shouldShowSyncState()) {
+                accounts = mAccountTypeManager.getWritableGoogleAccounts();
+            } else {
+                accounts = Collections.emptyList();
+            }
+            if (SyncUtil.isAnySyncing(accounts)) {
+                return;
             }
             swipeRefreshLayout.setRefreshing(false);
         }
@@ -222,6 +226,7 @@
             Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate start");
         }
         super.onCreate(savedState);
+        mAccountTypeManager = AccountTypeManager.getInstance(this);
 
         if (RequestPermissionsActivity.startPermissionActivity(this)) {
             return;
@@ -573,21 +578,9 @@
 
     private boolean shouldShowList() {
         return mProviderStatus != null
-                && ((mProviderStatus.equals(ProviderStatus.STATUS_EMPTY) && hasNonLocalAccount())
-                        || mProviderStatus.equals(ProviderStatus.STATUS_NORMAL));
-    }
-
-    // Returns true if there are real accounts (not "local" account) in the list of accounts.
-    private boolean hasNonLocalAccount() {
-        final List<AccountWithDataSet> allAccounts =
-                AccountTypeManager.getInstance(this).getAccounts(/* contactWritableOnly */ false);
-        if (allAccounts == null || allAccounts.size() == 0) {
-            return false;
-        }
-        if (allAccounts.size() > 1) {
-            return true;
-        }
-        return !allAccounts.get(0).isNullAccount();
+                && ((mProviderStatus.equals(ProviderStatus.STATUS_EMPTY)
+                && mAccountTypeManager.hasNonLocalAccount())
+                || mProviderStatus.equals(ProviderStatus.STATUS_NORMAL));
     }
 
     private void invalidateOptionsMenuIfNeeded() {
diff --git a/src/com/android/contacts/list/ContactListFilter.java b/src/com/android/contacts/list/ContactListFilter.java
index 850683c..4245be4 100644
--- a/src/com/android/contacts/list/ContactListFilter.java
+++ b/src/com/android/contacts/list/ContactListFilter.java
@@ -420,6 +420,13 @@
         return false;
     }
 
+    public boolean shouldShowSyncState() {
+        return (isGoogleAccountType() && filterType == ContactListFilter.FILTER_TYPE_ACCOUNT)
+                || filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS
+                || filterType == ContactListFilter.FILTER_TYPE_CUSTOM
+                || filterType == ContactListFilter.FILTER_TYPE_DEFAULT;
+    }
+
     /**
      * Returns the Google accounts (see {@link #isGoogleAccountType) for this ContactListFilter.
      */
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index a8c37d4..d87b444 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -178,6 +178,39 @@
      */
     public abstract Account getDefaultGoogleAccount();
 
+    /**
+     * Returns the Google Accounts.
+     *
+     * <p>This method exists in addition to filterAccountsByTypeAsync because it should be safe
+     * to call synchronously.
+     * </p>
+     */
+    public List<AccountWithDataSet> getWritableGoogleAccounts() {
+        // This implementation may block and should be overridden by the Impl class
+        return Futures.getUnchecked(filterAccountsByTypeAsync(new Predicate<AccountType>() {
+            @Override
+            public boolean apply(@Nullable AccountType input) {
+                return  input.areContactsWritable() &&
+                        GoogleAccountType.ACCOUNT_TYPE.equals(input.accountType);
+
+            }
+        }));
+    }
+
+    /**
+     * Returns true if there are real accounts (not "local" account) in the list of accounts.
+     */
+    public boolean hasNonLocalAccount() {
+        final List<AccountWithDataSet> allAccounts = getAccounts(/* contactWritableOnly */ false);
+        if (allAccounts == null || allAccounts.size() == 0) {
+            return false;
+        }
+        if (allAccounts.size() > 1) {
+            return true;
+        }
+        return !allAccounts.get(0).isNullAccount();
+    }
+
     static Account getDefaultGoogleAccount(AccountManager accountManager,
             SharedPreferences prefs, String defaultAccountKey) {
         // Get all the google accounts on the device
@@ -560,12 +593,29 @@
      */
     @Override
     public Account getDefaultGoogleAccount() {
-        final AccountManager accountManager = AccountManager.get(mContext);
         final SharedPreferences sharedPreferences =
                 mContext.getSharedPreferences(mContext.getPackageName(), Context.MODE_PRIVATE);
         final String defaultAccountKey =
                 mContext.getResources().getString(R.string.contact_editor_default_account_key);
-        return getDefaultGoogleAccount(accountManager, sharedPreferences, defaultAccountKey);
+        return getDefaultGoogleAccount(mAccountManager, sharedPreferences, defaultAccountKey);
+    }
+
+    @Override
+    public List<AccountWithDataSet> getWritableGoogleAccounts() {
+        final Account[] googleAccounts =
+                mAccountManager.getAccountsByType(GoogleAccountType.ACCOUNT_TYPE);
+        final List<AccountWithDataSet> result = new ArrayList<>();
+        for (Account account : googleAccounts) {
+            // Accounts with a dataSet (e.g. Google plus accounts) are not writable.
+            result.add(new AccountWithDataSet(account.name, account.type, null));
+        }
+        return result;
+    }
+
+    @Override
+    public boolean hasNonLocalAccount() {
+        final Account[] accounts = mAccountManager.getAccounts();
+        return accounts != null && accounts.length > 0;
     }
 
     /**
diff --git a/src/com/android/contacts/util/SyncUtil.java b/src/com/android/contacts/util/SyncUtil.java
index 0d6c494..ce10937 100644
--- a/src/com/android/contacts/util/SyncUtil.java
+++ b/src/com/android/contacts/util/SyncUtil.java
@@ -22,8 +22,11 @@
 import android.net.NetworkInfo;
 import android.provider.ContactsContract;
 
+import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.model.account.GoogleAccountType;
 
+import java.util.List;
+
 /**
  * Utilities related to sync.
  */
@@ -46,6 +49,19 @@
     }
 
     /**
+     * Returns true {@link ContentResolver#isSyncPending(Account, String)} or
+     * {@link ContentResolver#isSyncActive(Account, String)} is true for any account in accounts
+     */
+    public static final boolean isAnySyncing(List<AccountWithDataSet> accounts) {
+        for (AccountWithDataSet accountWithDataSet : accounts) {
+            if (isSyncStatusPendingOrActive(accountWithDataSet.getAccountOrNull())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Returns true if the given Google account is not syncable.
      */
     public static final boolean isUnsyncableGoogleAccount(Account account) {