Merge changes If1b344d5,Idaffc3f0,I5a33ad27 into ub-contactsdialer-i-dev

* changes:
  Remove getGroupWritableAccounts method
  Replace getAccounts method with blockForWritableAccounts
  Add setter for accounts in AccountsListAdapter
diff --git a/src/com/android/contacts/ContactsDrawerActivity.java b/src/com/android/contacts/ContactsDrawerActivity.java
index f0bc37e..ad4c2ac 100644
--- a/src/com/android/contacts/ContactsDrawerActivity.java
+++ b/src/com/android/contacts/ContactsDrawerActivity.java
@@ -67,16 +67,17 @@
 import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.model.account.AccountDisplayInfo;
 import com.android.contacts.model.account.AccountDisplayInfoFactory;
+import com.android.contacts.model.account.AccountInfo;
 import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.preference.ContactsPreferenceActivity;
 import com.android.contacts.util.AccountFilterUtil;
-import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
 import com.android.contacts.util.ImplicitIntentsUtil;
 import com.android.contacts.util.MaterialColorMapUtils;
 import com.android.contacts.util.SharedPreferenceUtil;
 import com.android.contacts.util.ViewUtil;
 import com.android.contactsbind.HelpUtils;
 import com.android.contactsbind.ObjectFactory;
+import com.google.common.util.concurrent.Futures;
 
 import java.util.HashMap;
 import java.util.Iterator;
@@ -402,7 +403,8 @@
     }
 
     @Override
-    public void onGroupsLoaded(List<GroupListItem> groupListItems) {
+    public void onGroupsLoaded(List<GroupListItem> groupListItems,
+            boolean areGroupWritableAccountsAvailable) {
         final Menu menu = mNavigationView.getMenu();
         final MenuItem groupsMenuItem = menu.findItem(R.id.nav_groups);
         final SubMenu subMenu = groupsMenuItem.getSubMenu();
@@ -443,7 +445,7 @@
         }
 
         // Don't show "Create new..." menu if there's no group-writable accounts available.
-        if (!ContactsUtils.areGroupWritableAccountsAvailable(this)) {
+        if (!areGroupWritableAccountsAvailable) {
             return;
         }
 
@@ -679,8 +681,10 @@
     }
 
     private void selectAccountForNewGroup() {
-        final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(this)
-                .getGroupWritableAccounts();
+        // This should never block because the GroupsFragment loads the accounts and the
+        // "Create Label" item only exists when that loading finishes
+        final List<AccountInfo> accounts = Futures.getUnchecked(AccountTypeManager.getInstance(this)
+                .filterAccountsAsync(AccountTypeManager.AccountFilter.GROUPS_WRITABLE));
         if (accounts.isEmpty()) {
             // We shouldn't present the add group button if there are no writable accounts
             // but check it since it's possible we are started with an Intent.
@@ -689,11 +693,11 @@
         }
         // If there is a single writable account, use it w/o showing a dialog.
         if (accounts.size() == 1) {
-            onAccountChosen(accounts.get(0), /* extraArgs */ null);
+            onAccountChosen(accounts.get(0).getAccount(), /* extraArgs */ null);
             return;
         }
         SelectAccountDialogFragment.show(getFragmentManager(), R.string.dialog_new_group_account,
-                AccountListFilter.ACCOUNTS_GROUP_WRITABLE, /* extraArgs */ null,
+                AccountTypeManager.AccountFilter.GROUPS_WRITABLE, /* extraArgs */ null,
                 TAG_SELECT_ACCOUNT_DIALOG);
     }
 
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
index 448e696..69890b4 100644
--- a/src/com/android/contacts/ContactsUtils.java
+++ b/src/com/android/contacts/ContactsUtils.java
@@ -29,13 +29,10 @@
 
 import com.android.contacts.compat.ContactsCompat;
 import com.android.contacts.compat.DirectoryCompat;
-import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.model.dataitem.ImDataItem;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.List;
 
 public class ContactsUtils {
     private static final String TAG = "ContactsUtils";
@@ -138,12 +135,6 @@
         return TextUtils.equals(a.getAction(), b.getAction());
     }
 
-    public static boolean areGroupWritableAccountsAvailable(Context context) {
-        final List<AccountWithDataSet> accounts =
-                AccountTypeManager.getInstance(context).getGroupWritableAccounts();
-        return !accounts.isEmpty();
-    }
-
     /**
      * Returns the size (width and height) of thumbnail pictures as configured in the provider. This
      * can safely be called from the UI thread, as the provider can serve this without performing
diff --git a/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java b/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
index 2c3c2c8..2717cab 100644
--- a/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
@@ -37,7 +37,6 @@
 import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.model.account.AccountsLoader;
 import com.android.contacts.util.AccountsListAdapter;
-import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
 import com.android.contacts.util.ImplicitIntentsUtil;
 
 import java.util.List;
@@ -142,8 +141,7 @@
             button.setOnClickListener(mAddAccountClickListener);
 
             final ListView accountListView = (ListView) view.findViewById(R.id.account_list);
-            mAccountListAdapter = new AccountsListAdapter(this,
-                    AccountListFilter.ACCOUNTS_CONTACT_WRITABLE);
+            mAccountListAdapter = new AccountsListAdapter(this, accounts);
             accountListView.setAdapter(mAccountListAdapter);
             accountListView.setOnItemClickListener(mAccountListItemClickListener);
         } else if (numAccounts == 1 && !accounts.get(0).getAccount().isNullAccount()) {
diff --git a/src/com/android/contacts/editor/SelectAccountDialogFragment.java b/src/com/android/contacts/editor/SelectAccountDialogFragment.java
index fe3d9d6..88e92b7 100644
--- a/src/com/android/contacts/editor/SelectAccountDialogFragment.java
+++ b/src/com/android/contacts/editor/SelectAccountDialogFragment.java
@@ -27,43 +27,51 @@
 import android.widget.TextView;
 
 import com.android.contacts.R;
+import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.account.AccountInfo;
 import com.android.contacts.model.account.AccountWithDataSet;
+import com.android.contacts.model.account.AccountsLoader;
 import com.android.contacts.util.AccountsListAdapter;
-import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
+import com.google.common.base.Preconditions;
+
+import java.util.List;
 
 /**
  * Shows a dialog asking the user which account to chose.
  *
  * The result is passed to {@code targetFragment} passed to {@link #show}.
  */
-public final class SelectAccountDialogFragment extends DialogFragment {
+public final class SelectAccountDialogFragment extends DialogFragment
+        implements AccountsLoader.AccountsListener {
     public static final String TAG = "SelectAccountDialogFragment";
 
     private static final String KEY_TITLE_RES_ID = "title_res_id";
     private static final String KEY_LIST_FILTER = "list_filter";
     private static final String KEY_EXTRA_ARGS = "extra_args";
 
+    private AccountsListAdapter mAccountsAdapter;
+    private AccountTypeManager.AccountFilter mFilter;
+
     /**
      * Show the dialog.
      *
      * @param fragmentManager {@link FragmentManager}.
      * @param titleResourceId resource ID to use as the title.
-     * @param accountListFilter account filter.
      * @param extraArgs Extra arguments, which will later be passed to
      *     {@link Listener#onAccountChosen}.  {@code null} will be converted to
      *     {@link Bundle#EMPTY}.
      */
     public static void show(FragmentManager fragmentManager, int titleResourceId,
-            AccountListFilter accountListFilter, Bundle extraArgs) {
-        show(fragmentManager, titleResourceId, accountListFilter, extraArgs, /* tag */ null);
+            AccountTypeManager.AccountFilter filter, Bundle extraArgs) {
+        show(fragmentManager, titleResourceId, filter, extraArgs, /* tag */ null);
     }
 
     public static void show(FragmentManager fragmentManager, int titleResourceId,
-            AccountListFilter accountListFilter, Bundle extraArgs, String tag) {
+            AccountTypeManager.AccountFilter filter, Bundle extraArgs, String tag) {
         final Bundle args = new Bundle();
         args.putInt(KEY_TITLE_RES_ID, titleResourceId);
-        args.putSerializable(KEY_LIST_FILTER, accountListFilter);
         args.putBundle(KEY_EXTRA_ARGS, (extraArgs == null) ? Bundle.EMPTY : extraArgs);
+        args.putSerializable(KEY_LIST_FILTER, filter);
 
         final SelectAccountDialogFragment instance = new SelectAccountDialogFragment();
         instance.setArguments(args);
@@ -71,14 +79,22 @@
     }
 
     @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final Bundle args = getArguments();
+        mFilter = (AccountTypeManager.AccountFilter) args.getSerializable(KEY_LIST_FILTER);
+        if (mFilter == null) {
+            mFilter = AccountTypeManager.AccountFilter.ALL;
+        }
+    }
+
+    @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
         final Bundle args = getArguments();
 
-        final AccountListFilter filter = (AccountListFilter) args.getSerializable(KEY_LIST_FILTER);
-        final AccountsListAdapter accountAdapter = new AccountsListAdapter(builder.getContext(),
-                filter);
-        accountAdapter.setCustomLayout(R.layout.account_selector_list_item_condensed);
+        mAccountsAdapter = new AccountsListAdapter(builder.getContext());
+        mAccountsAdapter.setCustomLayout(R.layout.account_selector_list_item_condensed);
 
         final DialogInterface.OnClickListener clickListener =
                 new DialogInterface.OnClickListener() {
@@ -86,19 +102,25 @@
             public void onClick(DialogInterface dialog, int which) {
                 dialog.dismiss();
 
-                onAccountSelected(accountAdapter.getItem(which));
+                onAccountSelected(mAccountsAdapter.getItem(which));
             }
         };
 
         final TextView title = (TextView) View.inflate(getActivity(), R.layout.dialog_title, null);
         title.setText(args.getInt(KEY_TITLE_RES_ID));
         builder.setCustomTitle(title);
-        builder.setSingleChoiceItems(accountAdapter, 0, clickListener);
+        builder.setSingleChoiceItems(mAccountsAdapter, 0, clickListener);
         final AlertDialog result = builder.create();
         return result;
     }
 
     @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        AccountsLoader.loadAccounts(this, 0, mFilter);
+    }
+
+    @Override
     public void onCancel(DialogInterface dialog) {
         super.onCancel(dialog);
         final Listener listener = getListener();
@@ -126,6 +148,13 @@
         return listener;
     }
 
+    @Override
+    public void onAccountsLoaded(List<AccountInfo> accounts) {
+        Preconditions.checkNotNull(mAccountsAdapter,
+                "Accounts adapter should have been initialized");
+        mAccountsAdapter.setAccounts(accounts, null);
+    }
+
     public interface Listener {
         void onAccountChosen(AccountWithDataSet account, Bundle extraArgs);
         void onAccountSelectorCancelled();
diff --git a/src/com/android/contacts/group/GroupsFragment.java b/src/com/android/contacts/group/GroupsFragment.java
index 522d3ba..e2a1de4 100644
--- a/src/com/android/contacts/group/GroupsFragment.java
+++ b/src/com/android/contacts/group/GroupsFragment.java
@@ -24,6 +24,9 @@
 import android.os.Bundle;
 
 import com.android.contacts.GroupListLoader;
+import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.account.AccountInfo;
+import com.android.contacts.model.account.AccountsLoader;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -31,9 +34,10 @@
 /**
  * Loads groups and group metadata for all accounts.
  */
-public final class GroupsFragment extends Fragment {
+public final class GroupsFragment extends Fragment implements AccountsLoader.AccountsListener {
 
     private static final int LOADER_GROUPS = 1;
+    private static final int LOADER_ACCOUNTS = 2;
 
     /**
      * Callbacks for hosts of the {@link GroupsFragment}.
@@ -43,7 +47,8 @@
         /**
          * Invoked after groups and group metadata have been loaded.
          */
-        void onGroupsLoaded(List<GroupListItem> groupListItems);
+        void onGroupsLoaded(List<GroupListItem> groupListItems,
+                boolean areGroupWritableAccountsAvailable);
     }
 
     private final LoaderManager.LoaderCallbacks<Cursor> mGroupListLoaderListener =
@@ -65,9 +70,8 @@
                             mGroupListItems.add(GroupUtil.getGroupListItem(data, i));
                         }
                     }
-                    if (mListener != null) {
-                        mListener.onGroupsLoaded(mGroupListItems);
-                    }
+                    mGroupsLoaded = true;
+                    notifyIfReady();
                 }
 
                 public void onLoaderReset(Loader<Cursor> loader) {
@@ -75,15 +79,33 @@
             };
 
     private List<GroupListItem> mGroupListItems = new ArrayList<>();
+    private boolean mHasGroupWritableAccounts = false;
+    private boolean mGroupsLoaded = false;
+    private boolean mAccountsLoaded = false;
     private GroupsListener mListener;
 
     @Override
-    public void onStart() {
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        AccountsLoader.loadAccounts(this, LOADER_ACCOUNTS,
+                AccountTypeManager.AccountFilter.GROUPS_WRITABLE);
         getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupListLoaderListener);
-        super.onStart();
     }
 
     public void setListener(GroupsListener listener) {
         mListener = listener;
     }
+
+    @Override
+    public void onAccountsLoaded(List<AccountInfo> accounts) {
+        mHasGroupWritableAccounts = !accounts.isEmpty();
+        mAccountsLoaded = true;
+        notifyIfReady();
+    }
+
+    private void notifyIfReady() {
+        if (mAccountsLoaded && mGroupsLoaded && mListener != null) {
+            mListener.onGroupsLoaded(mGroupListItems, mHasGroupWritableAccounts);
+        }
+    }
 }
diff --git a/src/com/android/contacts/interactions/ImportDialogFragment.java b/src/com/android/contacts/interactions/ImportDialogFragment.java
index 5bf4fe4..367ae2f 100644
--- a/src/com/android/contacts/interactions/ImportDialogFragment.java
+++ b/src/com/android/contacts/interactions/ImportDialogFragment.java
@@ -44,12 +44,9 @@
 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;
@@ -274,7 +271,7 @@
             args.putInt(KEY_SUBSCRIPTION_ID, subscriptionId);
             SelectAccountDialogFragment.show(
                     getFragmentManager(), R.string.dialog_new_contact_account,
-                    AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, args);
+                    AccountTypeManager.AccountFilter.CONTACTS_WRITABLE, args);
         } else {
             AccountSelectionUtil.doImport(getActivity(), resId,
                     (size == 1 ? accountList.get(0) : null),
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index cbdccd5..f8e20e8 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -54,9 +54,7 @@
 import com.google.common.base.Function;
 import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
 import com.google.common.collect.Collections2;
-import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -83,6 +81,27 @@
     public static final String BROADCAST_ACCOUNTS_CHANGED = AccountTypeManager.class.getName() +
             ".AccountsChanged";
 
+    public enum AccountFilter implements Predicate<AccountInfo> {
+        ALL {
+            @Override
+            public boolean apply(@Nullable AccountInfo input) {
+                return input != null;
+            }
+        },
+        CONTACTS_WRITABLE {
+            @Override
+            public boolean apply(@Nullable AccountInfo input) {
+                return input != null && input.getType().areContactsWritable();
+            }
+        },
+        GROUPS_WRITABLE {
+            @Override
+            public boolean apply(@Nullable AccountInfo input) {
+                return input != null && input.getType().isGroupMembershipEditable();
+            }
+        };
+    }
+
     /**
      * Requests the singleton instance of {@link AccountTypeManager} with data bound from
      * the available authenticators. This method can safely be called from the UI thread.
@@ -118,11 +137,6 @@
     private static final AccountTypeManager EMPTY = new AccountTypeManager() {
 
         @Override
-        public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly) {
-            return Collections.emptyList();
-        }
-
-        @Override
         public ListenableFuture<List<AccountInfo>> getAccountsAsync() {
             return Futures.immediateFuture(Collections.<AccountInfo>emptyList());
         }
@@ -139,11 +153,6 @@
         }
 
         @Override
-        public List<AccountWithDataSet> getGroupWritableAccounts() {
-            return Collections.emptyList();
-        }
-
-        @Override
         public Account getDefaultGoogleAccount() {
             return null;
         }
@@ -157,9 +166,29 @@
     /**
      * Returns the list of all accounts (if contactWritableOnly is false) or just the list of
      * contact writable accounts (if contactWritableOnly is true).
+     *
+     * <p>TODO(mhagerott) delete this method. It's left in place to prevent build breakages when
+     * this change is automerged. Usages of this method in downstream branches should be
+     * replaced with an asynchronous account loading pattern</p>
      */
-    // TODO: Consider splitting this into getContactWritableAccounts() and getAllAccounts()
-    public abstract List<AccountWithDataSet> getAccounts(boolean contactWritableOnly);
+    public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly) {
+        return contactWritableOnly
+                ? blockForWritableAccounts()
+                : AccountInfo.extractAccounts(Futures.getUnchecked(getAccountsAsync()));
+    }
+
+    /**
+     * Returns all contact writable accounts
+     *
+     * <p>In general this method should be avoided. It exists to support some legacy usages of
+     * accounts in infrequently used features where refactoring to asynchronous loading is
+     * not justified. The chance that this will actually block is pretty low if the app has been
+     * launched previously</p>
+     */
+    public List<AccountWithDataSet> blockForWritableAccounts() {
+        return AccountInfo.extractAccounts(
+                Futures.getUnchecked(filterAccountsAsync(AccountFilter.CONTACTS_WRITABLE)));
+    }
 
     /**
      * Loads accounts in background and returns future that will complete with list of all accounts
@@ -175,11 +204,6 @@
     public abstract AccountInfo getAccountInfoForAccount(AccountWithDataSet account);
 
     /**
-     * Returns the list of accounts that are group writable.
-     */
-    public abstract List<AccountWithDataSet> getGroupWritableAccounts();
-
-    /**
      * Returns the default google account.
      */
     public abstract Account getDefaultGoogleAccount();
@@ -298,43 +322,12 @@
         return canGetAccounts && canReadContacts;
     }
 
-    public static Predicate<AccountInfo> nonNullAccountFilter() {
-        return new Predicate<AccountInfo>() {
-            @Override
-            public boolean apply(AccountInfo info) {
-                AccountWithDataSet account = info != null ? info.getAccount() : null;
-                return account != null && !account.isNullAccount();
-            }
-        };
-
-    }
-
     public static Predicate<AccountInfo> writableFilter() {
-        return new Predicate<AccountInfo>() {
-            @Override
-            public boolean apply(AccountInfo account) {
-                return account.getType().areContactsWritable();
-            }
-        };
+        return AccountFilter.CONTACTS_WRITABLE;
     }
 
     public static Predicate<AccountInfo> groupWritableFilter() {
-        return new Predicate<AccountInfo>() {
-            @Override
-            public boolean apply(@Nullable AccountInfo account) {
-                return account.getType().isGroupMembershipEditable();
-            }
-        };
-    }
-
-    public static Predicate<AccountInfo> onlyNonEmptyExtensionFilter(Context context) {
-        final Context appContext = context.getApplicationContext();
-        return new Predicate<AccountInfo>() {
-            @Override
-            public boolean apply(@Nullable AccountInfo input) {
-                return !input.getType().isExtension() || input.getAccount().hasData(appContext);
-            }
-        };
+        return AccountFilter.GROUPS_WRITABLE;
     }
 }
 
@@ -530,19 +523,6 @@
                 mMainThreadExecutor);
     }
 
-    /**
-     * Return list of all known or contact writable {@link AccountWithDataSet}'s.
-     * {@param contactWritableOnly} whether to restrict to contact writable accounts only
-     */
-    @Override
-    public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly) {
-        final Predicate<AccountInfo> filter = contactWritableOnly ?
-                writableFilter() : Predicates.<AccountInfo>alwaysTrue();
-        // TODO: Shouldn't have a synchronous version for getting all accounts
-        return Lists.transform(Futures.getUnchecked(filterAccountsAsync(filter)),
-                AccountInfo.ACCOUNT_EXTRACTOR);
-    }
-
     @Override
     public ListenableFuture<List<AccountInfo>> getAccountsAsync() {
         return getAllAccountsAsyncInternal();
@@ -621,14 +601,6 @@
     }
 
     /**
-     * Return the list of all known, group writable {@link AccountWithDataSet}'s.
-     */
-    public List<AccountWithDataSet> getGroupWritableAccounts() {
-        return Lists.transform(Futures.getUnchecked(
-                filterAccountsAsync(groupWritableFilter())), AccountInfo.ACCOUNT_EXTRACTOR);
-    }
-
-    /**
      * Returns the default google account specified in preferences, the first google account
      * if it is not specified in preferences or is no longer on the device, and null otherwise.
      */
diff --git a/src/com/android/contacts/model/account/AccountsLoader.java b/src/com/android/contacts/model/account/AccountsLoader.java
index 260c44b..e3b4336 100644
--- a/src/com/android/contacts/model/account/AccountsLoader.java
+++ b/src/com/android/contacts/model/account/AccountsLoader.java
@@ -71,6 +71,8 @@
      * <p>This is a convenience method to reduce the
      * boilerplate needed when implementing {@link android.app.LoaderManager.LoaderCallbacks}
      * in the simple case that the fragment wants to just load the accounts directly</p>
+     * <p>Note that changing the filter between invocations in the same component will not work
+     * properly because the loader is cached.</p>
      */
     public static <FragmentType extends Fragment & AccountsListener> void loadAccounts(
             final FragmentType fragment, int loaderId, final Predicate<AccountInfo> filter) {
@@ -78,6 +80,9 @@
                 fragment.getActivity(), fragment.getLoaderManager(), loaderId, filter, fragment);
     }
 
+    /**
+     * Same as {@link #loadAccounts(Fragment, int, Predicate)} for an Activity
+     */
     public static <ActivityType extends Activity & AccountsListener> void loadAccounts(
             final ActivityType activity, int id, final Predicate<AccountInfo> filter) {
         loadAccounts(activity, activity.getLoaderManager(), id, filter, activity);
diff --git a/src/com/android/contacts/preference/DefaultAccountPreference.java b/src/com/android/contacts/preference/DefaultAccountPreference.java
index 72ba74d..efff5a0 100644
--- a/src/com/android/contacts/preference/DefaultAccountPreference.java
+++ b/src/com/android/contacts/preference/DefaultAccountPreference.java
@@ -24,14 +24,17 @@
 import android.view.View;
 
 import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.account.AccountDisplayInfoFactory;
+import com.android.contacts.model.account.AccountInfo;
 import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.util.AccountsListAdapter;
 
+import java.util.List;
+
 public class DefaultAccountPreference extends DialogPreference {
     private ContactsPreferences mPreferences;
     private AccountsListAdapter mListAdapter;
     private AccountTypeManager mAccountTypeManager;
+    private List<AccountInfo> mAccounts;
     private int mChosenIndex = -1;
 
     public DefaultAccountPreference(Context context) {
@@ -44,6 +47,13 @@
         prepare();
     }
 
+    public void setAccounts(List<AccountInfo> accounts) {
+        mAccounts = accounts;
+        if (mListAdapter != null) {
+            mListAdapter.setAccounts(accounts, null);
+        }
+    }
+
     @Override
     protected View onCreateDialogView() {
         prepare();
@@ -52,8 +62,10 @@
 
     private void prepare() {
         mPreferences = new ContactsPreferences(getContext());
-        mListAdapter = new AccountsListAdapter(getContext(),
-                AccountsListAdapter.AccountListFilter.ACCOUNTS_CONTACT_WRITABLE);
+        mListAdapter = new AccountsListAdapter(getContext());
+        if (mAccounts != null) {
+            mListAdapter.setAccounts(mAccounts, null);
+        }
         mAccountTypeManager = AccountTypeManager.getInstance(getContext());
     }
 
diff --git a/src/com/android/contacts/preference/DisplayOptionsPreferenceFragment.java b/src/com/android/contacts/preference/DisplayOptionsPreferenceFragment.java
index a9ec250..e9c3a01 100644
--- a/src/com/android/contacts/preference/DisplayOptionsPreferenceFragment.java
+++ b/src/com/android/contacts/preference/DisplayOptionsPreferenceFragment.java
@@ -297,6 +297,10 @@
         if (accounts.isEmpty()) {
             getPreferenceScreen().removePreference(findPreference(KEY_DEFAULT_ACCOUNT));
             getPreferenceScreen().removePreference(findPreference(KEY_CUSTOM_CONTACTS_FILTER));
+        } else {
+            final DefaultAccountPreference preference =
+                    (DefaultAccountPreference) findPreference(KEY_DEFAULT_ACCOUNT);
+            preference.setAccounts(accounts);
         }
     }
 
diff --git a/src/com/android/contacts/util/AccountSelectionUtil.java b/src/com/android/contacts/util/AccountSelectionUtil.java
index a29af9a..bfe8a08 100644
--- a/src/com/android/contacts/util/AccountSelectionUtil.java
+++ b/src/com/android/contacts/util/AccountSelectionUtil.java
@@ -84,15 +84,6 @@
         }
     }
 
-    public static Dialog getSelectAccountDialog(Activity activity, int resId) {
-        return getSelectAccountDialog(activity, resId, null, null);
-    }
-
-    public static Dialog getSelectAccountDialog(Activity activity, int resId,
-            DialogInterface.OnClickListener onClickListener) {
-        return getSelectAccountDialog(activity, resId, onClickListener, null);
-    }
-
     /**
      * When OnClickListener or OnCancelListener is null, uses a default listener.
      * The default OnCancelListener just closes itself with {@link Dialog#dismiss()}.
@@ -101,7 +92,8 @@
             DialogInterface.OnClickListener onClickListener,
             DialogInterface.OnCancelListener onCancelListener) {
         final AccountTypeManager accountTypes = AccountTypeManager.getInstance(activity);
-        final List<AccountWithDataSet> writableAccountList = accountTypes.getAccounts(true);
+        final List<AccountWithDataSet> writableAccountList =
+                accountTypes.blockForWritableAccounts();
 
         Log.i(LOG_TAG, "The number of available accounts: " + writableAccountList.size());
 
diff --git a/src/com/android/contacts/util/AccountsListAdapter.java b/src/com/android/contacts/util/AccountsListAdapter.java
index 005bb8d..2bcc68b 100644
--- a/src/com/android/contacts/util/AccountsListAdapter.java
+++ b/src/com/android/contacts/util/AccountsListAdapter.java
@@ -30,6 +30,7 @@
 import com.android.contacts.model.account.AccountWithDataSet;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -37,50 +38,11 @@
  */
 public final class AccountsListAdapter extends BaseAdapter {
     private final LayoutInflater mInflater;
-    private final List<AccountInfo> mAccounts;
-    private final Context mContext;
+    private List<AccountInfo> mAccounts;
     private int mCustomLayout = -1;
 
-    public enum AccountListFilter {
-        ALL_ACCOUNTS {
-            @Override
-            public List<AccountWithDataSet> getSourceAccounts(Context context) {
-                return AccountTypeManager.getInstance(context).getAccounts(false);
-            }
-        },
-        ACCOUNTS_CONTACT_WRITABLE {
-            @Override
-            public List<AccountWithDataSet> getSourceAccounts(Context context) {
-                return AccountTypeManager.getInstance(context).getAccounts(true);
-            }
-        },
-        ACCOUNTS_GROUP_WRITABLE {
-            @Override
-            public List<AccountWithDataSet> getSourceAccounts(Context context) {
-                return AccountTypeManager.getInstance(context).getGroupWritableAccounts();
-            }
-        };
-
-        private List<AccountInfo> getAccounts(Context context) {
-            final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(context);
-            final List<AccountInfo> result = new ArrayList<>();
-            final List<AccountWithDataSet> sourceAccounts = getSourceAccounts(context);
-            for (AccountWithDataSet account : sourceAccounts) {
-                result.add(accountTypeManager.getAccountInfoForAccount(account));
-            }
-            return result;
-        }
-
-        public abstract List<AccountWithDataSet> getSourceAccounts(Context context);
-    }
-
-    public AccountsListAdapter(Context context, AccountListFilter filter) {
-        this(context, filter.getAccounts(context), null);
-    }
-
-    public AccountsListAdapter(Context context, AccountListFilter filter,
-            AccountWithDataSet currentAccount) {
-        this(context, filter.getAccounts(context), currentAccount);
+    public AccountsListAdapter(Context context) {
+        this(context, Collections.<AccountInfo>emptyList(), null);
     }
 
     public AccountsListAdapter(Context context, List<AccountInfo> accounts) {
@@ -93,19 +55,28 @@
      */
     public AccountsListAdapter(Context context, List<AccountInfo> accounts,
             AccountWithDataSet currentAccount) {
-        mContext = context;
-
-        final AccountInfo currentInfo = AccountInfo.getAccount(accounts, currentAccount);
-        if (currentInfo != null
-                && !accounts.isEmpty()
-                && !accounts.get(0).sameAccount(currentAccount)
-                && accounts.remove(currentInfo)) {
-            accounts.add(0, currentInfo);
-        }
-
         mInflater = LayoutInflater.from(context);
 
-        mAccounts = accounts;
+        mAccounts = new ArrayList<>(accounts.size());
+        setAccounts(accounts, currentAccount);
+    }
+
+    public void setAccounts(List<AccountInfo> accounts, AccountWithDataSet currentAccount) {
+        // If it's not empty use the previous "current" account (the first one in the list)
+        final AccountInfo currentInfo = mAccounts.isEmpty()
+                ? AccountInfo.getAccount(accounts, currentAccount)
+                : AccountInfo.getAccount(accounts, mAccounts.get(0).getAccount());
+
+        mAccounts.clear();
+        mAccounts.addAll(accounts);
+
+        if (currentInfo != null
+                && !mAccounts.isEmpty()
+                && !mAccounts.get(0).sameAccount(currentAccount)
+                && mAccounts.remove(currentInfo)) {
+            mAccounts.add(0, currentInfo);
+        }
+        notifyDataSetChanged();
     }
 
     public void setCustomLayout(int customLayout) {
diff --git a/src/com/android/contacts/vcard/ImportVCardActivity.java b/src/com/android/contacts/vcard/ImportVCardActivity.java
index 6d486e3..2c69cdf 100644
--- a/src/com/android/contacts/vcard/ImportVCardActivity.java
+++ b/src/com/android/contacts/vcard/ImportVCardActivity.java
@@ -597,7 +597,7 @@
             mAccount = new AccountWithDataSet(accountName, accountType, dataSet);
         } else {
             final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
-            final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
+            final List<AccountWithDataSet> accountList = accountTypes.blockForWritableAccounts();
             if (accountList.size() == 0) {
                 mAccount = null;
             } else if (accountList.size() == 1) {
diff --git a/src/com/android/contacts/vcard/NfcImportVCardActivity.java b/src/com/android/contacts/vcard/NfcImportVCardActivity.java
index 4793d47..4eb9b57 100644
--- a/src/com/android/contacts/vcard/NfcImportVCardActivity.java
+++ b/src/com/android/contacts/vcard/NfcImportVCardActivity.java
@@ -194,7 +194,7 @@
         mRecord = msg.getRecords()[0];
 
         final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
-        final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
+        final List<AccountWithDataSet> accountList = accountTypes.blockForWritableAccounts();
         if (accountList.size() == 0) {
             mAccount = null;
         } else if (accountList.size() == 1) {
diff --git a/src/com/android/contacts/vcard/SelectAccountActivity.java b/src/com/android/contacts/vcard/SelectAccountActivity.java
index 8809fac..ac5b3eb 100644
--- a/src/com/android/contacts/vcard/SelectAccountActivity.java
+++ b/src/com/android/contacts/vcard/SelectAccountActivity.java
@@ -58,7 +58,7 @@
         // - no account -> use phone-local storage without asking the user
         final int resId = R.string.import_from_vcf_file;
         final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
-        final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
+        final List<AccountWithDataSet> accountList = accountTypes.blockForWritableAccounts();
         if (accountList.size() == 0) {
             Log.w(LOG_TAG, "Account does not exist");
             finish();
diff --git a/tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java b/tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java
index 956f775..d5c1ccb 100644
--- a/tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java
+++ b/tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java
@@ -25,9 +25,6 @@
 import com.android.contacts.model.account.BaseAccountType;
 import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 
 import java.util.Arrays;
@@ -66,7 +63,7 @@
     }
 
     @Override
-    public List<AccountWithDataSet> getAccounts(boolean writableOnly) {
+    public List<AccountWithDataSet> blockForWritableAccounts() {
         return Arrays.asList(mAccounts);
     }
 
@@ -86,11 +83,6 @@
     }
 
     @Override
-    public List<AccountWithDataSet> getGroupWritableAccounts() {
-        return Arrays.asList(mAccounts);
-    }
-
-    @Override
     public Account getDefaultGoogleAccount() {
         return null;
     }