Fix account list for group editing (for master)
- Don't use contact writable account list to populate the
account picker when creating new groups, instead check for
isGroupMembershipEditable() on the account type
- Repeat the same for determining whether the "new group"
button should appear in the PeopleActivity or not
Bug: 5360120
Change-Id: Ifd2fd1cf4ea7bf02d4dcba3e9c023bd7041fab83
Original-Id: Ia1ec62eff3fe4fd5b495548218c58f238ff49788
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
index 4de62b6..9a3f2ef 100644
--- a/src/com/android/contacts/ContactsUtils.java
+++ b/src/com/android/contacts/ContactsUtils.java
@@ -16,6 +16,7 @@
package com.android.contacts;
+import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.model.AccountWithDataSet;
import com.android.contacts.test.NeededForTesting;
@@ -172,11 +173,15 @@
return detector.detectCountry().getCountryIso();
}
- public static boolean areAccountsAvailable(Context context) {
+ public static boolean areContactWritableAccountsAvailable(Context context) {
final List<AccountWithDataSet> accounts =
AccountTypeManager.getInstance(context).getAccounts(true /* writeable */);
return !accounts.isEmpty();
}
-
+ public static boolean areGroupWritableAccountsAvailable(Context context) {
+ final List<AccountWithDataSet> accounts =
+ AccountTypeManager.getInstance(context).getGroupWritableAccounts();
+ return !accounts.isEmpty();
+ }
}
diff --git a/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java b/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
index d63ea6a..3e2a893 100644
--- a/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
@@ -16,7 +16,6 @@
package com.android.contacts.activities;
-import android.accounts.Account;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
@@ -34,6 +33,7 @@
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.model.AccountWithDataSet;
import com.android.contacts.util.AccountsListAdapter;
+import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
import java.util.List;
@@ -97,7 +97,8 @@
button.setOnClickListener(mAddAccountClickListener);
final ListView accountListView = (ListView) findViewById(R.id.account_list);
- mAccountListAdapter = new AccountsListAdapter(this, true);
+ mAccountListAdapter = new AccountsListAdapter(this,
+ AccountListFilter.ACCOUNTS_CONTACT_WRITABLE);
accountListView.setAdapter(mAccountListAdapter);
accountListView.setOnItemClickListener(mAccountListItemClickListener);
} else if (numAccounts == 1) {
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 3430109..b088b89 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -56,6 +56,7 @@
import com.android.contacts.util.AccountPromptUtils;
import com.android.contacts.util.AccountSelectionUtil;
import com.android.contacts.util.AccountsListAdapter;
+import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
import com.android.contacts.util.Constants;
import com.android.contacts.util.DialogManager;
import com.android.contacts.util.PhoneCapabilityTester;
@@ -200,10 +201,13 @@
return mProviderStatus == ProviderStatus.STATUS_NORMAL;
}
- private boolean areAccountsAvailable() {
- return ContactsUtils.areAccountsAvailable(this);
+ private boolean areContactWritableAccountsAvailable() {
+ return ContactsUtils.areContactWritableAccountsAvailable(this);
}
+ private boolean areGroupWritableAccountsAvailable() {
+ return ContactsUtils.areGroupWritableAccountsAvailable(this);
+ }
/**
* Initialize fragments that are (or may not be) in the layout.
@@ -604,7 +608,7 @@
invalidateOptionsMenu();
showEmptyStateForTab(tab);
if (tab == TabState.GROUPS) {
- mGroupsFragment.setAddAccountsVisibility(!areAccountsAvailable());
+ mGroupsFragment.setAddAccountsVisibility(!areGroupWritableAccountsAvailable());
}
return;
}
@@ -625,7 +629,7 @@
mFavoritesView.setVisibility(View.GONE);
mBrowserView.setVisibility(View.VISIBLE);
mDetailsView.setVisibility(View.VISIBLE);
- mGroupsFragment.setAddAccountsVisibility(!areAccountsAvailable());
+ mGroupsFragment.setAddAccountsVisibility(!areGroupWritableAccountsAvailable());
break;
case ALL:
mFavoritesView.setVisibility(View.GONE);
@@ -686,7 +690,7 @@
break;
case GROUPS:
mContactsUnavailableFragment.setMessageText(R.string.noGroups,
- areAccountsAvailable() ? -1 : R.string.noAccounts);
+ areGroupWritableAccountsAvailable() ? -1 : R.string.noAccounts);
break;
case ALL:
mContactsUnavailableFragment.setMessageText(R.string.noContacts, -1);
@@ -712,7 +716,7 @@
mActionBarAdapter.setCurrentTab(selectedTab, false);
showEmptyStateForTab(selectedTab);
if (selectedTab == TabState.GROUPS) {
- mGroupsFragment.setAddAccountsVisibility(!areAccountsAvailable());
+ mGroupsFragment.setAddAccountsVisibility(!areGroupWritableAccountsAvailable());
}
invalidateOptionsMenu();
}
@@ -922,7 +926,8 @@
// If there are no accounts on the device and we should show the "no account" prompt
// (based on {@link SharedPreferences}), then launch the account setup activity so the
// user can sign-in or create an account.
- if (!areAccountsAvailable() && AccountPromptUtils.shouldShowAccountPrompt(this)) {
+ if (!areContactWritableAccountsAvailable() &&
+ AccountPromptUtils.shouldShowAccountPrompt(this)) {
AccountPromptUtils.launchAccountPrompt(this);
return;
}
@@ -1304,7 +1309,7 @@
break;
case GROUPS:
// Do not display the "new group" button if no accounts are available
- if (areAccountsAvailable()) {
+ if (areGroupWritableAccountsAvailable()) {
addGroupMenu.setVisible(true);
} else {
addGroupMenu.setVisible(false);
@@ -1410,7 +1415,8 @@
popup.setAnchorView(mAddGroupImageView);
// Create a list adapter with all writeable accounts (assume that the writeable accounts all
// allow group creation).
- final AccountsListAdapter adapter = new AccountsListAdapter(this, true);
+ final AccountsListAdapter adapter = new AccountsListAdapter(this,
+ AccountListFilter.ACCOUNTS_GROUP_WRITABLE);
popup.setAdapter(adapter);
popup.setOnItemClickListener(new OnItemClickListener() {
@Override
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 062c021..b341f83 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -34,6 +34,7 @@
import com.android.contacts.model.EntityModifier;
import com.android.contacts.model.GoogleAccountType;
import com.android.contacts.util.AccountsListAdapter;
+import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
import android.accounts.Account;
import android.app.Activity;
@@ -826,7 +827,8 @@
public void onClick(View v) {
final ListPopupWindow popup = new ListPopupWindow(mContext, null);
final AccountsListAdapter adapter =
- new AccountsListAdapter(mContext, true, currentAccount);
+ new AccountsListAdapter(mContext,
+ AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, currentAccount);
popup.setWidth(anchorView.getWidth());
popup.setAnchorView(anchorView);
popup.setAdapter(adapter);
diff --git a/src/com/android/contacts/editor/SelectAccountDialogFragment.java b/src/com/android/contacts/editor/SelectAccountDialogFragment.java
index 9dbe20a..3a8681a 100644
--- a/src/com/android/contacts/editor/SelectAccountDialogFragment.java
+++ b/src/com/android/contacts/editor/SelectAccountDialogFragment.java
@@ -19,6 +19,7 @@
import com.android.contacts.R;
import com.android.contacts.model.AccountWithDataSet;
import com.android.contacts.util.AccountsListAdapter;
+import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -37,13 +38,18 @@
public class SelectAccountDialogFragment extends DialogFragment {
public static final String TAG = "SelectAccountDialogFragment";
- private int mTitleResourceId = R.string.dialog_new_contact_account;
+ // TODO: This dialog is used in the context of group editing by default, but should be generic
+ // to work for contact editing as well. Save/restore the resource ID and account list filter
+ // that are passed in as parameters on device rotation. Bug: 5369853
+ private int mTitleResourceId = R.string.dialog_new_group_account;
+ private AccountListFilter mAccountListFilter = AccountListFilter.ACCOUNTS_GROUP_WRITABLE;
public SelectAccountDialogFragment() {
}
- public SelectAccountDialogFragment(int titleResourceId) {
+ public SelectAccountDialogFragment(int titleResourceId, AccountListFilter accountListFilter) {
mTitleResourceId = titleResourceId;
+ mAccountListFilter = accountListFilter;
}
@Override
@@ -51,7 +57,7 @@
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final AccountsListAdapter accountAdapter = new AccountsListAdapter(builder.getContext(),
- true);
+ mAccountListFilter);
final DialogInterface.OnClickListener clickListener =
new DialogInterface.OnClickListener() {
diff --git a/src/com/android/contacts/group/GroupBrowseListFragment.java b/src/com/android/contacts/group/GroupBrowseListFragment.java
index 82539e8..79bdd09 100644
--- a/src/com/android/contacts/group/GroupBrowseListFragment.java
+++ b/src/com/android/contacts/group/GroupBrowseListFragment.java
@@ -144,7 +144,7 @@
startActivity(intent);
}
});
- setAddAccountsVisibility(!ContactsUtils.areAccountsAvailable(mContext));
+ setAddAccountsVisibility(!ContactsUtils.areGroupWritableAccountsAvailable(mContext));
return mRootView;
}
@@ -214,7 +214,7 @@
private void bindGroupList() {
mEmptyView.setText(R.string.noGroups);
- setAddAccountsVisibility(!ContactsUtils.areAccountsAvailable(mContext));
+ setAddAccountsVisibility(!ContactsUtils.areGroupWritableAccountsAvailable(mContext));
if (mGroupListCursor == null) {
return;
}
diff --git a/src/com/android/contacts/group/GroupEditorFragment.java b/src/com/android/contacts/group/GroupEditorFragment.java
index 99e6b48..1d1237e 100644
--- a/src/com/android/contacts/group/GroupEditorFragment.java
+++ b/src/com/android/contacts/group/GroupEditorFragment.java
@@ -28,6 +28,7 @@
import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
import com.android.internal.util.Objects;
import android.accounts.Account;
@@ -332,7 +333,7 @@
mStatus = Status.SELECTING_ACCOUNT;
final SelectAccountDialogFragment dialog = new SelectAccountDialogFragment(
- R.string.dialog_new_group_account);
+ R.string.dialog_new_group_account, AccountListFilter.ACCOUNTS_GROUP_WRITABLE);
dialog.setTargetFragment(this, 0);
dialog.show(getFragmentManager(), SelectAccountDialogFragment.TAG);
}
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index dc2fb0d..5443196 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -85,7 +85,17 @@
return new AccountTypeManagerImpl(context);
}
- public abstract List<AccountWithDataSet> getAccounts(boolean writableOnly);
+ /**
+ * Returns the list of all accounts (if contactWritableOnly is false) or just the list of
+ * contact writable accounts (if contactWritableOnly is true).
+ */
+ // TODO: Consider splitting this into getContactWritableAccounts() and getAllAccounts()
+ public abstract List<AccountWithDataSet> getAccounts(boolean contactWritableOnly);
+
+ /**
+ * Returns the list of accounts that are group writable.
+ */
+ public abstract List<AccountWithDataSet> getGroupWritableAccounts();
public abstract AccountType getAccountType(AccountTypeWithDataSet accountTypeWithDataSet);
@@ -130,7 +140,8 @@
private AccountType mFallbackAccountType;
private List<AccountWithDataSet> mAccounts = Lists.newArrayList();
- private List<AccountWithDataSet> mWritableAccounts = Lists.newArrayList();
+ private List<AccountWithDataSet> mContactWritableAccounts = Lists.newArrayList();
+ private List<AccountWithDataSet> mGroupWritableAccounts = Lists.newArrayList();
private Map<AccountTypeWithDataSet, AccountType> mAccountTypesWithDataSets = Maps.newHashMap();
private Map<AccountTypeWithDataSet, AccountType> mInvitableAccountTypes =
Collections.unmodifiableMap(new HashMap<AccountTypeWithDataSet, AccountType>());
@@ -288,16 +299,18 @@
final long startTimeWall = SystemClock.elapsedRealtime();
// Account types, keyed off the account type and data set concatenation.
- Map<AccountTypeWithDataSet, AccountType> accountTypesByTypeAndDataSet = Maps.newHashMap();
+ final Map<AccountTypeWithDataSet, AccountType> accountTypesByTypeAndDataSet =
+ Maps.newHashMap();
// The same AccountTypes, but keyed off {@link RawContacts#ACCOUNT_TYPE}. Since there can
// be multiple account types (with different data sets) for the same type of account, each
// type string may have multiple AccountType entries.
- Map<String, List<AccountType>> accountTypesByType = Maps.newHashMap();
+ final Map<String, List<AccountType>> accountTypesByType = Maps.newHashMap();
- List<AccountWithDataSet> allAccounts = Lists.newArrayList();
- List<AccountWithDataSet> writableAccounts = Lists.newArrayList();
- Set<String> extensionPackages = Sets.newHashSet();
+ final List<AccountWithDataSet> allAccounts = Lists.newArrayList();
+ final List<AccountWithDataSet> contactWritableAccounts = Lists.newArrayList();
+ final List<AccountWithDataSet> groupWritableAccounts = Lists.newArrayList();
+ final Set<String> extensionPackages = Sets.newHashSet();
final AccountManager am = mAccountManager;
final IContentService cs = ContentResolver.getContentService();
@@ -402,7 +415,10 @@
account.name, account.type, accountType.dataSet);
allAccounts.add(accountWithDataSet);
if (accountType.areContactsWritable()) {
- writableAccounts.add(accountWithDataSet);
+ contactWritableAccounts.add(accountWithDataSet);
+ }
+ if (accountType.isGroupMembershipEditable()) {
+ groupWritableAccounts.add(accountWithDataSet);
}
}
}
@@ -410,14 +426,16 @@
}
Collections.sort(allAccounts, ACCOUNT_COMPARATOR);
- Collections.sort(writableAccounts, ACCOUNT_COMPARATOR);
+ Collections.sort(contactWritableAccounts, ACCOUNT_COMPARATOR);
+ Collections.sort(groupWritableAccounts, ACCOUNT_COMPARATOR);
timings.addSplit("Loaded accounts");
synchronized (this) {
mAccountTypesWithDataSets = accountTypesByTypeAndDataSet;
mAccounts = allAccounts;
- mWritableAccounts = writableAccounts;
+ mContactWritableAccounts = contactWritableAccounts;
+ mGroupWritableAccounts = groupWritableAccounts;
mInvitableAccountTypes = findInvitableAccountTypes(
mContext, allAccounts, accountTypesByTypeAndDataSet);
}
@@ -467,12 +485,20 @@
}
/**
- * Return list of all known, writable {@link AccountWithDataSet}'s.
+ * Return list of all known, contact writable {@link AccountWithDataSet}'s.
*/
@Override
- public List<AccountWithDataSet> getAccounts(boolean writableOnly) {
+ public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly) {
ensureAccountsLoaded();
- return writableOnly ? mWritableAccounts : mAccounts;
+ return contactWritableOnly ? mContactWritableAccounts : mAccounts;
+ }
+
+ /**
+ * Return the list of all known, group writable {@link AccountWithDataSet}'s.
+ */
+ public List<AccountWithDataSet> getGroupWritableAccounts() {
+ ensureAccountsLoaded();
+ return mGroupWritableAccounts;
}
/**
diff --git a/src/com/android/contacts/util/AccountsListAdapter.java b/src/com/android/contacts/util/AccountsListAdapter.java
index fc48e72..058cf84 100644
--- a/src/com/android/contacts/util/AccountsListAdapter.java
+++ b/src/com/android/contacts/util/AccountsListAdapter.java
@@ -42,20 +42,28 @@
private final AccountTypeManager mAccountTypes;
private final Context mContext;
- public AccountsListAdapter(Context context, boolean writableOnly) {
- this(context, writableOnly, null);
+ /**
+ * Filters that affect the list of accounts that is displayed by this adapter.
+ */
+ public enum AccountListFilter {
+ ALL_ACCOUNTS, // All read-only and writable accounts
+ ACCOUNTS_CONTACT_WRITABLE, // Only where the account type is contact writable
+ ACCOUNTS_GROUP_WRITABLE // Only accounts where the account type is group writable
+ }
+
+ public AccountsListAdapter(Context context, AccountListFilter accountListFilter) {
+ this(context, accountListFilter, null);
}
/**
* @param currentAccount the Account currently selected by the user, which should come
* first in the list. Can be null.
*/
- public AccountsListAdapter(Context context, boolean writableOnly,
+ public AccountsListAdapter(Context context, AccountListFilter accountListFilter,
AccountWithDataSet currentAccount) {
mContext = context;
mAccountTypes = AccountTypeManager.getInstance(context);
- // We don't want possible side-effect toward AccountTypeManager
- mAccounts = new ArrayList<AccountWithDataSet>(mAccountTypes.getAccounts(writableOnly));
+ mAccounts = getAccounts(accountListFilter);
if (currentAccount != null
&& !mAccounts.isEmpty()
&& !mAccounts.get(0).equals(currentAccount)
@@ -65,6 +73,14 @@
mInflater = LayoutInflater.from(context);
}
+ private List<AccountWithDataSet> getAccounts(AccountListFilter accountListFilter) {
+ if (accountListFilter == AccountListFilter.ACCOUNTS_GROUP_WRITABLE) {
+ return new ArrayList<AccountWithDataSet>(mAccountTypes.getGroupWritableAccounts());
+ }
+ return new ArrayList<AccountWithDataSet>(mAccountTypes.getAccounts(
+ accountListFilter == AccountListFilter.ACCOUNTS_CONTACT_WRITABLE));
+ }
+
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View resultView = convertView != null ? convertView
diff --git a/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java b/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java
index 3b712c7..5ca1ccd 100644
--- a/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java
+++ b/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java
@@ -59,6 +59,11 @@
}
@Override
+ public List<AccountWithDataSet> getGroupWritableAccounts() {
+ return Arrays.asList(mAccounts);
+ }
+
+ @Override
public Map<AccountTypeWithDataSet, AccountType> getInvitableAccountTypes() {
return Maps.newHashMap(); // Always returns empty
}