Remove getGroupWritableAccounts method

This method would block on accounts loading. Replaced with asynchronous
loading of the group writable accounts.

Test: manually verify that labels are still shown in nav drawer

Bug 33627801

Change-Id: If1b344d5bfee59dd5b8cc5446b02742ceec1f459
diff --git a/src/com/android/contacts/ContactsDrawerActivity.java b/src/com/android/contacts/ContactsDrawerActivity.java
index fc7639a..ad4c2ac 100644
--- a/src/com/android/contacts/ContactsDrawerActivity.java
+++ b/src/com/android/contacts/ContactsDrawerActivity.java
@@ -67,6 +67,7 @@
 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;
@@ -76,6 +77,7 @@
 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;
@@ -401,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();
@@ -442,7 +445,7 @@
         }
 
         // Don't show "Create new..." menu if there's no group-writable accounts available.
-        if (!ContactsUtils.areGroupWritableAccountsAvailable(this)) {
+        if (!areGroupWritableAccountsAvailable) {
             return;
         }
 
@@ -678,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.
@@ -688,7 +693,7 @@
         }
         // 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,
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/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/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index cb0fe24..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;
@@ -155,11 +153,6 @@
         }
 
         @Override
-        public List<AccountWithDataSet> getGroupWritableAccounts() {
-            return Collections.emptyList();
-        }
-
-        @Override
         public Account getDefaultGoogleAccount() {
             return null;
         }
@@ -211,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();
@@ -613,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/tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java b/tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java
index b5ccb1e..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;
@@ -86,11 +83,6 @@
     }
 
     @Override
-    public List<AccountWithDataSet> getGroupWritableAccounts() {
-        return Arrays.asList(mAccounts);
-    }
-
-    @Override
     public Account getDefaultGoogleAccount() {
         return null;
     }