/** * Requests the singleton instance of {@link AccountTypeManager} with data bound from * the available authenticators. This method can safely be called from the UI thread. */ public static AccountTypeManager getInstance(Context context) { synchronized (mInitializationLock) { if (mAccountTypeManager == null) { context = context.getApplicationContext(); mAccountTypeManager = new AccountTypeManagerImpl(context); } } return mAccountTypeManager; }
/** * Return list of all known, contact writable {@link AccountWithDataSet}'s. */ @Override public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly) { ensureAccountsLoaded(); return contactWritableOnly ? mContactWritableAccounts : mAccounts; }
@Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_LOAD_DATA: loadAccountsInBackground(); break; case MESSAGE_PROCESS_BROADCAST_INTENT: processBroadcastIntent((Intent) msg.obj); break; } } };
final AuthenticatorDescription auth = findAuthenticator(auths, type); if (auth == null) { Log.w(TAG, "No authenticator found for type=" + type + ", ignoring it."); accountType.iconRes = auth.iconId; addAccountType(accountType, accountTypesByTypeAndDataSet, accountTypesByType); + ", packageName=" + extensionPackage); addAccountType(accountType, accountTypesByTypeAndDataSet, accountTypesByType); mContactWritableAccounts = contactWritableAccounts; mGroupWritableAccounts = groupWritableAccounts; mInvitableAccountTypes = findAllInvitableAccountTypes( mContext, allAccounts, accountTypesByTypeAndDataSet);
@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(); }
public void onAccountsUpdated(Account[] accounts) { // Refresh to catch any changed accounts loadAccountsInBackground(); }
Map<AccountTypeWithDataSet, AccountType> allInvitables = getAllInvitableAccountTypes(); if (allInvitables.isEmpty()) { return EMPTY_UNMODIFIABLE_ACCOUNT_TYPE_MAP;
/** * Return the list of all known, group writable {@link AccountWithDataSet}'s. */ public List<AccountWithDataSet> getGroupWritableAccounts() { ensureAccountsLoaded(); return mGroupWritableAccounts; }
/** * @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; }
/** * Return {@link AccountType} for the given account type and data set. */ @Override public AccountType getAccountType(AccountTypeWithDataSet accountTypeWithDataSet) { ensureAccountsLoaded(); synchronized (this) { AccountType type = mAccountTypesWithDataSets.get(accountTypeWithDataSet); return type != null ? type : mFallbackAccountType; } }
@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; }
/** * 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}. */ @Override public DataKind getKindOrFallback(AccountType type, String mimeType) { ensureAccountsLoaded(); DataKind kind = null; // Try finding account type and kind matching request if (type != null) { kind = type.getKindForMimetype(mimeType); } if (kind == null) { // Nothing found, so try fallback as last resort kind = mFallbackAccountType.getKindForMimetype(mimeType); } if (kind == null) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Unknown type=" + type + ", mime=" + mimeType); } } return kind; }