Replace several usages for of AccountTypeManager.getAccounts

Test: Ran GoogleContactsTests

Bug 33627801

Change-Id: Ifde6c5f314558159bb468c92fa38b20a8d90bf06
diff --git a/src/com/android/contacts/SimImportFragment.java b/src/com/android/contacts/SimImportFragment.java
index a8db4ee..9393e1a 100644
--- a/src/com/android/contacts/SimImportFragment.java
+++ b/src/com/android/contacts/SimImportFragment.java
@@ -126,9 +126,9 @@
         if (savedInstanceState != null) {
             mAccountHeaderPresenter.onRestoreInstanceState(savedInstanceState);
         } else {
-            final AccountWithDataSet currentDefaultAccount = AccountWithDataSet
-                    .getDefaultOrBestFallback(mPreferences, mAccountTypeManager);
-            mAccountHeaderPresenter.setCurrentAccount(currentDefaultAccount);
+            // Default may be null in which case the first account in the list will be selected
+            // after they are loaded.
+            mAccountHeaderPresenter.setCurrentAccount(mPreferences.getDefaultAccount());
         }
         mAccountHeaderPresenter.setObserver(new AccountHeaderPresenter.Observer() {
             @Override
@@ -173,6 +173,9 @@
 
     private void rememberSelectionsForCurrentAccount() {
         final AccountWithDataSet current = mAdapter.getAccount();
+        if (current == null) {
+            return;
+        }
         final long[] ids = mListView.getCheckedItemIds();
         Arrays.sort(ids);
         mPerAccountCheckedIds.put(current, ids);
diff --git a/src/com/android/contacts/editor/AccountHeaderPresenter.java b/src/com/android/contacts/editor/AccountHeaderPresenter.java
index e7e8e50..4e4f35a 100644
--- a/src/com/android/contacts/editor/AccountHeaderPresenter.java
+++ b/src/com/android/contacts/editor/AccountHeaderPresenter.java
@@ -99,8 +99,9 @@
 
     public void setAccounts(List<AccountInfo> accounts) {
         mAccounts = accounts;
-        // If the current account was removed just switch to the next one in the list.
-        if (mCurrentAccount != null && !AccountInfo.contains(mAccounts, mCurrentAccount)) {
+        // If the current account hasn't been set or it has been removed just use the first
+        // account.
+        if (mCurrentAccount == null || !AccountInfo.contains(mAccounts, mCurrentAccount)) {
             mCurrentAccount = mAccounts.isEmpty() ? null : accounts.get(0).getAccount();
             mObserver.onChange(this);
         }
diff --git a/src/com/android/contacts/editor/PickRawContactDialogFragment.java b/src/com/android/contacts/editor/PickRawContactDialogFragment.java
index d894371..5a9c9fd 100644
--- a/src/com/android/contacts/editor/PickRawContactDialogFragment.java
+++ b/src/com/android/contacts/editor/PickRawContactDialogFragment.java
@@ -53,7 +53,6 @@
         private final LayoutInflater mInflater;
         private final Context mContext;
         private final RawContactsMetadata mRawContactsMetadata;
-        private final AccountDisplayInfoFactory mAccountDisplayInfoFactory;
         private final AccountTypeManager mAccountTypeManager;
         private final ContactsPreferences mPreferences;
 
@@ -61,7 +60,6 @@
                 RawContactsMetadata rawContactsMetadata) {
             mContext = context;
             mInflater = LayoutInflater.from(context);
-            mAccountDisplayInfoFactory = AccountDisplayInfoFactory.forWritableAccounts(context);
             mAccountTypeManager = AccountTypeManager.getInstance(context);
             mPreferences = new ContactsPreferences(context);
             mRawContactsMetadata = rawContactsMetadata;
diff --git a/src/com/android/contacts/interactions/ImportDialogFragment.java b/src/com/android/contacts/interactions/ImportDialogFragment.java
index 7f5ce4e..5bf4fe4 100644
--- a/src/com/android/contacts/interactions/ImportDialogFragment.java
+++ b/src/com/android/contacts/interactions/ImportDialogFragment.java
@@ -43,11 +43,16 @@
 import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.model.SimCard;
 import com.android.contacts.model.SimContact;
+import com.android.contacts.model.account.AccountInfo;
+import com.android.contacts.model.account.AccountType;
 import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.util.AccountSelectionUtil;
 import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 
 import java.util.List;
+import java.util.concurrent.Future;
 
 /**
  * An dialog invoked to import/export contacts.
@@ -65,6 +70,8 @@
     private boolean mSimOnly = false;
     private SimContactDao mSimDao;
 
+    private Future<List<AccountInfo>> mAccountsFuture;
+
     /** Preferred way to show this dialog */
     public static void show(FragmentManager fragmentManager) {
         final ImportDialogFragment fragment = new ImportDialogFragment();
@@ -100,6 +107,15 @@
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+
+        // Start loading the accounts. This is done in onResume in case they were refreshed.
+        mAccountsFuture = AccountTypeManager.getInstance(getActivity()).filterAccountsAsync(
+                AccountTypeManager.writableFilter());
+    }
+
+    @Override
     public Context getContext() {
         return getActivity();
     }
@@ -240,12 +256,16 @@
      * Handle "import from SD".
      */
     private void handleImportRequest(int resId, int subscriptionId) {
+        // Get the accounts. Because this only happens after a user action this should pretty
+        // much never block since it will usually be at least several seconds before the user
+        // interacts with the view
+        final List<AccountWithDataSet> accountList = AccountInfo.extractAccounts(
+                Futures.getUnchecked(mAccountsFuture));
+
         // There are three possibilities:
         // - more than one accounts -> ask the user
         // - just one account -> use the account without asking the user
         // - no account -> use phone-local storage without asking the user
-        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(getActivity());
-        final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
         final int size = accountList.size();
         if (size > 1) {
             // Send over to the account selector
diff --git a/src/com/android/contacts/list/ContactListFilter.java b/src/com/android/contacts/list/ContactListFilter.java
index 4245be4..32e4b9c 100644
--- a/src/com/android/contacts/list/ContactListFilter.java
+++ b/src/com/android/contacts/list/ContactListFilter.java
@@ -392,12 +392,16 @@
         }
     }
 
+    public boolean isSyncable() {
+        return isGoogleAccountType() && filterType == FILTER_TYPE_ACCOUNT;
+    }
+
     /**
      * Returns true if this ContactListFilter contains at least one Google account.
      * (see {@link #isGoogleAccountType)
      */
     public boolean isSyncable(List<AccountWithDataSet> accounts) {
-        if (isGoogleAccountType() && filterType == ContactListFilter.FILTER_TYPE_ACCOUNT) {
+        if (isSyncable()) {
             return true;
         }
         // Since we don't know which group is selected until the actual contacts loading, we
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index 855a530..bf3ee81 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -70,6 +70,7 @@
 import com.android.contacts.logging.Logger;
 import com.android.contacts.logging.ScreenEvent;
 import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.account.AccountInfo;
 import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.quickcontact.QuickContactActivity;
 import com.android.contacts.util.AccountFilterUtil;
@@ -78,9 +79,11 @@
 import com.android.contacts.util.SyncUtil;
 import com.android.contactsbind.FeatureHighlightHelper;
 import com.android.contactsbind.experiments.Flags;
+import com.google.common.util.concurrent.Futures;
 
 import java.util.List;
 import java.util.Locale;
+import java.util.concurrent.Future;
 
 /**
  * Fragment containing a contact list used for browsing (as compared to
@@ -152,6 +155,8 @@
     private ContactsRequest mContactsRequest;
     private ContactListFilterController mContactListFilterController;
 
+    private Future<List<AccountInfo>> mWritableAccountsFuture;
+
     private final ActionBarAdapter.Listener mActionBarListener = new ActionBarAdapter.Listener() {
         @Override
         public void onAction(int action) {
@@ -320,12 +325,13 @@
         // TODO(samchen) : Check ContactListFilter.FILTER_TYPE_CUSTOM
         if (ContactListFilter.FILTER_TYPE_DEFAULT == filter.filterType
                 || ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS == filter.filterType) {
-            final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(getContext())
-                    .getAccounts(/* contactsWritableOnly */ true);
-            final List<Account> syncableAccounts = filter.getSyncableAccounts(accounts);
+            final List<AccountInfo> syncableAccounts =
+                    AccountTypeManager.getInstance(getContext()).getWritableGoogleAccounts();
 
             if (syncableAccounts != null && syncableAccounts.size() > 0) {
-                for (Account account : syncableAccounts) {
+                for (AccountInfo info : syncableAccounts) {
+                    // Won't be null because Google accounts have a non-null name and type.
+                    final Account account = info.getAccount().getAccountOrNull();
                     if (SyncUtil.isSyncStatusPendingOrActive(account)
                             || SyncUtil.isUnsyncableGoogleAccount(account)) {
                         return false;
@@ -508,9 +514,11 @@
     public void onEnableAutoSync(ContactListFilter filter) {
         // Turn on auto-sync
         ContentResolver.setMasterSyncAutomatically(true);
+
+        // This should be OK (won't block) because this only happens after a user action
+        final List<AccountInfo> accountInfos = Futures.getUnchecked(mWritableAccountsFuture);
         // Also enable Contacts sync
-        final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(
-                getContext()).getAccounts(/* contactsWritableOnly */ true);
+        final List<AccountWithDataSet> accounts = AccountInfo.extractAccounts(accountInfos);
         final List<Account> syncableAccounts = filter.getSyncableAccounts(accounts);
         if (syncableAccounts != null && syncableAccounts.size() > 0) {
             for (Account account : syncableAccounts) {
@@ -578,8 +586,8 @@
         bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
         bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
 
-        final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(
-                getContext()).getAccounts(/* contactsWritableOnly */ true);
+        final List<AccountWithDataSet> accounts = AccountInfo.extractAccounts(
+                Futures.getUnchecked(mWritableAccountsFuture));
         final List<Account> syncableAccounts = filter.getSyncableAccounts(accounts);
         if (syncableAccounts != null && syncableAccounts.size() > 0) {
             for (Account account : syncableAccounts) {
@@ -729,6 +737,9 @@
         mActionBarAdapter.setListener(mActionBarListener);
         mDisableOptionItemSelected = false;
         maybeHideCheckBoxes();
+
+        mWritableAccountsFuture = AccountTypeManager.getInstance(getContext()).filterAccountsAsync(
+                AccountTypeManager.writableFilter());
     }
 
     private void maybeHideCheckBoxes() {
@@ -843,9 +854,9 @@
 
         if (filter != null && !mActionBarAdapter.isSearchMode()
                 && !mActionBarAdapter.isSelectionMode()) {
-            final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(getContext())
-                    .getAccounts(/* contactsWritableOnly */ true);
-            if (filter.isSyncable(accounts)) {
+            if (filter.isSyncable()
+                    || (filter.shouldShowSyncState()
+                    && SyncUtil.hasSyncableAccount(AccountTypeManager.getInstance(getContext())))) {
                 swipeRefreshLayout.setEnabled(true);
             }
         }
diff --git a/src/com/android/contacts/model/account/AccountDisplayInfoFactory.java b/src/com/android/contacts/model/account/AccountDisplayInfoFactory.java
index 759eede..ac1ad35 100644
--- a/src/com/android/contacts/model/account/AccountDisplayInfoFactory.java
+++ b/src/com/android/contacts/model/account/AccountDisplayInfoFactory.java
@@ -89,18 +89,6 @@
         return new AccountDisplayInfoFactory(context, accounts);
     }
 
-    public static AccountDisplayInfoFactory forAllAccounts(Context context) {
-        final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(context);
-        final List<AccountWithDataSet> accounts = accountTypeManager.getAccounts(false);
-        return new AccountDisplayInfoFactory(context, accounts);
-    }
-
-    public static AccountDisplayInfoFactory forWritableAccounts(Context context) {
-        final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(context);
-        final List<AccountWithDataSet> accounts = accountTypeManager.getAccounts(true);
-        return new AccountDisplayInfoFactory(context, accounts);
-    }
-
     private boolean shouldUseTypeLabelForName(AccountWithDataSet account) {
         final int type = mDeviceAccountTypeFactory.classifyAccount(account.type);
         return (type == DeviceLocalAccountTypeFactory.TYPE_SIM && mSimAccountCount == 1)
diff --git a/src/com/android/contacts/model/account/AccountInfo.java b/src/com/android/contacts/model/account/AccountInfo.java
index 2161edb..b07204e 100644
--- a/src/com/android/contacts/model/account/AccountInfo.java
+++ b/src/com/android/contacts/model/account/AccountInfo.java
@@ -76,6 +76,10 @@
         return mDisplayInfo.isDeviceAccount();
     }
 
+    public boolean hasGoogleAccountType() {
+        return mDisplayInfo.hasGoogleAccountType();
+    }
+
     public boolean sameAccount(AccountInfo other) {
         return sameAccount(other.getAccount());
     }
diff --git a/src/com/android/contacts/model/account/AccountWithDataSet.java b/src/com/android/contacts/model/account/AccountWithDataSet.java
index a636440..a163139 100644
--- a/src/com/android/contacts/model/account/AccountWithDataSet.java
+++ b/src/com/android/contacts/model/account/AccountWithDataSet.java
@@ -254,30 +254,5 @@
 
         return ret;
     }
-
-    public static AccountWithDataSet getDefaultOrBestFallback(ContactsPreferences preferences,
-            AccountTypeManager accountTypeManager) {
-        if (preferences.isDefaultAccountSet()) {
-            final AccountWithDataSet account = preferences.getDefaultAccount();
-            if (accountTypeManager.isWritable(account)) {
-                return account;
-            }
-        }
-        final List<AccountWithDataSet> accounts = accountTypeManager
-                .getAccounts(/* writableOnly */ true);
-
-        if (accounts.isEmpty()) {
-            return AccountWithDataSet.getNullAccount();
-        }
-
-        // Return the first google account
-        for (AccountWithDataSet account : accounts) {
-            if (GoogleAccountType.ACCOUNT_TYPE.equals(account) && account.dataSet == null) {
-                return account;
-            }
-        }
-        // Arbitrarily return the first writable account
-        return accounts.get(0);
-    }
 }
 
diff --git a/src/com/android/contacts/preference/DefaultAccountPreference.java b/src/com/android/contacts/preference/DefaultAccountPreference.java
index fc23e13..72ba74d 100644
--- a/src/com/android/contacts/preference/DefaultAccountPreference.java
+++ b/src/com/android/contacts/preference/DefaultAccountPreference.java
@@ -31,7 +31,6 @@
 public class DefaultAccountPreference extends DialogPreference {
     private ContactsPreferences mPreferences;
     private AccountsListAdapter mListAdapter;
-    private AccountDisplayInfoFactory mAccountDisplayInfoFactory;
     private AccountTypeManager mAccountTypeManager;
     private int mChosenIndex = -1;
 
@@ -56,7 +55,6 @@
         mListAdapter = new AccountsListAdapter(getContext(),
                 AccountsListAdapter.AccountListFilter.ACCOUNTS_CONTACT_WRITABLE);
         mAccountTypeManager = AccountTypeManager.getInstance(getContext());
-        mAccountDisplayInfoFactory = AccountDisplayInfoFactory.forWritableAccounts(getContext());
     }
 
     @Override
@@ -68,10 +66,10 @@
     public CharSequence getSummary() {
         final AccountWithDataSet defaultAccount = mPreferences.getDefaultAccount();
         if (defaultAccount == null ||
-                !mAccountTypeManager.getAccounts(/* writable */ true).contains(defaultAccount)) {
+                !mAccountTypeManager.exists(defaultAccount)) {
             return null;
         } else {
-            return mAccountDisplayInfoFactory.getAccountDisplayInfo(defaultAccount).getNameLabel();
+            return mAccountTypeManager.getAccountInfoForAccount(defaultAccount).getNameLabel();
         }
     }
 
diff --git a/src/com/android/contacts/util/AccountFilterUtil.java b/src/com/android/contacts/util/AccountFilterUtil.java
index a7824f4..54c16e2 100644
--- a/src/com/android/contacts/util/AccountFilterUtil.java
+++ b/src/com/android/contacts/util/AccountFilterUtil.java
@@ -230,13 +230,16 @@
     }
 
     private static String getActionBarTitleForAccount(Context context, ContactListFilter filter) {
-        final AccountDisplayInfoFactory factory =
-                AccountDisplayInfoFactory.forAllAccounts(context);
-        final AccountDisplayInfo account = factory.getAccountDisplayInfoFor(filter);
-        if (account.hasGoogleAccountType()) {
+        final AccountInfo info = AccountTypeManager.getInstance(context)
+                .getAccountInfoForAccount(filter.toAccountWithDataSet());
+        if (info == null) {
+            return context.getString(R.string.contactsList);
+        }
+
+        if (info.hasGoogleAccountType()) {
             return context.getString(R.string.title_from_google);
         }
-        return account.withFormattedName(context, R.string.title_from_other_accounts)
-                .getNameLabel().toString();
+        return context.getString(R.string.title_from_other_accounts,
+                info.getNameLabel().toString());
     }
 }
diff --git a/src/com/android/contacts/util/SyncUtil.java b/src/com/android/contacts/util/SyncUtil.java
index ce10937..c5feb39 100644
--- a/src/com/android/contacts/util/SyncUtil.java
+++ b/src/com/android/contacts/util/SyncUtil.java
@@ -22,6 +22,7 @@
 import android.net.NetworkInfo;
 import android.provider.ContactsContract;
 
+import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.model.account.GoogleAccountType;
 
@@ -71,6 +72,10 @@
         return ContentResolver.getIsSyncable(account, ContactsContract.AUTHORITY) <= 0;
     }
 
+    public static final boolean hasSyncableAccount(AccountTypeManager accountTypeManager) {
+        return !accountTypeManager.getWritableGoogleAccounts().isEmpty();
+    }
+
     public static boolean isAlertVisible(Context context, Account account, int reason) {
         if (reason == SYNC_SETTING_GLOBAL_SYNC_OFF) {
             return (SharedPreferenceUtil.getNumOfDismissesForAutoSyncOff(context) == 0);