Add setter for accounts in AccountsListAdapter
This allows the accounts to be set after the adapter has been created
which simplifies usage in cases where the accounts are loaded with a
loader.
Test: manually verify that account list is correct for default account
preference, import from .vcf and create label.
Bug 33627801
Change-Id: I5a33ad2746cff41d0251cead9a33dc53e5bf822d
diff --git a/src/com/android/contacts/ContactsDrawerActivity.java b/src/com/android/contacts/ContactsDrawerActivity.java
index f0bc37e..fc7639a 100644
--- a/src/com/android/contacts/ContactsDrawerActivity.java
+++ b/src/com/android/contacts/ContactsDrawerActivity.java
@@ -70,7 +70,6 @@
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;
@@ -693,7 +692,7 @@
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/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/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..b3f05c5 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -83,6 +83,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.
@@ -298,43 +319,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;
}
}
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/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) {