diff options
Diffstat (limited to 'src/com/android/email/provider/AccountReconciler.java')
-rw-r--r-- | src/com/android/email/provider/AccountReconciler.java | 306 |
1 files changed, 0 insertions, 306 deletions
diff --git a/src/com/android/email/provider/AccountReconciler.java b/src/com/android/email/provider/AccountReconciler.java deleted file mode 100644 index 251c59a37..000000000 --- a/src/com/android/email/provider/AccountReconciler.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (C) 2011 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.email.provider; - -import android.accounts.AccountManager; -import android.accounts.AccountManagerFuture; -import android.accounts.AuthenticatorException; -import android.accounts.OperationCanceledException; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.pm.PackageManager; -import android.database.Cursor; -import android.provider.CalendarContract; -import android.provider.ContactsContract; -import android.text.TextUtils; - -import com.android.email.NotificationController; -import com.android.email.R; -import com.android.email.SecurityPolicy; -import com.android.email.service.EmailServiceUtils; -import com.android.email.service.EmailServiceUtils.EmailServiceInfo; -import com.android.emailcommon.Logging; -import com.android.emailcommon.provider.Account; -import com.android.emailcommon.provider.HostAuth; -import com.android.emailcommon.utility.MigrationUtils; -import com.android.mail.utils.LogUtils; -import com.google.common.collect.ImmutableList; - -import java.io.IOException; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.List; - -public class AccountReconciler { - /** - * Get all AccountManager accounts for all email types. - * @param context Our {@link Context}. - * @return A list of all {@link android.accounts.Account}s created by our app. - */ - private static List<android.accounts.Account> getAllAmAccounts(final Context context) { - final AccountManager am = AccountManager.get(context); - - // TODO: Consider getting the types programmatically, in case we add more types. - // Some Accounts types can be identical, the set de-duplicates. - final LinkedHashSet<String> accountTypes = new LinkedHashSet<String>(); - accountTypes.add(context.getString(R.string.account_manager_type_legacy_imap)); - accountTypes.add(context.getString(R.string.account_manager_type_pop3)); - accountTypes.add(context.getString(R.string.account_manager_type_exchange)); - - final ImmutableList.Builder<android.accounts.Account> builder = ImmutableList.builder(); - for (final String type : accountTypes) { - final android.accounts.Account[] accounts = am.getAccountsByType(type); - builder.add(accounts); - } - return builder.build(); - } - - /** - * Get a all {@link Account} objects from the {@link EmailProvider}. - * @param context Our {@link Context}. - * @return A list of all {@link Account}s from the {@link EmailProvider}. - */ - private static List<Account> getAllEmailProviderAccounts(final Context context) { - final Cursor c = context.getContentResolver().query(Account.CONTENT_URI, - Account.CONTENT_PROJECTION, null, null, null); - if (c == null) { - return Collections.emptyList(); - } - - final ImmutableList.Builder<Account> builder = ImmutableList.builder(); - try { - while (c.moveToNext()) { - final Account account = new Account(); - account.restore(c); - builder.add(account); - } - } finally { - c.close(); - } - return builder.build(); - } - - /** - * Compare our account list (obtained from EmailProvider) with the account list owned by - * AccountManager. If there are any orphans (an account in one list without a corresponding - * account in the other list), delete the orphan, as these must remain in sync. - * - * Note that the duplication of account information is caused by the Email application's - * incomplete integration with AccountManager. - * - * This function may not be called from the main/UI thread, because it makes blocking calls - * into the account manager. - * - * @param context The context in which to operate - */ - public static synchronized void reconcileAccounts(final Context context) { - final List<android.accounts.Account> amAccounts = getAllAmAccounts(context); - final List<Account> providerAccounts = getAllEmailProviderAccounts(context); - reconcileAccountsInternal(context, providerAccounts, amAccounts, true); - } - - /** - * Check if the AccountManager accounts list contains a specific account. - * @param accounts The list of {@link android.accounts.Account} objects. - * @param name The name of the account to find. - * @return Whether the account is in the list. - */ - private static boolean hasAmAccount(final List<android.accounts.Account> accounts, - final String name, final String type) { - for (final android.accounts.Account account : accounts) { - if (account.name.equalsIgnoreCase(name) && account.type.equalsIgnoreCase(type)) { - return true; - } - } - return false; - } - - /** - * Check if the EmailProvider accounts list contains a specific account. - * @param accounts The list of {@link Account} objects. - * @param name The name of the account to find. - * @return Whether the account is in the list. - */ - private static boolean hasEpAccount(final List<Account> accounts, final String name) { - for (final Account account : accounts) { - if (account.mEmailAddress.equalsIgnoreCase(name)) { - return true; - } - } - return false; - } - - /** - * Internal method to actually perform reconciliation, or simply check that it needs to be done - * and avoid doing any heavy work, depending on the value of the passed in - * {@code performReconciliation}. - */ - private static boolean reconcileAccountsInternal( - final Context context, - final List<Account> emailProviderAccounts, - final List<android.accounts.Account> accountManagerAccounts, - final boolean performReconciliation) { - boolean needsReconciling = false; - int accountsDeleted = 0; - boolean exchangeAccountDeleted = false; - - LogUtils.d(Logging.LOG_TAG, "reconcileAccountsInternal"); - - if (MigrationUtils.migrationInProgress()) { - LogUtils.d(Logging.LOG_TAG, "deferring reconciliation, migration in progress"); - return false; - } - - // See if we should have the Eas authenticators enabled. - if (!EmailServiceUtils.isServiceAvailable(context, - context.getString(R.string.protocol_eas))) { - EmailServiceUtils.disableExchangeComponents(context); - } else { - EmailServiceUtils.enableExchangeComponent(context); - } - // First, look through our EmailProvider accounts to make sure there's a corresponding - // AccountManager account - for (final Account providerAccount : emailProviderAccounts) { - final String providerAccountName = providerAccount.mEmailAddress; - final EmailServiceUtils.EmailServiceInfo infoForAccount = EmailServiceUtils - .getServiceInfoForAccount(context, providerAccount.mId); - - // We want to delete the account if there is no matching Account Manager account for it - // unless it is flagged as incomplete. We also want to delete it if we can't find - // an accountInfo object for it. - if (infoForAccount == null || !hasAmAccount( - accountManagerAccounts, providerAccountName, infoForAccount.accountType)) { - if (infoForAccount != null && - (providerAccount.mFlags & Account.FLAGS_INCOMPLETE) != 0) { - LogUtils.w(Logging.LOG_TAG, - "Account reconciler noticed incomplete account; ignoring"); - continue; - } - - needsReconciling = true; - if (performReconciliation) { - // This account has been deleted in the AccountManager! - LogUtils.d(Logging.LOG_TAG, - "Account deleted in AccountManager; deleting from provider: " + - providerAccountName); - // See if this is an exchange account - final HostAuth auth = providerAccount.getOrCreateHostAuthRecv(context); - LogUtils.d(Logging.LOG_TAG, "deleted account with hostAuth " + auth); - if (auth != null && TextUtils.equals(auth.mProtocol, - context.getString(R.string.protocol_eas))) { - exchangeAccountDeleted = true; - } - // Cancel all notifications for this account - NotificationController.cancelNotifications(context, providerAccount); - - context.getContentResolver().delete( - EmailProvider.uiUri("uiaccount", providerAccount.mId), null, null); - - accountsDeleted++; - - } - } - } - // Now, look through AccountManager accounts to make sure we have a corresponding cached EAS - // account from EmailProvider - boolean needsPolicyUpdate = false; - for (final android.accounts.Account accountManagerAccount : accountManagerAccounts) { - final String accountManagerAccountName = accountManagerAccount.name; - if (!hasEpAccount(emailProviderAccounts, accountManagerAccountName)) { - // This account has been deleted from the EmailProvider database - needsReconciling = true; - - if (performReconciliation) { - LogUtils.d(Logging.LOG_TAG, - "Account deleted from provider; deleting from AccountManager: " + - accountManagerAccountName); - // Delete the account - AccountManagerFuture<Boolean> blockingResult = AccountManager.get(context) - .removeAccount(accountManagerAccount, null, null); - try { - // Note: All of the potential errors from removeAccount() are simply logged - // here, as there is nothing to actually do about them. - blockingResult.getResult(); - } catch (OperationCanceledException e) { - LogUtils.w(Logging.LOG_TAG, e.toString()); - } catch (AuthenticatorException e) { - LogUtils.w(Logging.LOG_TAG, e.toString()); - } catch (IOException e) { - LogUtils.w(Logging.LOG_TAG, e.toString()); - } - // Just set a flag that our policies need to be updated with device - // So we can do the update, one time, at a later point in time. - needsPolicyUpdate = true; - } - } else { - // Fix up the Calendar and Contacts syncing. It used to be possible for IMAP and - // POP accounts to get calendar and contacts syncing enabled. - // See b/11818312 - final String accountType = accountManagerAccount.type; - final String protocol = EmailServiceUtils.getProtocolFromAccountType( - context, accountType); - final EmailServiceInfo info = EmailServiceUtils.getServiceInfo(context, protocol); - if (info == null || !info.syncCalendar) { - ContentResolver.setIsSyncable(accountManagerAccount, - CalendarContract.AUTHORITY, 0); - } - if (info == null || !info.syncContacts) { - ContentResolver.setIsSyncable(accountManagerAccount, - ContactsContract.AUTHORITY, 0); - } - } - } - - if (needsPolicyUpdate) { - // We have removed accounts from the AccountManager, let's make sure that - // our policies are up to date. - SecurityPolicy.getInstance(context).policiesUpdated(); - } - - final String composeActivityName = - context.getString(R.string.reconciliation_compose_activity_name); - if (!TextUtils.isEmpty(composeActivityName)) { - // If there are no accounts remaining after reconciliation, disable the compose activity - final boolean enableCompose = emailProviderAccounts.size() - accountsDeleted > 0; - final ComponentName componentName = new ComponentName(context, composeActivityName); - context.getPackageManager().setComponentEnabledSetting(componentName, - enableCompose ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : - PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP); - LogUtils.d(LogUtils.TAG, "Setting compose activity to " - + (enableCompose ? "enabled" : "disabled")); - } - - - // If an account has been deleted, the simplest thing is just to kill our process. - // Otherwise we might have a service running trying to do something for the account - // which has been deleted, which can get NPEs. It's not as clean is it could be, but - // it still works pretty well because there is nowhere in the email app to delete the - // account. You have to go to Settings, so it's not user visible that the Email app - // has been killed. - if (accountsDeleted > 0) { - LogUtils.i(Logging.LOG_TAG, "Restarting because account deleted"); - if (exchangeAccountDeleted) { - EmailServiceUtils.killService(context, context.getString(R.string.protocol_eas)); - } - System.exit(-1); - } - - return needsReconciling; - } -} |