diff options
10 files changed, 29 insertions, 597 deletions
diff --git a/src/com/android/contacts/editor/ContactEditorUtils.java b/src/com/android/contacts/editor/ContactEditorUtils.java index 24d5ce009..4bb075cc6 100644 --- a/src/com/android/contacts/editor/ContactEditorUtils.java +++ b/src/com/android/contacts/editor/ContactEditorUtils.java @@ -23,6 +23,7 @@ import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.Bundle; import android.provider.ContactsContract; import android.text.TextUtils; @@ -147,46 +148,20 @@ public class ContactEditorUtils { } } - @VisibleForTesting - String[] getWritableAccountTypeStrings() { - final Set<String> types = Sets.newHashSet(); - for (AccountType type : mAccountTypes.getAccountTypes(true)) { - types.add(type.accountType); - } - return types.toArray(new String[types.size()]); - } - /** - * Create an {@link Intent} to start "add new account" setup wizard. Selectable account - * types will be limited to ones that supports editing contacts. + * Parses a result from {@link AccountManager#newChooseAccountIntent(Account, List, String[], + * String, String, String[], Bundle)} and returns the created {@link Account}, or null if + * the user has canceled the wizard. * - * Use {@link Activity#startActivityForResult} or - * {@link android.app.Fragment#startActivityForResult} to start the wizard, and - * {@link Activity#onActivityResult} or {@link android.app.Fragment#onActivityResult} to - * get the result. - */ - public Intent createAddWritableAccountIntent() { - return AccountManager.newChooseAccountIntent( - null, // selectedAccount - new ArrayList<Account>(), // allowableAccounts - getWritableAccountTypeStrings(), // allowableAccountTypes - false, // alwaysPromptForAccount - null, // descriptionOverrideText - null, // addAccountAuthTokenType - null, // addAccountRequiredFeatures - null // addAccountOptions - ); - } - - /** - * Parses a result from {@link #createAddWritableAccountIntent} and returns the created - * {@link Account}, or null if the user has canceled the wizard. Pass the {@code resultCode} - * and {@code data} parameters passed to {@link Activity#onActivityResult} or - * {@link android.app.Fragment#onActivityResult}. + * <p>Pass the {@code resultCode} and {@code data} parameters passed to + * {@link Activity#onActivityResult} or {@link android.app.Fragment#onActivityResult}. + * </p> * + * <p> * Note although the return type is {@link AccountWithDataSet}, return values from this method * will never have {@link AccountWithDataSet#dataSet} set, as there's no way to create an * extension package account from setup wizard. + * </p> */ public AccountWithDataSet getCreatedAccount(int resultCode, Intent resultData) { // Javadoc doesn't say anything about resultCode but that the data intent will be non null diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java index b0b3173a9..24957d7b7 100644 --- a/src/com/android/contacts/model/AccountTypeManager.java +++ b/src/com/android/contacts/model/AccountTypeManager.java @@ -16,8 +16,6 @@ package com.android.contacts.model; -import static com.android.contacts.util.DeviceLocalAccountTypeFactory.Util.isLocalAccountType; - import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AuthenticatorDescription; @@ -31,10 +29,8 @@ import android.content.SharedPreferences; import android.content.SyncAdapterType; import android.content.SyncStatusObserver; import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.database.ContentObserver; import android.net.Uri; -import android.os.AsyncTask; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; @@ -47,7 +43,6 @@ import android.util.Log; import android.util.TimingLogger; import com.android.contacts.Experiments; -import com.android.contacts.MoreContactUtils; import com.android.contacts.R; import com.android.contacts.list.ContactListFilterController; import com.android.contacts.model.account.AccountType; @@ -63,8 +58,6 @@ import com.android.contacts.util.Constants; import com.android.contacts.util.DeviceLocalAccountTypeFactory; import com.android.contactsbind.ObjectFactory; import com.android.contactsbind.experiments.Flags; - -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Objects; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; @@ -73,18 +66,17 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; import javax.annotation.Nullable; +import static com.android.contacts.util.DeviceLocalAccountTypeFactory.Util.isLocalAccountType; + /** * Singleton holder for all parsed {@link AccountType} available on the * system, typically filled through {@link PackageManager} queries. @@ -150,25 +142,9 @@ public abstract class AccountTypeManager { } @Override - public List<AccountWithDataSet> getSortedAccounts(AccountWithDataSet defaultAccount, - boolean contactWritableOnly) { - return Collections.emptyList(); - } - - @Override public AccountType getAccountType(AccountTypeWithDataSet accountTypeWithDataSet) { return null; } - - @Override - public Map<AccountTypeWithDataSet, AccountType> getUsableInvitableAccountTypes() { - return null; - } - - @Override - public List<AccountType> getAccountTypes(boolean contactWritableOnly) { - return Collections.emptyList(); - } }; /** @@ -180,9 +156,6 @@ public abstract class AccountTypeManager { public abstract List<AccountWithDataSet> getAccounts(Predicate<AccountWithDataSet> filter); - public abstract List<AccountWithDataSet> getSortedAccounts(AccountWithDataSet defaultAccount, - boolean contactWritableOnly); - /** * Returns the list of accounts that are group writable. */ @@ -235,21 +208,6 @@ public abstract class AccountTypeManager { } /** - * @return Unmodifiable map from {@link AccountTypeWithDataSet}s to {@link AccountType}s - * which support the "invite" feature and have one or more account. - * - * This is a filtered down and more "usable" list compared to - * {@link #getAllInvitableAccountTypes}, where usable is defined as: - * (1) making sure that the app that contributed the account type is not disabled - * (in order to avoid presenting the user with an option that does nothing), and - * (2) that there is at least one raw contact with that account type in the database - * (assuming that the user probably doesn't use that account type). - * - * Warning: Don't use on the UI thread because this can scan the database. - */ - public abstract Map<AccountTypeWithDataSet, AccountType> getUsableInvitableAccountTypes(); - - /** * Find the best {@link DataKind} matching the requested * {@link AccountType#accountType}, {@link AccountType#dataSet}, and {@link DataKind#mimeType}. * If no direct match found, we try searching {@link FallbackAccountType}. @@ -259,13 +217,6 @@ public abstract class AccountTypeManager { } /** - * Returns all registered {@link AccountType}s, including extension ones. - * - * @param contactWritableOnly if true, it only returns ones that support writing contacts. - */ - public abstract List<AccountType> getAccountTypes(boolean contactWritableOnly); - - /** * @param contactWritableOnly if true, it only returns ones that support writing contacts. * @return true when this instance contains the given account. */ @@ -282,6 +233,15 @@ 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; @@ -351,19 +311,6 @@ class AccountComparator implements Comparator<AccountWithDataSet> { class AccountTypeManagerImpl extends AccountTypeManager implements OnAccountsUpdateListener, SyncStatusObserver { - private static final Map<AccountTypeWithDataSet, AccountType> - EMPTY_UNMODIFIABLE_ACCOUNT_TYPE_MAP = - Collections.unmodifiableMap(new HashMap<AccountTypeWithDataSet, AccountType>()); - - /** - * A sample contact URI used to test whether any activities will respond to an - * invitable intent with the given URI as the intent data. This doesn't need to be - * specific to a real contact because an app that intercepts the intent should probably do so - * for all types of contact URIs. - */ - private static final Uri SAMPLE_CONTACT_URI = ContactsContract.Contacts.getLookupUri( - 1, "xxx"); - private Context mContext; private AccountManager mAccountManager; private DeviceLocalAccountTypeFactory mDeviceLocalAccountTypeFactory; @@ -374,22 +321,6 @@ class AccountTypeManagerImpl extends AccountTypeManager private List<AccountWithDataSet> mContactWritableAccounts = Lists.newArrayList(); private List<AccountWithDataSet> mGroupWritableAccounts = Lists.newArrayList(); private Map<AccountTypeWithDataSet, AccountType> mAccountTypesWithDataSets = Maps.newHashMap(); - private Map<AccountTypeWithDataSet, AccountType> mInvitableAccountTypes = - EMPTY_UNMODIFIABLE_ACCOUNT_TYPE_MAP; - - private final InvitableAccountTypeCache mInvitableAccountTypeCache; - - /** - * The boolean value is equal to true if the {@link InvitableAccountTypeCache} has been - * initialized. False otherwise. - */ - private final AtomicBoolean mInvitablesCacheIsInitialized = new AtomicBoolean(false); - - /** - * The boolean value is equal to true if the {@link FindInvitablesTask} is still executing. - * False otherwise. - */ - private final AtomicBoolean mInvitablesTaskIsRunning = new AtomicBoolean(false); private static final int MESSAGE_LOAD_DATA = 0; private static final int MESSAGE_PROCESS_BROADCAST_INTENT = 1; @@ -445,8 +376,6 @@ class AccountTypeManagerImpl extends AccountTypeManager } }; - mInvitableAccountTypeCache = new InvitableAccountTypeCache(); - // Request updates when packages or accounts change IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); @@ -721,8 +650,6 @@ class AccountTypeManagerImpl extends AccountTypeManager mAccounts = allAccounts; mContactWritableAccounts = contactWritableAccounts; mGroupWritableAccounts = groupWritableAccounts; - mInvitableAccountTypes = findAllInvitableAccountTypes( - mContext, allAccounts, accountTypesByTypeAndDataSet); } timings.dumpToLog(); @@ -789,21 +716,6 @@ class AccountTypeManagerImpl extends AccountTypeManager } /** - * Return list of all known or contact writable {@link AccountWithDataSet}'s sorted by - * {@code defaultAccount}. - * {@param defaultAccount} account to sort by - * {@param contactWritableOnly} whether to restrict to contact writable accounts only - */ - @Override - public List<AccountWithDataSet> getSortedAccounts(AccountWithDataSet defaultAccount, - boolean contactWritableOnly) { - final AccountComparator comparator = new AccountComparator(defaultAccount); - final List<AccountWithDataSet> accounts = getAccounts(contactWritableOnly); - Collections.sort(accounts, comparator); - return accounts; - } - - /** * Return the list of all known, group writable {@link AccountWithDataSet}'s. */ public List<AccountWithDataSet> getGroupWritableAccounts() { @@ -865,195 +777,4 @@ class AccountTypeManagerImpl extends AccountTypeManager return type != null ? type : mFallbackAccountType; } } - - /** - * @return Unmodifiable map from {@link AccountTypeWithDataSet}s to {@link AccountType}s - * which support the "invite" feature and have one or more account. This is an unfiltered - * list. See {@link #getUsableInvitableAccountTypes()}. - */ - private Map<AccountTypeWithDataSet, AccountType> getAllInvitableAccountTypes() { - ensureAccountsLoaded(); - return mInvitableAccountTypes; - } - - @Override - public Map<AccountTypeWithDataSet, AccountType> getUsableInvitableAccountTypes() { - ensureAccountsLoaded(); - // Since this method is not thread-safe, it's possible for multiple threads to encounter - // the situation where (1) the cache has not been initialized yet or - // (2) an async task to refresh the account type list in the cache has already been - // started. Hence we use {@link AtomicBoolean}s and return cached values immediately - // while we compute the actual result in the background. We use this approach instead of - // using "synchronized" because computing the account type list involves a DB read, and - // can potentially cause a deadlock situation if this method is called from code which - // holds the DB lock. The trade-off of potentially having an incorrect list of invitable - // account types for a short period of time seems more manageable than enforcing the - // context in which this method is called. - - // Computing the list of usable invitable account types is done on the fly as requested. - // If this method has never been called before, then block until the list has been computed. - if (!mInvitablesCacheIsInitialized.get()) { - mInvitableAccountTypeCache.setCachedValue(findUsableInvitableAccountTypes(mContext)); - mInvitablesCacheIsInitialized.set(true); - } else { - // Otherwise, there is a value in the cache. If the value has expired and - // an async task has not already been started by another thread, then kick off a new - // async task to compute the list. - if (mInvitableAccountTypeCache.isExpired() && - mInvitablesTaskIsRunning.compareAndSet(false, true)) { - new FindInvitablesTask().execute(); - } - } - - return mInvitableAccountTypeCache.getCachedValue(); - } - - /** - * Return all {@link AccountType}s with at least one account which supports "invite", i.e. - * its {@link AccountType#getInviteContactActivityClassName()} is not empty. - */ - @VisibleForTesting - static Map<AccountTypeWithDataSet, AccountType> findAllInvitableAccountTypes(Context context, - Collection<AccountWithDataSet> accounts, - Map<AccountTypeWithDataSet, AccountType> accountTypesByTypeAndDataSet) { - HashMap<AccountTypeWithDataSet, AccountType> result = Maps.newHashMap(); - for (AccountWithDataSet account : accounts) { - AccountTypeWithDataSet accountTypeWithDataSet = account.getAccountTypeWithDataSet(); - AccountType type = accountTypesByTypeAndDataSet.get(accountTypeWithDataSet); - if (type == null) continue; // just in case - if (result.containsKey(accountTypeWithDataSet)) continue; - - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Type " + accountTypeWithDataSet - + " inviteClass=" + type.getInviteContactActivityClassName()); - } - if (!TextUtils.isEmpty(type.getInviteContactActivityClassName())) { - result.put(accountTypeWithDataSet, type); - } - } - return Collections.unmodifiableMap(result); - } - - /** - * Return all usable {@link AccountType}s that support the "invite" feature from the - * list of all potential invitable account types (retrieved from - * {@link #getAllInvitableAccountTypes}). A usable invitable account type means: - * (1) there is at least 1 raw contact in the database with that account type, and - * (2) the app contributing the account type is not disabled. - * - * Warning: Don't use on the UI thread because this can scan the database. - */ - private Map<AccountTypeWithDataSet, AccountType> findUsableInvitableAccountTypes( - Context context) { - Map<AccountTypeWithDataSet, AccountType> allInvitables = getAllInvitableAccountTypes(); - if (allInvitables.isEmpty()) { - return EMPTY_UNMODIFIABLE_ACCOUNT_TYPE_MAP; - } - - final HashMap<AccountTypeWithDataSet, AccountType> result = Maps.newHashMap(); - result.putAll(allInvitables); - - final PackageManager packageManager = context.getPackageManager(); - for (AccountTypeWithDataSet accountTypeWithDataSet : allInvitables.keySet()) { - AccountType accountType = allInvitables.get(accountTypeWithDataSet); - - // Make sure that account types don't come from apps that are disabled. - Intent invitableIntent = MoreContactUtils.getInvitableIntent(accountType, - SAMPLE_CONTACT_URI); - if (invitableIntent == null) { - result.remove(accountTypeWithDataSet); - continue; - } - ResolveInfo resolveInfo = packageManager.resolveActivity(invitableIntent, - PackageManager.MATCH_DEFAULT_ONLY); - if (resolveInfo == null) { - // If we can't find an activity to start for this intent, then there's no point in - // showing this option to the user. - result.remove(accountTypeWithDataSet); - continue; - } - - // Make sure that there is at least 1 raw contact with this account type. This check - // is non-trivial and should not be done on the UI thread. - if (!accountTypeWithDataSet.hasData(context)) { - result.remove(accountTypeWithDataSet); - } - } - - return Collections.unmodifiableMap(result); - } - - @Override - public List<AccountType> getAccountTypes(boolean contactWritableOnly) { - ensureAccountsLoaded(); - final List<AccountType> accountTypes = Lists.newArrayList(); - synchronized (this) { - for (AccountType type : mAccountTypesWithDataSets.values()) { - if (!contactWritableOnly || type.areContactsWritable()) { - accountTypes.add(type); - } - } - } - return accountTypes; - } - - /** - * Background task to find all usable {@link AccountType}s that support the "invite" feature - * from the list of all potential invitable account types. Once the work is completed, - * the list of account types is stored in the {@link AccountTypeManager}'s - * {@link InvitableAccountTypeCache}. - */ - private class FindInvitablesTask extends AsyncTask<Void, Void, - Map<AccountTypeWithDataSet, AccountType>> { - - @Override - protected Map<AccountTypeWithDataSet, AccountType> doInBackground(Void... params) { - return findUsableInvitableAccountTypes(mContext); - } - - @Override - protected void onPostExecute(Map<AccountTypeWithDataSet, AccountType> accountTypes) { - mInvitableAccountTypeCache.setCachedValue(accountTypes); - mInvitablesTaskIsRunning.set(false); - } - } - - /** - * This cache holds a list of invitable {@link AccountTypeWithDataSet}s, in the form of a - * {@link Map<AccountTypeWithDataSet, AccountType>}. Note that the cached value is valid only - * for {@link #TIME_TO_LIVE} milliseconds. - */ - private static final class InvitableAccountTypeCache { - - /** - * The cached {@link #mInvitableAccountTypes} list expires after this number of milliseconds - * has elapsed. - */ - private static final long TIME_TO_LIVE = 60000; - - private Map<AccountTypeWithDataSet, AccountType> mInvitableAccountTypes; - - private long mTimeLastSet; - - /** - * Returns true if the data in this cache is stale and needs to be refreshed. Returns false - * otherwise. - */ - public boolean isExpired() { - return SystemClock.elapsedRealtime() - mTimeLastSet > TIME_TO_LIVE; - } - - /** - * Returns the cached value. Note that the caller is responsible for checking - * {@link #isExpired()} to ensure that the value is not stale. - */ - public Map<AccountTypeWithDataSet, AccountType> getCachedValue() { - return mInvitableAccountTypes; - } - - public void setCachedValue(Map<AccountTypeWithDataSet, AccountType> map) { - mInvitableAccountTypes = map; - mTimeLastSet = SystemClock.elapsedRealtime(); - } - } } diff --git a/src/com/android/contacts/model/Contact.java b/src/com/android/contacts/model/Contact.java index 9d7d9aaa2..82661236d 100644 --- a/src/com/android/contacts/model/Contact.java +++ b/src/com/android/contacts/model/Contact.java @@ -74,7 +74,6 @@ public class Contact { private final Integer mPresence; private ImmutableList<RawContact> mRawContacts; private ImmutableMap<Long,DataStatus> mStatuses; - private ImmutableList<AccountType> mInvitableAccountTypes; private String mDirectoryDisplayName; private String mDirectoryType; @@ -123,7 +122,6 @@ public class Contact { mPhoneticName = null; mStarred = false; mPresence = null; - mInvitableAccountTypes = null; mSendToVoicemail = false; mCustomRingtone = null; mIsUserProfile = false; @@ -164,7 +162,6 @@ public class Contact { mPhoneticName = phoneticName; mStarred = starred; mPresence = presence; - mInvitableAccountTypes = null; mSendToVoicemail = sendToVoicemail; mCustomRingtone = customRingtone; mIsUserProfile = isUserProfile; @@ -191,7 +188,6 @@ public class Contact { mPresence = from.mPresence; mRawContacts = from.mRawContacts; mStatuses = from.mStatuses; - mInvitableAccountTypes = from.mInvitableAccountTypes; mDirectoryDisplayName = from.mDirectoryDisplayName; mDirectoryType = from.mDirectoryType; @@ -349,15 +345,6 @@ public class Contact { return mPresence; } - /** - * This can return non-null invitable account types only if the {@link ContactLoader} was - * configured to load invitable account types in its constructor. - * @return - */ - public ImmutableList<AccountType> getInvitableAccountTypes() { - return mInvitableAccountTypes; - } - public ImmutableList<RawContact> getRawContacts() { return mRawContacts; } @@ -503,10 +490,6 @@ public class Contact { mStatuses = statuses; } - /* package */ void setInvitableAccountTypes(ImmutableList<AccountType> accountTypes) { - mInvitableAccountTypes = accountTypes; - } - /* package */ void setGroupMetaData(ImmutableList<GroupMetaData> groups) { mGroups = groups; } diff --git a/src/com/android/contacts/model/ContactLoader.java b/src/com/android/contacts/model/ContactLoader.java index a864a865d..acb821203 100644 --- a/src/com/android/contacts/model/ContactLoader.java +++ b/src/com/android/contacts/model/ContactLoader.java @@ -89,7 +89,6 @@ public class ContactLoader extends AsyncTaskLoader<Contact> { private final Uri mRequestedUri; private Uri mLookupUri; private boolean mLoadGroupMetaData; - private boolean mLoadInvitableAccountTypes; private boolean mPostViewNotification; private boolean mComputeFormattedPhoneNumber; private Contact mContact; @@ -97,22 +96,20 @@ public class ContactLoader extends AsyncTaskLoader<Contact> { private final Set<Long> mNotifiedRawContactIds = Sets.newHashSet(); public ContactLoader(Context context, Uri lookupUri, boolean postViewNotification) { - this(context, lookupUri, false, false, postViewNotification, false); + this(context, lookupUri, false, postViewNotification, false); } public ContactLoader(Context context, Uri lookupUri, boolean postViewNotification, boolean loadGroupMetaData) { - this(context, lookupUri, loadGroupMetaData, false, postViewNotification, false); + this(context, lookupUri, loadGroupMetaData, postViewNotification, false); } public ContactLoader(Context context, Uri lookupUri, boolean loadGroupMetaData, - boolean loadInvitableAccountTypes, boolean postViewNotification, boolean computeFormattedPhoneNumber) { super(context); mLookupUri = lookupUri; mRequestedUri = lookupUri; mLoadGroupMetaData = loadGroupMetaData; - mLoadInvitableAccountTypes = loadInvitableAccountTypes; mPostViewNotification = postViewNotification; mComputeFormattedPhoneNumber = computeFormattedPhoneNumber; } @@ -344,10 +341,6 @@ public class ContactLoader extends AsyncTaskLoader<Contact> { } if (!resultIsCached) loadPhotoBinaryData(result); - // Note ME profile should never have "Add connection" - if (mLoadInvitableAccountTypes && result.getInvitableAccountTypes() == null) { - loadInvitableAccountTypes(result); - } } return result; } catch (Exception e) { @@ -591,35 +584,6 @@ public class ContactLoader extends AsyncTaskLoader<Contact> { } /** - * Sets the "invitable" account types to {@link Contact#mInvitableAccountTypes}. - */ - private void loadInvitableAccountTypes(Contact contactData) { - final ImmutableList.Builder<AccountType> resultListBuilder = - new ImmutableList.Builder<AccountType>(); - if (!contactData.isUserProfile()) { - Map<AccountTypeWithDataSet, AccountType> invitables = - AccountTypeManager.getInstance(getContext()).getUsableInvitableAccountTypes(); - if (!invitables.isEmpty()) { - final Map<AccountTypeWithDataSet, AccountType> resultMap = - Maps.newHashMap(invitables); - - // Remove the ones that already have a raw contact in the current contact - for (RawContact rawContact : contactData.getRawContacts()) { - final AccountTypeWithDataSet type = AccountTypeWithDataSet.get( - rawContact.getAccountTypeString(), - rawContact.getDataSet()); - resultMap.remove(type); - } - - resultListBuilder.addAll(resultMap.values()); - } - } - - // Set to mInvitableAccountTypes - contactData.setInvitableAccountTypes(resultListBuilder.build()); - } - - /** * Extracts Contact level columns from the cursor. */ private Contact loadContactHeaderData(final Cursor cursor, Uri contactUri) { @@ -954,28 +918,6 @@ public class ContactLoader extends AsyncTaskLoader<Contact> { } } - /** - * Fully upgrades this ContactLoader to one with all lists fully loaded. When done, the - * new result will be delivered - */ - public void upgradeToFullContact() { - // Everything requested already? Nothing to do, so let's bail out - if (mLoadGroupMetaData && mLoadInvitableAccountTypes - && mPostViewNotification && mComputeFormattedPhoneNumber) return; - - mLoadGroupMetaData = true; - mLoadInvitableAccountTypes = true; - mPostViewNotification = true; - mComputeFormattedPhoneNumber = true; - - // Cache the current result, so that we only load the "missing" parts of the contact. - cacheResult(); - - // Our load parameters have changed, so let's pretend the data has changed. Its the same - // thing, essentially. - onContentChanged(); - } - public Uri getLookupUri() { return mLookupUri; } diff --git a/src/com/android/contacts/model/account/AccountWithDataSet.java b/src/com/android/contacts/model/account/AccountWithDataSet.java index b0bb84d35..0f36918b6 100644 --- a/src/com/android/contacts/model/account/AccountWithDataSet.java +++ b/src/com/android/contacts/model/account/AccountWithDataSet.java @@ -30,7 +30,6 @@ import android.text.TextUtils; import com.android.contacts.model.AccountTypeManager; import com.android.contacts.preference.ContactsPreferences; - import com.google.common.base.Objects; import com.google.common.collect.Lists; @@ -281,3 +280,4 @@ public class AccountWithDataSet implements Parcelable { return accounts.get(0); } } + diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java index 8bf7b68a0..1dfa10c3f 100644 --- a/src/com/android/contacts/quickcontact/QuickContactActivity.java +++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java @@ -2318,8 +2318,8 @@ public class QuickContactActivity extends ContactsActivity { // Load all contact data. We need loadGroupMetaData=true to determine whether the // contact is invisible. If it is, we need to display an "Add to Contacts" MenuItem. return new ContactLoader(getApplicationContext(), mLookupUri, - true /*loadGroupMetaData*/, false /*loadInvitableAccountTypes*/, - true /*postViewNotification*/, true /*computeFormattedPhoneNumber*/); + true /*loadGroupMetaData*/, true /*postViewNotification*/, + true /*computeFormattedPhoneNumber*/); } }; diff --git a/src/com/android/contacts/util/AccountFilterUtil.java b/src/com/android/contacts/util/AccountFilterUtil.java index 0c36f5e80..3a6d49e4e 100644 --- a/src/com/android/contacts/util/AccountFilterUtil.java +++ b/src/com/android/contacts/util/AccountFilterUtil.java @@ -133,8 +133,8 @@ public class AccountFilterUtil { DeviceLocalAccountTypeFactory deviceAccountTypeFactory) { final ArrayList<ContactListFilter> accountFilters = Lists.newArrayList(); final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(context); - final List<AccountWithDataSet> accounts = accountTypeManager.getSortedAccounts( - /* defaultAccount */ getDefaultAccount(context), /* contactWritableOnly */ true); + final List<AccountWithDataSet> accounts = accountTypeManager.getAccounts(true); + AccountTypeManager.sortAccounts(getDefaultAccount(context), accounts); for (AccountWithDataSet account : accounts) { final AccountType accountType = diff --git a/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java b/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java index f6c2d1b1c..9756a0c50 100644 --- a/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java +++ b/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java @@ -79,37 +79,6 @@ public class ContactEditorUtilsTest extends AndroidTestCase { mAccountTypes.mAccounts = accounts; } - public void testGetWritableAccountTypeStrings() { - String[] types; - - // 0 writable types - setAccountTypes(); - - types = mTarget.getWritableAccountTypeStrings(); - MoreAsserts.assertEquals(types, new String[0]); - - // 1 writable type - setAccountTypes(TYPE1); - - types = mTarget.getWritableAccountTypeStrings(); - MoreAsserts.assertEquals(Sets.newHashSet(TYPE1.accountType), Sets.newHashSet(types)); - - // 2 writable types - setAccountTypes(TYPE1, TYPE2EX); - - types = mTarget.getWritableAccountTypeStrings(); - MoreAsserts.assertEquals(Sets.newHashSet(TYPE1.accountType, TYPE2EX.accountType), - Sets.newHashSet(types)); - - // 3 writable types + 1 readonly type - setAccountTypes(TYPE1, TYPE2, TYPE2EX, TYPE3); - - types = mTarget.getWritableAccountTypeStrings(); - MoreAsserts.assertEquals( - Sets.newHashSet(TYPE1.accountType, TYPE2.accountType, TYPE2EX.accountType), - Sets.newHashSet(types)); - } - /** * Test for * - {@link ContactEditorUtils#saveDefaultAccount} diff --git a/tests/src/com/android/contacts/model/AccountTypeManagerTest.java b/tests/src/com/android/contacts/model/AccountTypeManagerTest.java index da2e6c3bd..982517b1b 100644 --- a/tests/src/com/android/contacts/model/AccountTypeManagerTest.java +++ b/tests/src/com/android/contacts/model/AccountTypeManagerTest.java @@ -16,11 +16,8 @@ package com.android.contacts.model; -import static org.mockito.Mockito.when; - import android.accounts.Account; import android.accounts.AccountManager; -import android.content.Context; import android.content.SharedPreferences; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; @@ -29,7 +26,6 @@ import com.android.contacts.model.account.AccountType; import com.android.contacts.model.account.AccountTypeWithDataSet; import com.android.contacts.model.account.AccountWithDataSet; import com.android.contacts.model.account.GoogleAccountType; - import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -42,6 +38,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static org.mockito.Mockito.when; + /** * Test case for {@link com.android.contacts.model.AccountTypeManager}. * @@ -67,93 +65,6 @@ public class AccountTypeManagerTest extends AndroidTestCase { MockitoAnnotations.initMocks(this); } - public void testFindAllInvitableAccountTypes() { - final Context c = getContext(); - - // Define account types. - final AccountType typeA = new MockAccountType("type1", null, null); - final AccountType typeB = new MockAccountType("type1", "minus", null); - final AccountType typeC = new MockAccountType("type2", null, "c"); - final AccountType typeD = new MockAccountType("type2", "minus", "d"); - - // Define users - final AccountWithDataSet accountA1 = createAccountWithDataSet("a1", typeA); - final AccountWithDataSet accountC1 = createAccountWithDataSet("c1", typeC); - final AccountWithDataSet accountC2 = createAccountWithDataSet("c2", typeC); - final AccountWithDataSet accountD1 = createAccountWithDataSet("d1", typeD); - - // empty - empty - Map<AccountTypeWithDataSet, AccountType> types = - AccountTypeManagerImpl.findAllInvitableAccountTypes(c, - buildAccounts(), buildAccountTypes()); - assertEquals(0, types.size()); - try { - types.clear(); - fail("Returned Map should be unmodifiable."); - } catch (UnsupportedOperationException ok) { - } - - // No invite support, no accounts - verifyAccountTypes( - buildAccounts(), - buildAccountTypes(typeA, typeB) - /* empty */ - ); - - // No invite support, with accounts - verifyAccountTypes( - buildAccounts(accountA1), - buildAccountTypes(typeA) - /* empty */ - ); - - // With invite support, no accounts - verifyAccountTypes( - buildAccounts(), - buildAccountTypes(typeC) - /* empty */ - ); - - // With invite support, 1 account - verifyAccountTypes( - buildAccounts(accountC1), - buildAccountTypes(typeC), - typeC - ); - - // With invite support, 2 account - verifyAccountTypes( - buildAccounts(accountC1, accountC2), - buildAccountTypes(typeC), - typeC - ); - - // Combinations... - verifyAccountTypes( - buildAccounts(accountA1), - buildAccountTypes(typeA, typeC) - /* empty */ - ); - - verifyAccountTypes( - buildAccounts(accountC1, accountA1), - buildAccountTypes(typeA, typeC), - typeC - ); - - verifyAccountTypes( - buildAccounts(accountC1, accountA1), - buildAccountTypes(typeD, typeA, typeC), - typeC - ); - - verifyAccountTypes( - buildAccounts(accountC1, accountA1, accountD1), - buildAccountTypes(typeD, typeA, typeC, typeB), - typeC, typeD - ); - } - private static AccountWithDataSet createAccountWithDataSet(String name, AccountType type) { return new AccountWithDataSet(name, type.accountType, type.dataSet); } @@ -180,51 +91,6 @@ public class AccountTypeManagerTest extends AndroidTestCase { return result; } - /** - * Executes {@link AccountTypeManagerImpl#findInvitableAccountTypes} and verifies the - * result. - */ - private void verifyAccountTypes( - Collection<AccountWithDataSet> accounts, - Map<AccountTypeWithDataSet, AccountType> types, - AccountType... expectedInvitableTypes - ) { - Map<AccountTypeWithDataSet, AccountType> result = - AccountTypeManagerImpl.findAllInvitableAccountTypes(getContext(), accounts, types); - for (AccountType type : expectedInvitableTypes) { - assertTrue("Result doesn't contain type=" + type.getAccountTypeAndDataSet(), - result.containsKey(type.getAccountTypeAndDataSet())); - } - final int numExcessTypes = result.size() - expectedInvitableTypes.length; - assertEquals("Result contains " + numExcessTypes + " excess type(s)", 0, numExcessTypes); - } - - private static class MockAccountType extends AccountType { - private final String mInviteContactActivityClassName; - - public MockAccountType(String type, String dataSet, String inviteContactActivityClassName) { - accountType = type; - this.dataSet = dataSet; - mInviteContactActivityClassName = inviteContactActivityClassName; - } - - @Override - public String getInviteContactActivityClassName() { - return mInviteContactActivityClassName; - } - - @Override - public boolean isGroupMembershipEditable() { - return false; - } - - @Override - public boolean areContactsWritable() { - return false; - } - } - - public void testGetDefaultAccount_NoAccounts() { assertNull(getDefaultGoogleAccountName()); } diff --git a/tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java b/tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java index 00686aa15..a69c87741 100644 --- a/tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java +++ b/tests/src/com/android/contacts/test/mocks/MockAccountTypeManager.java @@ -76,12 +76,6 @@ public class MockAccountTypeManager extends AccountTypeManager { } @Override - public List<AccountWithDataSet> getSortedAccounts(AccountWithDataSet account, - boolean writableOnly) { - return Arrays.asList(mAccounts); - } - - @Override public List<AccountWithDataSet> getGroupWritableAccounts() { return Arrays.asList(mAccounts); } @@ -90,22 +84,4 @@ public class MockAccountTypeManager extends AccountTypeManager { public Account getDefaultGoogleAccount() { return null; } - - @Override - public Map<AccountTypeWithDataSet, AccountType> getUsableInvitableAccountTypes() { - return Maps.newHashMap(); // Always returns empty - } - - @Override - public List<AccountType> getAccountTypes(boolean writableOnly) { - final List<AccountType> ret = Lists.newArrayList(); - synchronized (this) { - for (AccountType type : mTypes) { - if (!writableOnly || type.areContactsWritable()) { - ret.add(type); - } - } - } - return ret; - } } |