diff options
7 files changed, 206 insertions, 116 deletions
diff --git a/src/com/android/contacts/editor/AccountHeaderPresenter.java b/src/com/android/contacts/editor/AccountHeaderPresenter.java index 4afebce0a..01854190e 100644 --- a/src/com/android/contacts/editor/AccountHeaderPresenter.java +++ b/src/com/android/contacts/editor/AccountHeaderPresenter.java @@ -137,11 +137,7 @@ public class AccountHeaderPresenter { final String accountLabel = getAccountLabel(account); - // Either the account header or selector should be shown, not both. - final List<AccountWithDataSet> accounts = - AccountTypeManager.getInstance(mContext).getAccounts(true); - - if (accounts.size() > 1) { + if (mAccounts.size() > 1) { addAccountSelector(accountLabel); } else { addAccountHeader(accountLabel); @@ -185,9 +181,7 @@ public class AccountHeaderPresenter { private void showPopup() { final ListPopupWindow popup = new ListPopupWindow(mContext); final AccountsListAdapter adapter = - new AccountsListAdapter(mContext, - AccountsListAdapter.AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, - mCurrentAccount); + new AccountsListAdapter(mContext, mAccounts, mCurrentAccount); popup.setWidth(mAccountHeaderContainer.getWidth()); popup.setAnchorView(mAccountHeaderContainer); popup.setAdapter(adapter); diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java index 27f500eeb..a8c37d4a2 100644 --- a/src/com/android/contacts/model/AccountTypeManager.java +++ b/src/com/android/contacts/model/AccountTypeManager.java @@ -305,13 +305,26 @@ class AccountTypeManagerImpl extends AccountTypeManager private Context mContext; private AccountManager mAccountManager; + private DeviceLocalAccountLocator mLocalAccountLocator; private AccountTypeProvider mTypeProvider; private ListeningExecutorService mExecutor; private Executor mMainThreadExecutor; private AccountType mFallbackAccountType; - private ListenableFuture<AccountTypeProvider> mLoadingFuture; + private ListenableFuture<List<AccountWithDataSet>> mLocalAccountsFuture; + private ListenableFuture<AccountTypeProvider> mAccountTypesFuture; + + private FutureCallback<Object> mAccountsUpdateCallback = new FutureCallback<Object>() { + @Override + public void onSuccess(@Nullable Object result) { + onAccountsUpdatedInternal(); + } + + @Override + public void onFailure(Throwable t) { + } + }; private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); @@ -327,6 +340,7 @@ class AccountTypeManagerImpl extends AccountTypeManager */ public AccountTypeManagerImpl(Context context) { mContext = context; + mLocalAccountLocator = DeviceLocalAccountLocator.create(context); mTypeProvider = new AccountTypeProvider(context); mFallbackAccountType = new FallbackAccountType(context); @@ -368,12 +382,12 @@ class AccountTypeManagerImpl extends AccountTypeManager @Override public void onChange(boolean selfChange) { - // TODO: update device local account types + reloadLocalAccounts(); } @Override public void onChange(boolean selfChange, Uri uri) { - // TODO: update device local account types + reloadLocalAccounts(); } }); } @@ -397,36 +411,44 @@ class AccountTypeManagerImpl extends AccountTypeManager } private synchronized void startLoadingIfNeeded() { - if (mTypeProvider == null && mLoadingFuture == null) { + if (mTypeProvider == null && mAccountTypesFuture == null) { reloadAccountTypes(); } + if (mLocalAccountsFuture == null) { + reloadLocalAccounts(); + } } private void loadAccountTypes() { mTypeProvider = new AccountTypeProvider(mContext); - mLoadingFuture = mExecutor.submit(new Callable<AccountTypeProvider>() { + mAccountTypesFuture = mExecutor.submit(new Callable<AccountTypeProvider>() { @Override public AccountTypeProvider call() throws Exception { // This will request the AccountType for each Account - getAllAccounts(mTypeProvider); + getAccountsFromProvider(mTypeProvider); return mTypeProvider; } }); } - private void reloadAccountTypes() { + private synchronized void reloadAccountTypes() { loadAccountTypes(); - Futures.addCallback(mLoadingFuture, new FutureCallback<AccountTypeProvider>() { - @Override - public void onSuccess(AccountTypeProvider result) { - onAccountsUpdatedInternal(); - } + Futures.addCallback(mAccountTypesFuture, mAccountsUpdateCallback, mMainThreadExecutor); + } + private synchronized void loadLocalAccounts() { + mLocalAccountsFuture = mExecutor.submit(new Callable<List<AccountWithDataSet>>() { @Override - public void onFailure(Throwable t) { + public List<AccountWithDataSet> call() throws Exception { + return mLocalAccountLocator.getDeviceLocalAccounts(); } - }, mMainThreadExecutor); + }); + } + + private void reloadLocalAccounts() { + loadLocalAccounts(); + Futures.addCallback(mLocalAccountsFuture, mAccountsUpdateCallback, mMainThreadExecutor); } /** @@ -435,42 +457,71 @@ class AccountTypeManagerImpl extends AccountTypeManager */ @Override public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly) { - return contactWritableOnly ? filterAccountsByType(writableFilter()) : getAllAccounts(); + final Predicate<AccountType> filter = contactWritableOnly ? + writableFilter() : Predicates.<AccountType>alwaysTrue(); + // TODO: Shouldn't have a synchronous version for getting all accounts + return Futures.getUnchecked(filterAccountsByTypeAsync(filter)); } @Override public List<AccountWithDataSet> getAccounts(Predicate<AccountWithDataSet> filter) { - return new ArrayList<>(Collections2.filter(getAllAccounts(), filter)); + // TODO: Shouldn't have a synchronous version for getting all accounts + return Futures.getUnchecked(filterAccountsAsync(filter)); } @Override public ListenableFuture<List<AccountWithDataSet>> getAllAccountsAsync() { startLoadingIfNeeded(); - return Futures.transform(Futures.nonCancellationPropagating(mLoadingFuture), - new Function<AccountTypeProvider, List<AccountWithDataSet>>() { - @Override - public List<AccountWithDataSet> apply(AccountTypeProvider input) { - return getAllAccounts(input); - } - }); + 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(); - return Futures.transform(Futures.nonCancellationPropagating(mLoadingFuture), - new Function<AccountTypeProvider, List<AccountWithDataSet>>() { - @Override - public List<AccountWithDataSet> apply(AccountTypeProvider provider) { - final List<AccountWithDataSet> accounts = getAllAccounts(provider); - return new ArrayList<>(Collections2.filter(accounts, adaptTypeFilter( - Predicates.and(Predicates.notNull(), writableFilter()), provider))); + final ListenableFuture<List<AccountWithDataSet>> accountsFromTypes = + Futures.transform(Futures.nonCancellationPropagating(mAccountTypesFuture), + new Function<AccountTypeProvider, List<AccountWithDataSet>>() { + @Override + public List<AccountWithDataSet> apply(AccountTypeProvider provider) { + return getAccountsFromProvider(provider); + } + }); + + final ListenableFuture<List<List<AccountWithDataSet>>> all = + Futures.successfulAsList(accountsFromTypes, mLocalAccountsFuture); + + return Futures.transform(all, new Function<List<List<AccountWithDataSet>>, + List<AccountWithDataSet>>() { + @Nullable + @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)); } - }); + } + return result; + } + }); } - private List<AccountWithDataSet> getAllAccounts(AccountTypeProvider cache) { + private List<AccountWithDataSet> getAccountsFromProvider(AccountTypeProvider cache) { final List<AccountWithDataSet> result = new ArrayList<>(); final Account[] accounts = mAccountManager.getAccounts(); for (Account account : accounts) { @@ -482,18 +533,17 @@ class AccountTypeManagerImpl extends AccountTypeManager return result; } - private List<AccountWithDataSet> getAllAccounts() { - return getAllAccounts(mTypeProvider); - } - - private List<AccountWithDataSet> filterAccountsByType(final Predicate<AccountType> typeFilter) { - return getAccounts(new Predicate<AccountWithDataSet>() { - @Override - public boolean apply(@Nullable AccountWithDataSet input) { - final AccountType type = mTypeProvider.getTypeForAccount(input); - return type != null && typeFilter.apply(type); + private boolean hasWritableGoogleAccount(List<AccountWithDataSet> accounts) { + if (accounts == null) { + return false; + } + AccountType type; + for (AccountWithDataSet account : accounts) { + if (GoogleAccountType.ACCOUNT_TYPE.equals(account.type) && account.dataSet == null) { + return true; } - }); + } + return false; } @@ -501,12 +551,7 @@ class AccountTypeManagerImpl extends AccountTypeManager * Return the list of all known, group writable {@link AccountWithDataSet}'s. */ public List<AccountWithDataSet> getGroupWritableAccounts() { - return filterAccountsByType(new Predicate<AccountType>() { - @Override - public boolean apply(AccountType accountType) { - return accountType.isGroupMembershipEditable(); - } - }); + return Futures.getUnchecked(filterAccountsByTypeAsync(groupWritableFilter())); } /** diff --git a/src/com/android/contacts/model/Cp2DeviceLocalAccountLocator.java b/src/com/android/contacts/model/Cp2DeviceLocalAccountLocator.java index afd7917aa..307577de5 100644 --- a/src/com/android/contacts/model/Cp2DeviceLocalAccountLocator.java +++ b/src/com/android/contacts/model/Cp2DeviceLocalAccountLocator.java @@ -60,14 +60,10 @@ public class Cp2DeviceLocalAccountLocator extends DeviceLocalAccountLocator { public Cp2DeviceLocalAccountLocator(ContentResolver contentResolver, DeviceLocalAccountTypeFactory factory, - List<AccountWithDataSet> knownAccounts) { + Set<String> knownAccountTypes) { mResolver = contentResolver; mAccountTypeFactory = factory; - final Set<String> knownAccountTypes = new HashSet<>(); - for (AccountWithDataSet account : knownAccounts) { - knownAccountTypes.add(account.type); - } mSelection = getSelection(knownAccountTypes); mSelectionArgs = getSelectionArgs(knownAccountTypes); } diff --git a/src/com/android/contacts/model/DeviceLocalAccountLocator.java b/src/com/android/contacts/model/DeviceLocalAccountLocator.java index 7fb9ef864..0d34057f9 100644 --- a/src/com/android/contacts/model/DeviceLocalAccountLocator.java +++ b/src/com/android/contacts/model/DeviceLocalAccountLocator.java @@ -15,6 +15,8 @@ */ package com.android.contacts.model; +import android.accounts.Account; +import android.accounts.AccountManager; import android.content.Context; import com.android.contacts.Experiments; @@ -23,7 +25,9 @@ import com.android.contactsbind.ObjectFactory; import com.android.contactsbind.experiments.Flags; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * Attempts to detect accounts for device contacts @@ -45,10 +49,24 @@ public abstract class DeviceLocalAccountLocator { }; public static DeviceLocalAccountLocator create(Context context, - List<AccountWithDataSet> knownAccounts) { + Set<String> knownAccountTypes) { if (Flags.getInstance().getBoolean(Experiments.OEM_CP2_DEVICE_ACCOUNT_DETECTION_ENABLED)) { return new Cp2DeviceLocalAccountLocator(context.getContentResolver(), - ObjectFactory.getDeviceLocalAccountTypeFactory(context), knownAccounts); + ObjectFactory.getDeviceLocalAccountTypeFactory(context), knownAccountTypes); + } + return NULL_ONLY; + } + + public static DeviceLocalAccountLocator create(Context context) { + final AccountManager accountManager = + (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); + final Set<String> knownTypes = new HashSet<>(); + for (Account account : accountManager.getAccounts()) { + knownTypes.add(account.type); + } + if (Flags.getInstance().getBoolean(Experiments.OEM_CP2_DEVICE_ACCOUNT_DETECTION_ENABLED)) { + return new Cp2DeviceLocalAccountLocator(context.getContentResolver(), + ObjectFactory.getDeviceLocalAccountTypeFactory(context), knownTypes); } return NULL_ONLY; } diff --git a/src/com/android/contacts/model/account/AccountTypeProvider.java b/src/com/android/contacts/model/account/AccountTypeProvider.java index ccd465eeb..474b3b4dd 100644 --- a/src/com/android/contacts/model/account/AccountTypeProvider.java +++ b/src/com/android/contacts/model/account/AccountTypeProvider.java @@ -95,6 +95,16 @@ public class AccountTypeProvider { * </p> */ public List<AccountType> getAccountTypes(String accountType) { + // ConcurrentHashMap doesn't support null keys + if (accountType == null) { + AccountType type = mLocalAccountTypeFactory.getAccountType(accountType); + // Just in case the DeviceLocalAccountTypeFactory doesn't handle the null type + if (type == null) { + type = new FallbackAccountType(mContext); + } + return Collections.singletonList(type); + } + List<AccountType> types = mCache.get(accountType); if (types == null) { types = loadTypes(accountType); diff --git a/src/com/android/contacts/util/AccountsListAdapter.java b/src/com/android/contacts/util/AccountsListAdapter.java index 256123e91..94a7c29ac 100644 --- a/src/com/android/contacts/util/AccountsListAdapter.java +++ b/src/com/android/contacts/util/AccountsListAdapter.java @@ -25,9 +25,11 @@ 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.AccountWithDataSet; import java.util.ArrayList; @@ -39,30 +41,53 @@ 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 Context mContext; private int mCustomLayout = -1; - /** - * Filters that affect the list of accounts that is displayed by this adapter. - */ public enum AccountListFilter { - ALL_ACCOUNTS, // All read-only and writable accounts - ACCOUNTS_CONTACT_WRITABLE, // Only where the account type is contact writable - ACCOUNTS_GROUP_WRITABLE // Only accounts where the account type is group writable + ALL_ACCOUNTS { + @Override + public List<AccountWithDataSet> getAccounts(Context context) { + return AccountTypeManager.getInstance(context).getAccounts(false); + } + }, + ACCOUNTS_CONTACT_WRITABLE { + @Override + public List<AccountWithDataSet> getAccounts(Context context) { + return AccountTypeManager.getInstance(context).getAccounts(true); + } + }, + ACCOUNTS_GROUP_WRITABLE { + @Override + public List<AccountWithDataSet> getAccounts(Context context) { + return AccountTypeManager.getInstance(context).getGroupWritableAccounts(); + } + }; + + public abstract List<AccountWithDataSet> getAccounts(Context context); } - public AccountsListAdapter(Context context, AccountListFilter accountListFilter) { - this(context, accountListFilter, null); + public AccountsListAdapter(Context context, AccountListFilter filter) { + this(context, filter.getAccounts(context), null); + } + + public AccountsListAdapter(Context context, AccountListFilter filter, + AccountWithDataSet currentAccount) { + this(context, filter.getAccounts(context), currentAccount); + } + + public AccountsListAdapter(Context context, List<AccountWithDataSet> accounts) { + this(context, accounts, null); } /** * @param currentAccount the Account currently selected by the user, which should come * first in the list. Can be null. */ - public AccountsListAdapter(Context context, AccountListFilter accountListFilter, + public AccountsListAdapter(Context context, List<AccountWithDataSet> accounts, AccountWithDataSet currentAccount) { mContext = context; - final List<AccountWithDataSet> accounts = getAccounts(accountListFilter); if (currentAccount != null && !accounts.isEmpty() && !accounts.get(0).equals(currentAccount) @@ -77,15 +102,8 @@ public final class AccountsListAdapter extends BaseAdapter { mAccountDisplayInfoList.add(factory.getAccountDisplayInfo(account)); } mInflater = LayoutInflater.from(context); - } - private List<AccountWithDataSet> getAccounts(AccountListFilter accountListFilter) { - final AccountTypeManager typeManager = AccountTypeManager.getInstance(mContext); - if (accountListFilter == AccountListFilter.ACCOUNTS_GROUP_WRITABLE) { - return new ArrayList<AccountWithDataSet>(typeManager.getGroupWritableAccounts()); - } - return new ArrayList<AccountWithDataSet>(typeManager.getAccounts( - accountListFilter == AccountListFilter.ACCOUNTS_CONTACT_WRITABLE)); + mAccounts = accounts; } public void setCustomLayout(int customLayout) { diff --git a/tests/src/com/android/contacts/model/Cp2DeviceLocalAccountLocatorTests.java b/tests/src/com/android/contacts/model/Cp2DeviceLocalAccountLocatorTests.java index e6e67bfd8..4e6212619 100644 --- a/tests/src/com/android/contacts/model/Cp2DeviceLocalAccountLocatorTests.java +++ b/tests/src/com/android/contacts/model/Cp2DeviceLocalAccountLocatorTests.java @@ -24,6 +24,7 @@ import android.os.CancellationSignal; import android.provider.ContactsContract; import android.provider.ContactsContract.RawContacts; import android.support.annotation.Nullable; +import android.support.v4.util.ArraySet; import android.test.AndroidTestCase; import android.test.mock.MockContentResolver; import android.test.suitebuilder.annotation.SmallTest; @@ -48,7 +49,7 @@ public class Cp2DeviceLocalAccountLocatorTests extends AndroidTestCase { final DeviceLocalAccountLocator sut = new Cp2DeviceLocalAccountLocator( getContext().getContentResolver(), new DeviceLocalAccountTypeFactory.Default(getContext()), - Collections.<AccountWithDataSet>emptyList()); + Collections.<String>emptySet()); sut.getDeviceLocalAccounts(); // We didn't throw so it passed } @@ -80,31 +81,29 @@ public class Cp2DeviceLocalAccountLocatorTests extends AndroidTestCase { final DeviceLocalAccountTypeFactory stubFactory = new FakeDeviceAccountTypeFactory() .withDeviceTypes(null, "vnd.sec.contact.phone") .withSimTypes("vnd.sec.contact.sim"); - final DeviceLocalAccountLocator sut = new Cp2DeviceLocalAccountLocator( - createStubResolverWithContentQueryResult(queryResult( - "user", "com.example", - "user", "com.example", - "phone_account", "vnd.sec.contact.phone", - null, null, - "phone_account", "vnd.sec.contact.phone", - "user", "com.example", - null, null, - "sim_account", "vnd.sec.contact.sim", - "sim_account_2", "vnd.sec.contact.sim" - )), stubFactory, - Collections.<AccountWithDataSet>emptyList()); + final DeviceLocalAccountLocator sut = createLocator(queryResult( + "user", "com.example", + "user", "com.example", + "phone_account", "vnd.sec.contact.phone", + null, null, + "phone_account", "vnd.sec.contact.phone", + "user", "com.example", + null, null, + "sim_account", "vnd.sec.contact.sim", + "sim_account_2", "vnd.sec.contact.sim" + ), stubFactory); + assertEquals(4, sut.getDeviceLocalAccounts().size()); } - public void test_getDeviceLocalAccounts_doesNotContainItemsForKnownAccounts() { + public void test_getDeviceLocalAccounts_doesNotContainItemsForKnownAccountTypes() { final Cp2DeviceLocalAccountLocator sut = new Cp2DeviceLocalAccountLocator( getContext().getContentResolver(), new FakeDeviceAccountTypeFactory(), - Arrays.asList(new AccountWithDataSet("user", "com.example", null), - new AccountWithDataSet("user1", "com.example", null), - new AccountWithDataSet("user", "com.example.1", null))); + new ArraySet<>(Arrays.asList("com.example", "com.example.1"))); - assertTrue("Selection should filter known accounts", sut.getSelection().contains("NOT IN (?,?)")); + assertTrue("Selection should filter known accounts", + sut.getSelection().contains("NOT IN (?,?)")); final List<String> args = Arrays.asList(sut.getSelectionArgs()); assertEquals(2, args.size()); @@ -116,12 +115,11 @@ public class Cp2DeviceLocalAccountLocatorTests extends AndroidTestCase { final DeviceLocalAccountTypeFactory stubFactory = new FakeDeviceAccountTypeFactory() .withDeviceTypes(null, "vnd.sec.contact.phone") .withSimTypes("vnd.sec.contact.sim"); - final DeviceLocalAccountLocator sut = new Cp2DeviceLocalAccountLocator( - createContentResolverWithProvider(new FakeContactsProvider() - .withQueryResult(ContactsContract.Settings.CONTENT_URI, queryResult( - "phone_account", "vnd.sec.contact.phone", - "sim_account", "vnd.sec.contact.sim" - ))), stubFactory, Collections.<AccountWithDataSet>emptyList()); + final DeviceLocalAccountLocator sut = createLocator(new FakeContactsProvider() + .withQueryResult(ContactsContract.Settings.CONTENT_URI, queryResult( + "phone_account", "vnd.sec.contact.phone", + "sim_account", "vnd.sec.contact.sim" + )), stubFactory); assertEquals(2, sut.getDeviceLocalAccounts().size()); } @@ -130,22 +128,34 @@ public class Cp2DeviceLocalAccountLocatorTests extends AndroidTestCase { final DeviceLocalAccountTypeFactory stubFactory = new FakeDeviceAccountTypeFactory() .withDeviceTypes(null, "vnd.sec.contact.phone") .withSimTypes("vnd.sec.contact.sim"); - final DeviceLocalAccountLocator sut = new Cp2DeviceLocalAccountLocator( - createContentResolverWithProvider(new FakeContactsProvider() - .withQueryResult(ContactsContract.Groups.CONTENT_URI, queryResult( - "phone_account", "vnd.sec.contact.phone", - "sim_account", "vnd.sec.contact.sim" - ))), stubFactory, Collections.<AccountWithDataSet>emptyList()); + final DeviceLocalAccountLocator sut = createLocator(new FakeContactsProvider() + .withQueryResult(ContactsContract.Groups.CONTENT_URI, queryResult( + "phone_account", "vnd.sec.contact.phone", + "sim_account", "vnd.sec.contact.sim" + )), stubFactory); assertEquals(2, sut.getDeviceLocalAccounts().size()); } private DeviceLocalAccountLocator createWithQueryResult( Cursor cursor) { + return createLocator(cursor, new DeviceLocalAccountTypeFactory.Default(mContext)); + } + + private DeviceLocalAccountLocator createLocator(ContentProvider contactsProvider, + DeviceLocalAccountTypeFactory localAccountTypeFactory) { + final DeviceLocalAccountLocator locator = new Cp2DeviceLocalAccountLocator( + createContentResolverWithProvider(contactsProvider), + localAccountTypeFactory, Collections.<String>emptySet()); + return locator; + } + + private DeviceLocalAccountLocator createLocator(Cursor cursor, + DeviceLocalAccountTypeFactory localAccountTypeFactory) { final DeviceLocalAccountLocator locator = new Cp2DeviceLocalAccountLocator( createStubResolverWithContentQueryResult(cursor), - new DeviceLocalAccountTypeFactory.Default(getContext()), - Collections.<AccountWithDataSet>emptyList()); + localAccountTypeFactory, + Collections.<String>emptySet()); return locator; } @@ -155,7 +165,6 @@ public class Cp2DeviceLocalAccountLocatorTests extends AndroidTestCase { return resolver; } - private ContentResolver createStubResolverWithContentQueryResult(Cursor cursor) { final MockContentResolver resolver = new MockContentResolver(); resolver.addProvider(ContactsContract.AUTHORITY, new FakeContactsProvider() |