summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/com/android/contacts/SimImportFragment.java35
-rw-r--r--src/com/android/contacts/activities/PeopleActivity.java4
-rw-r--r--src/com/android/contacts/editor/AccountHeaderPresenter.java33
-rw-r--r--src/com/android/contacts/list/CustomContactListFilterActivity.java110
-rw-r--r--src/com/android/contacts/model/AccountTypeManager.java224
-rw-r--r--src/com/android/contacts/model/account/AccountInfo.java152
-rw-r--r--src/com/android/contacts/model/account/AccountType.java17
-rw-r--r--src/com/android/contacts/model/account/DeviceLocalAccountType.java9
-rw-r--r--src/com/android/contacts/model/account/SimAccountType.java9
-rw-r--r--src/com/android/contacts/util/AccountFilterUtil.java45
-rw-r--r--src/com/android/contacts/util/AccountsListAdapter.java56
-rw-r--r--src/com/android/contacts/util/concurrent/ListenableFutureLoader.java23
-rw-r--r--tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java14
13 files changed, 445 insertions, 286 deletions
diff --git a/src/com/android/contacts/SimImportFragment.java b/src/com/android/contacts/SimImportFragment.java
index 8d8e2dbe1..a8db4eea0 100644
--- a/src/com/android/contacts/SimImportFragment.java
+++ b/src/com/android/contacts/SimImportFragment.java
@@ -47,6 +47,7 @@ import com.android.contacts.editor.AccountHeaderPresenter;
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.AccountWithDataSet;
import com.android.contacts.preference.ContactsPreferences;
import com.android.contacts.util.concurrent.ContactsExecutors;
@@ -258,15 +259,15 @@ public class SimImportFragment extends Fragment
public void onLoaderReset(Loader<LoaderResult> loader) {
}
- private void restoreAdapterSelectedStates(List<AccountWithDataSet> accounts) {
+ private void restoreAdapterSelectedStates(List<AccountInfo> accounts) {
if (mSavedInstanceState == null) {
return;
}
- for (AccountWithDataSet account : accounts) {
+ for (AccountInfo account : accounts) {
final long[] selections = mSavedInstanceState.getLongArray(
- account.stringify() + KEY_SUFFIX_SELECTED_IDS);
- mPerAccountCheckedIds.put(account, selections);
+ account.getAccount().stringify() + KEY_SUFFIX_SELECTED_IDS);
+ mPerAccountCheckedIds.put(account.getAccount(), selections);
}
mSavedInstanceState = null;
}
@@ -446,10 +447,8 @@ public class SimImportFragment extends Fragment
private AccountTypeManager mAccountTypeManager;
private final int mSubscriptionId;
- private BroadcastReceiver mReceiver;
-
public SimContactLoader(Context context, int subscriptionId) {
- super(context);
+ super(context, new IntentFilter(AccountTypeManager.BROADCAST_ACCOUNTS_CHANGED));
mDao = SimContactDao.create(context);
mAccountTypeManager = AccountTypeManager.getInstance(getContext());
mSubscriptionId = subscriptionId;
@@ -459,7 +458,7 @@ public class SimImportFragment extends Fragment
protected ListenableFuture<LoaderResult> loadData() {
final ListenableFuture<List<Object>> future = Futures.<Object>allAsList(
mAccountTypeManager
- .filterAccountsByTypeAsync(AccountTypeManager.writableFilter()),
+ .filterAccountsAsync(AccountTypeManager.writableFilter()),
ContactsExecutors.getSimReadExecutor().<Object>submit(
new Callable<Object>() {
@Override
@@ -470,7 +469,7 @@ public class SimImportFragment extends Fragment
return Futures.transform(future, new Function<List<Object>, LoaderResult>() {
@Override
public LoaderResult apply(List<Object> input) {
- final List<AccountWithDataSet> accounts = (List<AccountWithDataSet>) input.get(0);
+ final List<AccountInfo> accounts = (List<AccountInfo>) input.get(0);
final LoaderResult simLoadResult = (LoaderResult) input.get(1);
simLoadResult.accounts = accounts;
return simLoadResult;
@@ -490,26 +489,10 @@ public class SimImportFragment extends Fragment
result.accountsMap = mDao.findAccountsOfExistingSimContacts(result.contacts);
return result;
}
-
- @Override
- protected void onStartLoading() {
- super.onStartLoading();
- if (mReceiver == null) {
- mReceiver = new ForceLoadReceiver();
- LocalBroadcastManager.getInstance(getContext()).registerReceiver(mReceiver,
- new IntentFilter(AccountTypeManager.BROADCAST_ACCOUNTS_CHANGED));
- }
- }
-
- @Override
- protected void onReset() {
- super.onReset();
- LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mReceiver);
- }
}
public static class LoaderResult {
- public List<AccountWithDataSet> accounts;
+ public List<AccountInfo> accounts;
public ArrayList<SimContact> contacts;
public Map<AccountWithDataSet, Set<SimContact>> accountsMap;
}
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 426dcd70d..28891e556 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -68,6 +68,7 @@ import com.android.contacts.list.ProviderStatusWatcher.ProviderStatusListener;
import com.android.contacts.logging.Logger;
import com.android.contacts.logging.ScreenEvent.ScreenType;
import com.android.contacts.model.AccountTypeManager;
+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.AccountFilterUtil;
@@ -172,7 +173,8 @@ public class PeopleActivity extends ContactsDrawerActivity {
accounts = Collections.singletonList(new AccountWithDataSet(filter.accountName,
filter.accountType, null));
} else if (filter.shouldShowSyncState()) {
- accounts = mAccountTypeManager.getWritableGoogleAccounts();
+ accounts = AccountInfo.extractAccounts(
+ mAccountTypeManager.getWritableGoogleAccounts());
} else {
accounts = Collections.emptyList();
}
diff --git a/src/com/android/contacts/editor/AccountHeaderPresenter.java b/src/com/android/contacts/editor/AccountHeaderPresenter.java
index 01854190e..e7e8e5021 100644
--- a/src/com/android/contacts/editor/AccountHeaderPresenter.java
+++ b/src/com/android/contacts/editor/AccountHeaderPresenter.java
@@ -26,9 +26,7 @@ import android.widget.ListPopupWindow;
import android.widget.TextView;
import com.android.contacts.R;
-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.util.AccountsListAdapter;
import com.android.contacts.util.UiClosables;
@@ -56,9 +54,8 @@ public class AccountHeaderPresenter {
}
private final Context mContext;
- private AccountDisplayInfoFactory mAccountDisplayInfoFactory;
- private List<AccountWithDataSet> mAccounts;
+ private List<AccountInfo> mAccounts;
private AccountWithDataSet mCurrentAccount;
// Account header
@@ -100,19 +97,18 @@ public class AccountHeaderPresenter {
updateDisplayedAccount();
}
- public void setAccounts(List<AccountWithDataSet> accounts) {
+ public void setAccounts(List<AccountInfo> accounts) {
mAccounts = accounts;
- mAccountDisplayInfoFactory = new AccountDisplayInfoFactory(mContext, accounts);
// If the current account was removed just switch to the next one in the list.
- if (mCurrentAccount != null && !mAccounts.contains(mCurrentAccount)) {
- mCurrentAccount = mAccounts.isEmpty() ? null : accounts.get(0);
+ if (mCurrentAccount != null && !AccountInfo.contains(mAccounts, mCurrentAccount)) {
+ mCurrentAccount = mAccounts.isEmpty() ? null : accounts.get(0).getAccount();
mObserver.onChange(this);
}
updateDisplayedAccount();
}
public AccountWithDataSet getCurrentAccount() {
- return mCurrentAccount;
+ return mCurrentAccount != null ? mCurrentAccount : null;
}
public void onSaveInstanceState(Bundle outState) {
@@ -132,10 +128,7 @@ public class AccountHeaderPresenter {
if (mCurrentAccount == null) return;
if (mAccounts == null) return;
- final AccountDisplayInfo account =
- mAccountDisplayInfoFactory.getAccountDisplayInfo(mCurrentAccount);
-
- final String accountLabel = getAccountLabel(account);
+ final String accountLabel = getAccountLabel(mCurrentAccount);
if (mAccounts.size() > 1) {
addAccountSelector(accountLabel);
@@ -157,10 +150,10 @@ public class AccountHeaderPresenter {
mAccountHeaderType.setText(selectorTitle);
}
+ final AccountInfo accountInfo = AccountInfo.getAccount(mAccounts, mCurrentAccount);
+
// Set the icon
- final AccountDisplayInfo displayInfo = mAccountDisplayInfoFactory
- .getAccountDisplayInfo(mCurrentAccount);
- mAccountHeaderIcon.setImageDrawable(displayInfo.getIcon());
+ mAccountHeaderIcon.setImageDrawable(accountInfo.getIcon());
// Set the content description
mAccountHeaderContainer.setContentDescription(
@@ -217,8 +210,8 @@ public class AccountHeaderPresenter {
mAccountHeaderContainer.setOnClickListener(listener);
}
- private String getAccountLabel(AccountDisplayInfo account) {
- // TODO: if used from editor this would need to be different if editing the user's profile.
- return account.getNameLabel().toString();
+ private String getAccountLabel(AccountWithDataSet account) {
+ final AccountInfo accountInfo = AccountInfo.getAccount(mAccounts, account);
+ return accountInfo != null ? accountInfo.getNameLabel().toString() : null;
}
}
diff --git a/src/com/android/contacts/list/CustomContactListFilterActivity.java b/src/com/android/contacts/list/CustomContactListFilterActivity.java
index 3ca8e36b1..bbde17bbf 100644
--- a/src/com/android/contacts/list/CustomContactListFilterActivity.java
+++ b/src/com/android/contacts/list/CustomContactListFilterActivity.java
@@ -23,13 +23,13 @@ import android.app.Dialog;
import android.app.DialogFragment;
import android.app.LoaderManager.LoaderCallbacks;
import android.app.ProgressDialog;
-import android.content.AsyncTaskLoader;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.Loader;
import android.content.OperationApplicationException;
import android.database.Cursor;
@@ -59,16 +59,18 @@ import android.widget.TextView;
import com.android.contacts.R;
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.model.ValuesDelta;
-import com.android.contacts.model.account.AccountDisplayInfo;
-import com.android.contacts.model.account.AccountDisplayInfoFactory;
-import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountInfo;
import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.model.account.GoogleAccountType;
import com.android.contacts.util.EmptyService;
import com.android.contacts.util.LocalizedNameResolver;
import com.android.contacts.util.WeakAsyncTask;
-
+import com.android.contacts.util.concurrent.ContactsExecutors;
+import com.android.contacts.util.concurrent.ListenableFutureLoader;
+import com.google.common.base.Function;
import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
import java.util.Collections;
@@ -76,6 +78,8 @@ import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
+import javax.annotation.Nullable;
+
/**
* Shows a list of all available {@link Groups} available, letting the user
* select which ones they want to be visible.
@@ -128,38 +132,38 @@ public class CustomContactListFilterActivity extends Activity implements
}
}
- public static class CustomFilterConfigurationLoader extends AsyncTaskLoader<AccountSet> {
+ public static class CustomFilterConfigurationLoader extends ListenableFutureLoader<AccountSet> {
- private AccountSet mAccountSet;
+ private AccountTypeManager mAccountTypeManager;
public CustomFilterConfigurationLoader(Context context) {
- super(context);
+ super(context, new IntentFilter(AccountTypeManager.BROADCAST_ACCOUNTS_CHANGED));
+ mAccountTypeManager = AccountTypeManager.getInstance(context);
}
@Override
- public AccountSet loadInBackground() {
- Context context = getContext();
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(context);
+ public ListenableFuture<AccountSet> loadData() {
+ return Futures.transform(mAccountTypeManager.getAccountsAsync(),
+ new Function<List<AccountInfo>, AccountSet>() {
+ @Nullable
+ @Override
+ public AccountSet apply(@Nullable List<AccountInfo> input) {
+ return createAccountSet(input);
+ }
+ }, ContactsExecutors.getDefaultThreadPoolExecutor());
+ }
+
+ private AccountSet createAccountSet(List<AccountInfo> sourceAccounts) {
+ final Context context = getContext();
final ContentResolver resolver = context.getContentResolver();
final AccountSet accounts = new AccountSet();
// Don't include the null account because it doesn't support writing to
// ContactsContract.Settings
- final List<AccountWithDataSet> sourceAccounts = accountTypes.getAccounts(
- AccountTypeManager.nonNullAccountFilter());
- final AccountDisplayInfoFactory displayableAccountFactory =
- new AccountDisplayInfoFactory(context, sourceAccounts);
- for (AccountWithDataSet account : sourceAccounts) {
- final AccountType accountType = accountTypes.getAccountTypeForAccount(account);
- if (accountType.isExtension() && !account.hasData(context)) {
- // Extension with no data -- skip.
- continue;
- }
-
- AccountDisplay accountDisplay =
- new AccountDisplay(resolver, account.name, account.type, account.dataSet,
- displayableAccountFactory.getAccountDisplayInfo(account));
+ for (AccountInfo info : sourceAccounts) {
+ final AccountWithDataSet account = info.getAccount();
+ final AccountDisplay accountDisplay = new AccountDisplay(resolver, info);
final Uri.Builder groupsUri = Groups.CONTENT_URI.buildUpon()
.appendQueryParameter(Groups.ACCOUNT_NAME, account.name)
@@ -197,41 +201,6 @@ public class CustomContactListFilterActivity extends Activity implements
return accounts;
}
-
- @Override
- public void deliverResult(AccountSet cursor) {
- if (isReset()) {
- return;
- }
-
- mAccountSet = cursor;
-
- if (isStarted()) {
- super.deliverResult(cursor);
- }
- }
-
- @Override
- protected void onStartLoading() {
- if (mAccountSet != null) {
- deliverResult(mAccountSet);
- }
- if (takeContentChanged() || mAccountSet == null) {
- forceLoad();
- }
- }
-
- @Override
- protected void onStopLoading() {
- cancelLoad();
- }
-
- @Override
- protected void onReset() {
- super.onReset();
- onStopLoading();
- mAccountSet = null;
- }
}
@Override
@@ -479,7 +448,7 @@ public class CustomContactListFilterActivity extends Activity implements
public final String mName;
public final String mType;
public final String mDataSet;
- public final AccountDisplayInfo mAccountDisplayInfo;
+ public final AccountInfo mAccountInfo;
public GroupDelta mUngrouped;
public ArrayList<GroupDelta> mSyncedGroups = Lists.newArrayList();
@@ -497,12 +466,11 @@ public class CustomContactListFilterActivity extends Activity implements
* Build an {@link AccountDisplay} covering all {@link Groups} under the
* given {@link AccountWithDataSet}.
*/
- public AccountDisplay(ContentResolver resolver, String accountName, String accountType,
- String dataSet, AccountDisplayInfo displayableInfo) {
- mName = accountName;
- mType = accountType;
- mDataSet = dataSet;
- mAccountDisplayInfo = displayableInfo;
+ public AccountDisplay(ContentResolver resolver, AccountInfo accountInfo) {
+ mName = accountInfo.getAccount().name;
+ mType = accountInfo.getAccount().type;
+ mDataSet = accountInfo.getAccount().dataSet;
+ mAccountInfo = accountInfo;
}
/**
@@ -616,11 +584,11 @@ public class CustomContactListFilterActivity extends Activity implements
final AccountDisplay account = (AccountDisplay)this.getGroup(groupPosition);
- text1.setText(account.mAccountDisplayInfo.getNameLabel());
- text1.setVisibility(!account.mAccountDisplayInfo.isDeviceAccount()
- || account.mAccountDisplayInfo.hasDistinctName()
+ text1.setText(account.mAccountInfo.getNameLabel());
+ text1.setVisibility(!account.mAccountInfo.isDeviceAccount()
+ || account.mAccountInfo.hasDistinctName()
? View.VISIBLE : View.GONE);
- text2.setText(account.mAccountDisplayInfo.getTypeLabel());
+ text2.setText(account.mAccountInfo.getTypeLabel());
final int textColor = mContext.getResources().getColor(isExpanded
? R.color.dialtacts_theme_color
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index d87b444bc..93ddd04ac 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -40,7 +40,7 @@ import android.util.Log;
import com.android.contacts.Experiments;
import com.android.contacts.R;
import com.android.contacts.list.ContactListFilterController;
-import com.android.contacts.model.account.AccountComparator;
+import com.android.contacts.model.account.AccountInfo;
import com.android.contacts.model.account.AccountType;
import com.android.contacts.model.account.AccountTypeProvider;
import com.android.contacts.model.account.AccountTypeWithDataSet;
@@ -50,10 +50,12 @@ import com.android.contacts.model.account.GoogleAccountType;
import com.android.contacts.model.dataitem.DataKind;
import com.android.contacts.util.concurrent.ContactsExecutors;
import com.android.contactsbind.experiments.Flags;
+import com.google.common.base.Preconditions;
import com.google.common.base.Function;
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;
@@ -120,19 +122,19 @@ public abstract class AccountTypeManager {
}
@Override
- public List<AccountWithDataSet> getAccounts(Predicate<AccountWithDataSet> filter) {
- return Collections.emptyList();
+ public ListenableFuture<List<AccountInfo>> getAccountsAsync() {
+ return Futures.immediateFuture(Collections.<AccountInfo>emptyList());
}
@Override
- public ListenableFuture<List<AccountWithDataSet>> getAllAccountsAsync() {
- return Futures.immediateFuture(Collections.<AccountWithDataSet>emptyList());
+ public ListenableFuture<List<AccountInfo>> filterAccountsAsync(
+ Predicate<AccountInfo> filter) {
+ return Futures.immediateFuture(Collections.<AccountInfo>emptyList());
}
@Override
- public ListenableFuture<List<AccountWithDataSet>> filterAccountsByTypeAsync(
- Predicate<AccountType> type) {
- return Futures.immediateFuture(Collections.<AccountWithDataSet>emptyList());
+ public AccountInfo getAccountInfoForAccount(AccountWithDataSet account) {
+ return null;
}
@Override
@@ -158,15 +160,18 @@ public abstract class AccountTypeManager {
// TODO: Consider splitting this into getContactWritableAccounts() and getAllAccounts()
public abstract List<AccountWithDataSet> getAccounts(boolean contactWritableOnly);
- public abstract List<AccountWithDataSet> getAccounts(Predicate<AccountWithDataSet> filter);
-
/**
* Loads accounts in background and returns future that will complete with list of all accounts
*/
- public abstract ListenableFuture<List<AccountWithDataSet>> getAllAccountsAsync();
+ public abstract ListenableFuture<List<AccountInfo>> getAccountsAsync();
+
+ /**
+ * Loads accounts and applies the fitler returning only for which the predicate is true
+ */
+ public abstract ListenableFuture<List<AccountInfo>> filterAccountsAsync(
+ Predicate<AccountInfo> filter);
- public abstract ListenableFuture<List<AccountWithDataSet>> filterAccountsByTypeAsync(
- Predicate<AccountType> type);
+ public abstract AccountInfo getAccountInfoForAccount(AccountWithDataSet account);
/**
* Returns the list of accounts that are group writable.
@@ -185,14 +190,13 @@ public abstract class AccountTypeManager {
* to call synchronously.
* </p>
*/
- public List<AccountWithDataSet> getWritableGoogleAccounts() {
+ public List<AccountInfo> getWritableGoogleAccounts() {
// This implementation may block and should be overridden by the Impl class
- return Futures.getUnchecked(filterAccountsByTypeAsync(new Predicate<AccountType>() {
+ return Futures.getUnchecked(filterAccountsAsync(new Predicate<AccountInfo>() {
@Override
- public boolean apply(@Nullable AccountType input) {
- return input.areContactsWritable() &&
- GoogleAccountType.ACCOUNT_TYPE.equals(input.accountType);
-
+ public boolean apply(@Nullable AccountInfo input) {
+ return input.getType().areContactsWritable() &&
+ GoogleAccountType.ACCOUNT_TYPE.equals(input.getType().accountType);
}
}));
}
@@ -278,15 +282,6 @@ public abstract class AccountTypeManager {
return getDefaultGoogleAccount() != null;
}
- /**
- * Sorts the accounts in-place such that defaultAccount is first in the list and the rest
- * of the accounts are ordered in manner that is useful for display purposes
- */
- public static void sortAccounts(AccountWithDataSet defaultAccount,
- List<AccountWithDataSet> accounts) {
- Collections.sort(accounts, new AccountComparator(defaultAccount));
- }
-
private static boolean hasRequiredPermissions(Context context) {
final boolean canGetAccounts = ContextCompat.checkSelfPermission(context,
android.Manifest.permission.GET_ACCOUNTS) == PackageManager.PERMISSION_GRANTED;
@@ -295,39 +290,41 @@ public abstract class AccountTypeManager {
return canGetAccounts && canReadContacts;
}
- public static Predicate<AccountWithDataSet> nonNullAccountFilter() {
- return new Predicate<AccountWithDataSet>() {
+ public static Predicate<AccountInfo> nonNullAccountFilter() {
+ return new Predicate<AccountInfo>() {
@Override
- public boolean apply(@Nullable AccountWithDataSet account) {
- return account != null && account.name != null && account.type != null;
+ public boolean apply(AccountInfo info) {
+ AccountWithDataSet account = info != null ? info.getAccount() : null;
+ return account != null && !account.isNullAccount();
}
};
+
}
- public static Predicate<AccountWithDataSet> adaptTypeFilter(
- final Predicate<AccountType> typeFilter, final AccountTypeProvider provider) {
- return new Predicate<AccountWithDataSet>() {
+ public static Predicate<AccountInfo> writableFilter() {
+ return new Predicate<AccountInfo>() {
@Override
- public boolean apply(@Nullable AccountWithDataSet input) {
- return typeFilter.apply(provider.getTypeForAccount(input));
+ public boolean apply(AccountInfo account) {
+ return account.getType().areContactsWritable();
}
};
}
- public static Predicate<AccountType> writableFilter() {
- return new Predicate<AccountType>() {
+ public static Predicate<AccountInfo> groupWritableFilter() {
+ return new Predicate<AccountInfo>() {
@Override
- public boolean apply(@Nullable AccountType account) {
- return account.areContactsWritable();
+ public boolean apply(@Nullable AccountInfo account) {
+ return account.getType().isGroupMembershipEditable();
}
};
}
- public static Predicate<AccountType> groupWritableFilter() {
- return new Predicate<AccountType>() {
+ public static Predicate<AccountInfo> onlyNonEmptyExtensionFilter(Context context) {
+ final Context appContext = context.getApplicationContext();
+ return new Predicate<AccountInfo>() {
@Override
- public boolean apply(@Nullable AccountType account) {
- return account.isGroupMembershipEditable();
+ public boolean apply(@Nullable AccountInfo input) {
+ return !input.getType().isExtension() || input.getAccount().hasData(appContext);
}
};
}
@@ -490,88 +487,111 @@ class AccountTypeManagerImpl extends AccountTypeManager
*/
@Override
public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly) {
- final Predicate<AccountType> filter = contactWritableOnly ?
- writableFilter() : Predicates.<AccountType>alwaysTrue();
+ final Predicate<AccountInfo> filter = contactWritableOnly ?
+ writableFilter() : Predicates.<AccountInfo>alwaysTrue();
// TODO: Shouldn't have a synchronous version for getting all accounts
- return Futures.getUnchecked(filterAccountsByTypeAsync(filter));
+ return Lists.transform(Futures.getUnchecked(filterAccountsAsync(filter)),
+ AccountInfo.ACCOUNT_EXTRACTOR);
}
@Override
- public List<AccountWithDataSet> getAccounts(Predicate<AccountWithDataSet> filter) {
- // TODO: Shouldn't have a synchronous version for getting all accounts
- return Futures.getUnchecked(filterAccountsAsync(filter));
+ public ListenableFuture<List<AccountInfo>> getAccountsAsync() {
+ return getAllAccountsAsyncInternal();
}
- @Override
- public ListenableFuture<List<AccountWithDataSet>> getAllAccountsAsync() {
+ private ListenableFuture<List<AccountInfo>> getAllAccountsAsyncInternal() {
startLoadingIfNeeded();
- return filterAccountsAsync(Predicates.<AccountWithDataSet>alwaysTrue());
- }
-
- @Override
- public ListenableFuture<List<AccountWithDataSet>> filterAccountsByTypeAsync(
- final Predicate<AccountType> typeFilter) {
- // Ensure that mTypeProvider is initialized so that the reference will be the same
- // here as in the call to filterAccountsAsync
- startLoadingIfNeeded();
- return filterAccountsAsync(adaptTypeFilter(typeFilter, mTypeProvider));
- }
-
- private ListenableFuture<List<AccountWithDataSet>> filterAccountsAsync(
- final Predicate<AccountWithDataSet> filter) {
- startLoadingIfNeeded();
- final ListenableFuture<List<AccountWithDataSet>> accountsFromTypes =
+ final AccountTypeProvider typeProvider = mTypeProvider;
+ final ListenableFuture<List<AccountInfo>> accountsFromTypes =
Futures.transform(Futures.nonCancellationPropagating(mAccountTypesFuture),
- new Function<AccountTypeProvider, List<AccountWithDataSet>>() {
+ new Function<AccountTypeProvider, List<AccountInfo>>() {
@Override
- public List<AccountWithDataSet> apply(AccountTypeProvider provider) {
+ public List<AccountInfo> apply(AccountTypeProvider provider) {
return getAccountsFromProvider(provider);
}
});
- final ListenableFuture<List<List<AccountWithDataSet>>> all =
- Futures.successfulAsList(accountsFromTypes, mLocalAccountsFuture);
+ final ListenableFuture<List<AccountInfo>> localAccountsInfo =
+ Futures.transform(mLocalAccountsFuture, new Function<List<AccountWithDataSet>,
+ List<AccountInfo>>() {
+ @Nullable
+ @Override
+ public List<AccountInfo> apply(@Nullable List<AccountWithDataSet> input) {
+ final List<AccountInfo> result = new ArrayList<>();
+ for (AccountWithDataSet account : input) {
+ final AccountType type = typeProvider.getTypeForAccount(account);
+ result.add(type.wrapAccount(mContext, account));
+ }
+ return result;
+ }
+ });
+
+ final ListenableFuture<List<List<AccountInfo>>> all =
+ Futures.successfulAsList(accountsFromTypes, localAccountsInfo);
- return Futures.transform(all, new Function<List<List<AccountWithDataSet>>,
- List<AccountWithDataSet>>() {
- @Nullable
+ return Futures.transform(all, new Function<List<List<AccountInfo>>,
+ List<AccountInfo>>() {
@Override
- public List<AccountWithDataSet> apply(@Nullable List<List<AccountWithDataSet>> input) {
- // The first result list is from the account types. Check if there is a Google
- // account in this list and if there is exclude the null account
- final Predicate<AccountWithDataSet> appliedFilter =
- hasWritableGoogleAccount(input.get(0)) ?
- Predicates.and(nonNullAccountFilter(), filter) :
- filter;
- List<AccountWithDataSet> result = new ArrayList<>();
- for (List<AccountWithDataSet> list : input) {
- if (list != null) {
- result.addAll(Collections2.filter(list, appliedFilter));
- }
+ public List<AccountInfo> apply(List<List<AccountInfo>> input) {
+ // input.get(0) contains accounts from AccountManager
+ // input.get(1) contains device local accounts
+ Preconditions.checkArgument(input.size() == 2,
+ "List should have exactly 2 elements");
+
+ final List<AccountInfo> result = new ArrayList<>(input.get(0));
+ // Check if there is a Google account in this list and if there is exclude the null
+ // account
+ if (hasWritableGoogleAccount(input.get(0))) {
+ result.addAll(Collections2.filter(input.get(1), nonNullAccountFilter()));
+ } else {
+ result.addAll(input.get(1));
}
+ AccountInfo.sortAccounts(null, result);
return result;
}
});
}
- private List<AccountWithDataSet> getAccountsFromProvider(AccountTypeProvider cache) {
- final List<AccountWithDataSet> result = new ArrayList<>();
+ @Override
+ public ListenableFuture<List<AccountInfo>> filterAccountsAsync(
+ final Predicate<AccountInfo> filter) {
+ return Futures.transform(getAllAccountsAsyncInternal(), new Function<List<AccountInfo>,
+ List<AccountInfo>>() {
+ @Override
+ public List<AccountInfo> apply(List<AccountInfo> input) {
+ return new ArrayList<>(Collections2.filter(input, filter));
+ }
+ }, mExecutor);
+ }
+
+ @Override
+ public AccountInfo getAccountInfoForAccount(AccountWithDataSet account) {
+ final AccountType type = mTypeProvider.getTypeForAccount(account);
+ if (type == null) {
+ return null;
+ }
+ return type.wrapAccount(mContext, account);
+ }
+
+ private List<AccountInfo> getAccountsFromProvider(AccountTypeProvider typeProvider) {
+ final List<AccountInfo> result = new ArrayList<>();
final Account[] accounts = mAccountManager.getAccounts();
for (Account account : accounts) {
- final List<AccountType> types = cache.getAccountTypes(account.type);
+ final List<AccountType> types = typeProvider.getAccountTypes(account.type);
for (AccountType type : types) {
- result.add(new AccountWithDataSet(account.name, account.type, type.dataSet));
+ result.add(type.wrapAccount(mContext,
+ new AccountWithDataSet(account.name, account.type, type.dataSet)));
}
}
return result;
}
- private boolean hasWritableGoogleAccount(List<AccountWithDataSet> accounts) {
+ private boolean hasWritableGoogleAccount(List<AccountInfo> accounts) {
if (accounts == null) {
return false;
}
- AccountType type;
- for (AccountWithDataSet account : accounts) {
+ for (AccountInfo info : accounts) {
+ AccountWithDataSet account = info.getAccount();
if (GoogleAccountType.ACCOUNT_TYPE.equals(account.type) && account.dataSet == null) {
return true;
}
@@ -579,12 +599,12 @@ class AccountTypeManagerImpl extends AccountTypeManager
return false;
}
-
/**
* Return the list of all known, group writable {@link AccountWithDataSet}'s.
*/
public List<AccountWithDataSet> getGroupWritableAccounts() {
- return Futures.getUnchecked(filterAccountsByTypeAsync(groupWritableFilter()));
+ return Lists.transform(Futures.getUnchecked(
+ filterAccountsAsync(groupWritableFilter())), AccountInfo.ACCOUNT_EXTRACTOR);
}
/**
@@ -601,13 +621,17 @@ class AccountTypeManagerImpl extends AccountTypeManager
}
@Override
- public List<AccountWithDataSet> getWritableGoogleAccounts() {
+ public List<AccountInfo> getWritableGoogleAccounts() {
final Account[] googleAccounts =
mAccountManager.getAccountsByType(GoogleAccountType.ACCOUNT_TYPE);
- final List<AccountWithDataSet> result = new ArrayList<>();
+ final List<AccountInfo> result = new ArrayList<>();
for (Account account : googleAccounts) {
+ final AccountWithDataSet accountWithDataSet = new AccountWithDataSet(
+ account.name, account.type, null);
+ final AccountType type = mTypeProvider.getTypeForAccount(accountWithDataSet);
+
// Accounts with a dataSet (e.g. Google plus accounts) are not writable.
- result.add(new AccountWithDataSet(account.name, account.type, null));
+ result.add(type.wrapAccount(mContext, accountWithDataSet));
}
return result;
}
diff --git a/src/com/android/contacts/model/account/AccountInfo.java b/src/com/android/contacts/model/account/AccountInfo.java
new file mode 100644
index 000000000..2161edb78
--- /dev/null
+++ b/src/com/android/contacts/model/account/AccountInfo.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts.model.account;
+
+import android.graphics.drawable.Drawable;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Holds an {@link AccountWithDataSet} and the corresponding {@link AccountType} for an account.
+ */
+public class AccountInfo {
+
+ private final AccountDisplayInfo mDisplayInfo;
+ private final AccountType mType;
+
+ public AccountInfo(AccountDisplayInfo displayInfo, AccountType type) {
+ this.mDisplayInfo = displayInfo;
+ this.mType = type;
+ }
+
+ public AccountType getType() {
+ return mType;
+ }
+
+ public AccountWithDataSet getAccount() {
+ return mDisplayInfo.getSource();
+ }
+
+ /**
+ * Returns the displayable account name label for the account
+ */
+ public CharSequence getNameLabel() {
+ return mDisplayInfo.getNameLabel();
+ }
+
+ /**
+ * Returns the displayable account type label for the account
+ */
+ public CharSequence getTypeLabel() {
+ return mDisplayInfo.getTypeLabel();
+ }
+
+ /**
+ * Returns the icon for the account type
+ */
+ public Drawable getIcon() {
+ return mDisplayInfo.getIcon();
+ }
+
+ public boolean hasDistinctName() {
+ return mDisplayInfo.hasDistinctName();
+ }
+
+ public boolean isDeviceAccount() {
+ return mDisplayInfo.isDeviceAccount();
+ }
+
+ public boolean sameAccount(AccountInfo other) {
+ return sameAccount(other.getAccount());
+ }
+
+ public boolean sameAccount(AccountWithDataSet other) {
+ return Objects.equals(getAccount(), other);
+ }
+
+ /**
+ * Returns whether accounts contains an account that is the same as account
+ *
+ * <p>This does not use equality rather checks whether the source account ({@link #getAccount()}
+ * is the same</p>
+ */
+ public static boolean contains(List<AccountInfo> accounts, AccountInfo account) {
+ return contains(accounts, account.getAccount());
+ }
+
+ /**
+ * Returns whether accounts contains an account that is the same as account
+ *
+ * <p>This does not use equality rather checks whether the source account ({@link #getAccount()}
+ * is the same</p>
+ */
+ public static boolean contains(List<AccountInfo> accounts, AccountWithDataSet account) {
+ return getAccount(accounts, account) != null;
+ }
+
+ /**
+ * Returns the AccountInfo from the list that has the specified account as it's source account
+ */
+ public static AccountInfo getAccount(List<AccountInfo> accounts, AccountWithDataSet account) {
+ Preconditions.checkNotNull(accounts);
+
+ for (AccountInfo info : accounts) {
+ if (info.sameAccount(account)) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Sorts the accounts using the same ordering as {@link AccountComparator}
+ */
+ public static void sortAccounts(AccountWithDataSet defaultAccount, List<AccountInfo> accounts) {
+ Collections.sort(accounts, sourceComparator(defaultAccount));
+ }
+
+ /**
+ * Gets a list of the AccountWithDataSet for accounts
+ */
+ public static List<AccountWithDataSet> extractAccounts(List<AccountInfo> accounts) {
+ return Lists.transform(accounts, ACCOUNT_EXTRACTOR);
+ }
+
+ private static Comparator<AccountInfo> sourceComparator(AccountWithDataSet defaultAccount) {
+ final AccountComparator accountComparator = new AccountComparator(defaultAccount);
+ return new Comparator<AccountInfo>() {
+ @Override
+ public int compare(AccountInfo o1, AccountInfo o2) {
+ return accountComparator.compare(o1.getAccount(), o2.getAccount());
+ }
+ };
+ }
+
+ public static final Function<AccountInfo, AccountWithDataSet> ACCOUNT_EXTRACTOR =
+ new Function<AccountInfo, AccountWithDataSet>() {
+ @Override
+ public AccountWithDataSet apply(AccountInfo from) {
+ return from.getAccount();
+ }
+ };
+}
diff --git a/src/com/android/contacts/model/account/AccountType.java b/src/com/android/contacts/model/account/AccountType.java
index f3462a134..bddfc0992 100644
--- a/src/com/android/contacts/model/account/AccountType.java
+++ b/src/com/android/contacts/model/account/AccountType.java
@@ -31,7 +31,9 @@ import android.widget.EditText;
import com.android.contacts.R;
import com.android.contacts.model.dataitem.DataKind;
+import com.google.common.base.Preconditions;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -183,6 +185,21 @@ public abstract class AccountType {
}
/**
+ * Creates an {@link AccountInfo} for the specified account with the same type
+ *
+ * <p>The {@link AccountWithDataSet#type} must match {@link #accountType} of this instance</p>
+ */
+ public AccountInfo wrapAccount(Context context, AccountWithDataSet account) {
+ Preconditions.checkArgument(Objects.equal(account.type, accountType),
+ "Account types must match: account.type=%s but accountType=%s",
+ account.type, accountType);
+
+ return new AccountInfo(
+ new AccountDisplayInfo(account, account.name,
+ getDisplayLabel(context), getDisplayIcon(context), false), this);
+ }
+
+ /**
* @return resource ID for the "invite contact" action label, or -1 if not defined.
*/
protected int getInviteContactActionResId() {
diff --git a/src/com/android/contacts/model/account/DeviceLocalAccountType.java b/src/com/android/contacts/model/account/DeviceLocalAccountType.java
index 3941cf776..c6c7d07fa 100644
--- a/src/com/android/contacts/model/account/DeviceLocalAccountType.java
+++ b/src/com/android/contacts/model/account/DeviceLocalAccountType.java
@@ -34,4 +34,13 @@ public class DeviceLocalAccountType extends FallbackAccountType {
public boolean isGroupMembershipEditable() {
return mGroupsEditable;
}
+
+ @Override
+ public AccountInfo wrapAccount(Context context, AccountWithDataSet account) {
+ // Use the "Device" type label for the name as well because on OEM phones the "name" is
+ // not always user-friendly
+ return new AccountInfo(
+ new AccountDisplayInfo(account, getDisplayLabel(context), getDisplayLabel(context),
+ getDisplayIcon(context), true), this);
+ }
}
diff --git a/src/com/android/contacts/model/account/SimAccountType.java b/src/com/android/contacts/model/account/SimAccountType.java
index 6e64c6434..5660d0144 100644
--- a/src/com/android/contacts/model/account/SimAccountType.java
+++ b/src/com/android/contacts/model/account/SimAccountType.java
@@ -112,4 +112,13 @@ public class SimAccountType extends BaseAccountType {
return kind;
}
+
+ @Override
+ public AccountInfo wrapAccount(Context context, AccountWithDataSet account) {
+ // Use the "SIM" type label for the name as well because on OEM phones the "name" is
+ // not always user-friendly
+ return new AccountInfo(
+ new AccountDisplayInfo(account, getDisplayLabel(context), getDisplayLabel(context),
+ getDisplayIcon(context), true), this);
+ }
}
diff --git a/src/com/android/contacts/util/AccountFilterUtil.java b/src/com/android/contacts/util/AccountFilterUtil.java
index 9eb8e7bcc..218604ceb 100644
--- a/src/com/android/contacts/util/AccountFilterUtil.java
+++ b/src/com/android/contacts/util/AccountFilterUtil.java
@@ -42,6 +42,7 @@ import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.model.Contact;
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.AccountType;
import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.preference.ContactsPreferences;
@@ -113,53 +114,33 @@ public class AccountFilterUtil {
public static class FilterLoader extends ListenableFutureLoader<List<ContactListFilter>> {
private AccountTypeManager mAccountTypeManager;
private DeviceLocalAccountTypeFactory mDeviceLocalFactory;
- private LocalBroadcastManager mLocalBroadcastManager;
- private BroadcastReceiver mReceiver;
public FilterLoader(Context context) {
- super(context);
+ super(context, new IntentFilter(AccountTypeManager.BROADCAST_ACCOUNTS_CHANGED));
mAccountTypeManager = AccountTypeManager.getInstance(context);
mDeviceLocalFactory = ObjectFactory.getDeviceLocalAccountTypeFactory(context);
- mLocalBroadcastManager = LocalBroadcastManager.getInstance(context);
}
- @Override
- protected void onStartLoading() {
- super.onStartLoading();
- if (mReceiver == null) {
- mReceiver = new ForceLoadReceiver();
- mLocalBroadcastManager.registerReceiver(mReceiver,
- new IntentFilter(AccountTypeManager.BROADCAST_ACCOUNTS_CHANGED));
- }
- }
-
- @Override
- protected void onReset() {
- super.onReset();
- if (mReceiver != null) {
- mLocalBroadcastManager.unregisterReceiver(mReceiver);
- }
- }
@Override
protected ListenableFuture<List<ContactListFilter>> loadData() {
- return Futures.transform(mAccountTypeManager.filterAccountsByTypeAsync(
+ return Futures.transform(mAccountTypeManager.filterAccountsAsync(
AccountTypeManager.writableFilter()),
- new Function<List<AccountWithDataSet>, List<ContactListFilter>>() {
+ new Function<List<AccountInfo>, List<ContactListFilter>>() {
@Override
- public List<ContactListFilter> apply(List<AccountWithDataSet> input) {
+ public List<ContactListFilter> apply(List<AccountInfo> input) {
return getFiltersForAccounts(input);
}
}, ContactsExecutors.getDefaultThreadPoolExecutor());
}
- private List<ContactListFilter> getFiltersForAccounts(List<AccountWithDataSet> accounts) {
- final ArrayList<ContactListFilter> accountFilters = Lists.newArrayList();
- AccountTypeManager.sortAccounts(getDefaultAccount(getContext()), accounts);
+ private List<ContactListFilter> getFiltersForAccounts(List<AccountInfo> accounts) {
+ final ArrayList<ContactListFilter> accountFilters = new ArrayList<>();
+ AccountInfo.sortAccounts(getDefaultAccount(getContext()), accounts);
- for (AccountWithDataSet account : accounts) {
- final AccountType accountType =
- mAccountTypeManager.getAccountType(account.type, account.dataSet);
+ for (AccountInfo accountInfo : accounts) {
+ final AccountType accountType = accountInfo.getType();
+ final AccountWithDataSet account = accountInfo.getAccount();
if ((accountType.isExtension() ||
DeviceLocalAccountTypeFactory.Util.isLocalAccountType(
mDeviceLocalFactory, account.type)) &&
@@ -178,9 +159,7 @@ public class AccountFilterUtil {
}
}
- final ArrayList<ContactListFilter> result = Lists.newArrayList();
- result.addAll(accountFilters);
- return result;
+ return accountFilters;
}
}
diff --git a/src/com/android/contacts/util/AccountsListAdapter.java b/src/com/android/contacts/util/AccountsListAdapter.java
index 94a7c29ac..005bb8d78 100644
--- a/src/com/android/contacts/util/AccountsListAdapter.java
+++ b/src/com/android/contacts/util/AccountsListAdapter.java
@@ -25,11 +25,8 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.android.contacts.R;
-import com.android.contacts.list.ContactListFilter;
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.AccountType;
+import com.android.contacts.model.account.AccountInfo;
import com.android.contacts.model.account.AccountWithDataSet;
import java.util.ArrayList;
@@ -40,32 +37,41 @@ import java.util.List;
*/
public final class AccountsListAdapter extends BaseAdapter {
private final LayoutInflater mInflater;
- private final List<AccountDisplayInfo> mAccountDisplayInfoList;
- private final List<AccountWithDataSet> mAccounts;
+ private final List<AccountInfo> mAccounts;
private final Context mContext;
private int mCustomLayout = -1;
public enum AccountListFilter {
ALL_ACCOUNTS {
@Override
- public List<AccountWithDataSet> getAccounts(Context context) {
+ public List<AccountWithDataSet> getSourceAccounts(Context context) {
return AccountTypeManager.getInstance(context).getAccounts(false);
}
},
ACCOUNTS_CONTACT_WRITABLE {
@Override
- public List<AccountWithDataSet> getAccounts(Context context) {
+ public List<AccountWithDataSet> getSourceAccounts(Context context) {
return AccountTypeManager.getInstance(context).getAccounts(true);
}
},
ACCOUNTS_GROUP_WRITABLE {
@Override
- public List<AccountWithDataSet> getAccounts(Context context) {
+ public List<AccountWithDataSet> getSourceAccounts(Context context) {
return AccountTypeManager.getInstance(context).getGroupWritableAccounts();
}
};
- public abstract List<AccountWithDataSet> getAccounts(Context context);
+ 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) {
@@ -77,7 +83,7 @@ public final class AccountsListAdapter extends BaseAdapter {
this(context, filter.getAccounts(context), currentAccount);
}
- public AccountsListAdapter(Context context, List<AccountWithDataSet> accounts) {
+ public AccountsListAdapter(Context context, List<AccountInfo> accounts) {
this(context, accounts, null);
}
@@ -85,22 +91,18 @@ public final class AccountsListAdapter extends BaseAdapter {
* @param currentAccount the Account currently selected by the user, which should come
* first in the list. Can be null.
*/
- public AccountsListAdapter(Context context, List<AccountWithDataSet> accounts,
+ public AccountsListAdapter(Context context, List<AccountInfo> accounts,
AccountWithDataSet currentAccount) {
mContext = context;
- if (currentAccount != null
+
+ final AccountInfo currentInfo = AccountInfo.getAccount(accounts, currentAccount);
+ if (currentInfo != null
&& !accounts.isEmpty()
- && !accounts.get(0).equals(currentAccount)
- && accounts.remove(currentAccount)) {
- accounts.add(0, currentAccount);
+ && !accounts.get(0).sameAccount(currentAccount)
+ && accounts.remove(currentInfo)) {
+ accounts.add(0, currentInfo);
}
- final AccountDisplayInfoFactory factory = new AccountDisplayInfoFactory(context,
- accounts);
- mAccountDisplayInfoList = new ArrayList<>(accounts.size());
- for (AccountWithDataSet account : accounts) {
- mAccountDisplayInfoList.add(factory.getAccountDisplayInfo(account));
- }
mInflater = LayoutInflater.from(context);
mAccounts = accounts;
@@ -120,22 +122,22 @@ public final class AccountsListAdapter extends BaseAdapter {
final TextView text2 = (TextView) resultView.findViewById(android.R.id.text2);
final ImageView icon = (ImageView) resultView.findViewById(android.R.id.icon);
- text1.setText(mAccountDisplayInfoList.get(position).getTypeLabel());
- text2.setText(mAccountDisplayInfoList.get(position).getNameLabel());
+ text1.setText(mAccounts.get(position).getTypeLabel());
+ text2.setText(mAccounts.get(position).getNameLabel());
- icon.setImageDrawable(mAccountDisplayInfoList.get(position).getIcon());
+ icon.setImageDrawable(mAccounts.get(position).getIcon());
return resultView;
}
@Override
public int getCount() {
- return mAccountDisplayInfoList.size();
+ return mAccounts.size();
}
@Override
public AccountWithDataSet getItem(int position) {
- return mAccountDisplayInfoList.get(position).getSource();
+ return mAccounts.get(position).getAccount();
}
@Override
diff --git a/src/com/android/contacts/util/concurrent/ListenableFutureLoader.java b/src/com/android/contacts/util/concurrent/ListenableFutureLoader.java
index f7edb6444..8c90d8763 100644
--- a/src/com/android/contacts/util/concurrent/ListenableFutureLoader.java
+++ b/src/com/android/contacts/util/concurrent/ListenableFutureLoader.java
@@ -18,7 +18,9 @@ package com.android.contacts.util.concurrent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.Loader;
+import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.google.common.util.concurrent.FutureCallback;
@@ -38,9 +40,14 @@ import java.util.concurrent.Executor;
public abstract class ListenableFutureLoader<D> extends Loader<D> {
private static final String TAG = "FutureLoader";
+ private final IntentFilter mReloadFilter;
+ private final Executor mUiExecutor;
+ private final LocalBroadcastManager mLocalBroadcastManager;
+
private ListenableFuture<D> mFuture;
private D mLoadedData;
- private Executor mUiExecutor;
+
+ private BroadcastReceiver mReceiver;
/**
* Stores away the application context associated with context.
@@ -53,12 +60,23 @@ public abstract class ListenableFutureLoader<D> extends Loader<D> {
* @param context used to retrieve the application context.
*/
public ListenableFutureLoader(Context context) {
+ this(context, null);
+ }
+
+ public ListenableFutureLoader(Context context, IntentFilter reloadBroadcastFilter) {
super(context);
mUiExecutor = ContactsExecutors.newUiThreadExecutor();
+ mReloadFilter = reloadBroadcastFilter;
+ mLocalBroadcastManager = LocalBroadcastManager.getInstance(context);
}
@Override
protected void onStartLoading() {
+ if (mReloadFilter != null && mReceiver == null) {
+ mReceiver = new ForceLoadReceiver();
+ mLocalBroadcastManager.registerReceiver(mReceiver, mReloadFilter);
+ }
+
if (mLoadedData != null) {
deliverResult(mLoadedData);
}
@@ -105,6 +123,9 @@ public abstract class ListenableFutureLoader<D> extends Loader<D> {
protected void onReset() {
mFuture = null;
mLoadedData = null;
+ if (mReceiver != null) {
+ mLocalBroadcastManager.unregisterReceiver(mReceiver);
+ }
}
protected abstract ListenableFuture<D> loadData();
diff --git a/tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java b/tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java
index e1c370af4..956f775b4 100644
--- a/tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java
+++ b/tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java
@@ -18,6 +18,7 @@ package com.android.contacts.test.mocks;
import android.accounts.Account;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.account.AccountInfo;
import com.android.contacts.model.account.AccountType;
import com.android.contacts.model.account.AccountTypeWithDataSet;
import com.android.contacts.model.account.AccountWithDataSet;
@@ -70,19 +71,18 @@ public class MockAccountTypeManager extends AccountTypeManager {
}
@Override
- public List<AccountWithDataSet> getAccounts(Predicate<AccountWithDataSet> filter) {
- return Lists.newArrayList(Collections2.filter(Arrays.asList(mAccounts), filter));
+ public ListenableFuture<List<AccountInfo>> getAccountsAsync() {
+ throw new UnsupportedOperationException("not implemented");
}
@Override
- public ListenableFuture<List<AccountWithDataSet>> getAllAccountsAsync() {
- return Futures.immediateFuture(Arrays.asList(mAccounts));
+ public ListenableFuture<List<AccountInfo>> filterAccountsAsync(Predicate<AccountInfo> filter) {
+ throw new UnsupportedOperationException("not implemented");
}
@Override
- public ListenableFuture<List<AccountWithDataSet>> filterAccountsByTypeAsync(
- Predicate<AccountType> type) {
- return Futures.immediateFuture(Arrays.asList(mAccounts));
+ public AccountInfo getAccountInfoForAccount(AccountWithDataSet account) {
+ throw new UnsupportedOperationException("not implemented");
}
@Override