diff options
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 |