18a574694606f0e5d781334d0d426fc379c51f3edMarc Blank/* 28a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * Copyright (C) 2011 The Android Open Source Project 38a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * 48a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * Licensed under the Apache License, Version 2.0 (the "License"); 58a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * you may not use this file except in compliance with the License. 68a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * You may obtain a copy of the License at 78a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * 88a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * http://www.apache.org/licenses/LICENSE-2.0 98a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * 108a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * Unless required by applicable law or agreed to in writing, software 118a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * distributed under the License is distributed on an "AS IS" BASIS, 128a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * See the License for the specific language governing permissions and 148a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * limitations under the License. 158a574694606f0e5d781334d0d426fc379c51f3edMarc Blank */ 168a574694606f0e5d781334d0d426fc379c51f3edMarc Blank 174e4aba9ebc43c6a83190f3a883fa05bb7d5100b3Marc Blankpackage com.android.email.provider; 188a574694606f0e5d781334d0d426fc379c51f3edMarc Blank 198a574694606f0e5d781334d0d426fc379c51f3edMarc Blankimport android.accounts.AccountManager; 208a574694606f0e5d781334d0d426fc379c51f3edMarc Blankimport android.accounts.AccountManagerFuture; 218a574694606f0e5d781334d0d426fc379c51f3edMarc Blankimport android.accounts.AuthenticatorException; 228a574694606f0e5d781334d0d426fc379c51f3edMarc Blankimport android.accounts.OperationCanceledException; 23dc7fe8964c5a8c26b60406bb682628d8a6d9183fTony Mantlerimport android.content.ComponentName; 243f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdonimport android.content.ContentResolver; 258a574694606f0e5d781334d0d426fc379c51f3edMarc Blankimport android.content.Context; 26dc7fe8964c5a8c26b60406bb682628d8a6d9183fTony Mantlerimport android.content.pm.PackageManager; 27afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Huimport android.database.Cursor; 283f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdonimport android.provider.CalendarContract; 293f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdonimport android.provider.ContactsContract; 3024bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdonimport android.text.TextUtils; 318a574694606f0e5d781334d0d426fc379c51f3edMarc Blank 32d8302b01faa8fc7f175c93e90458aa84e8a663c7Scott Kennedyimport com.android.email.NotificationController; 33afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Huimport com.android.email.R; 3424bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdonimport com.android.email.service.EmailServiceUtils; 353f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdonimport com.android.email.service.EmailServiceUtils.EmailServiceInfo; 364e4aba9ebc43c6a83190f3a883fa05bb7d5100b3Marc Blankimport com.android.emailcommon.Logging; 374e4aba9ebc43c6a83190f3a883fa05bb7d5100b3Marc Blankimport com.android.emailcommon.provider.Account; 3824bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdonimport com.android.emailcommon.provider.HostAuth; 39560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedyimport com.android.mail.utils.LogUtils; 40afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Huimport com.google.common.collect.ImmutableList; 414e4aba9ebc43c6a83190f3a883fa05bb7d5100b3Marc Blank 428a574694606f0e5d781334d0d426fc379c51f3edMarc Blankimport java.io.IOException; 43afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Huimport java.util.Arrays; 44afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Huimport java.util.Collections; 45f9d845c1b74d1e31db4796cbdb0ad05c0da0068eRégis Décampsimport java.util.LinkedHashSet; 468a574694606f0e5d781334d0d426fc379c51f3edMarc Blankimport java.util.List; 478a574694606f0e5d781334d0d426fc379c51f3edMarc Blank 488a574694606f0e5d781334d0d426fc379c51f3edMarc Blankpublic class AccountReconciler { 49afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu /** 50afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu * Get all AccountManager accounts for all email types. 51afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu * @param context Our {@link Context}. 52afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu * @return A list of all {@link android.accounts.Account}s created by our app. 53afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu */ 54afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu private static List<android.accounts.Account> getAllAmAccounts(final Context context) { 55afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu final AccountManager am = AccountManager.get(context); 56f9d845c1b74d1e31db4796cbdb0ad05c0da0068eRégis Décamps 57afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu // TODO: Consider getting the types programmatically, in case we add more types. 58f9d845c1b74d1e31db4796cbdb0ad05c0da0068eRégis Décamps // Some Accounts types can be identical, the set de-duplicates. 59f9d845c1b74d1e31db4796cbdb0ad05c0da0068eRégis Décamps final LinkedHashSet<String> accountTypes = new LinkedHashSet<String>(); 60f9d845c1b74d1e31db4796cbdb0ad05c0da0068eRégis Décamps accountTypes.add(context.getString(R.string.account_manager_type_legacy_imap)); 61f9d845c1b74d1e31db4796cbdb0ad05c0da0068eRégis Décamps accountTypes.add(context.getString(R.string.account_manager_type_pop3)); 62f9d845c1b74d1e31db4796cbdb0ad05c0da0068eRégis Décamps accountTypes.add(context.getString(R.string.account_manager_type_exchange)); 63f9d845c1b74d1e31db4796cbdb0ad05c0da0068eRégis Décamps 64f9d845c1b74d1e31db4796cbdb0ad05c0da0068eRégis Décamps final ImmutableList.Builder<android.accounts.Account> builder = ImmutableList.builder(); 65f9d845c1b74d1e31db4796cbdb0ad05c0da0068eRégis Décamps for (final String type : accountTypes) { 66f9d845c1b74d1e31db4796cbdb0ad05c0da0068eRégis Décamps final android.accounts.Account[] accounts = am.getAccountsByType(type); 67f9d845c1b74d1e31db4796cbdb0ad05c0da0068eRégis Décamps builder.add(accounts); 68f9d845c1b74d1e31db4796cbdb0ad05c0da0068eRégis Décamps } 69afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu return builder.build(); 70afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu } 71002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo 72002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo /** 73afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu * Get a all {@link Account} objects from the {@link EmailProvider}. 74afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu * @param context Our {@link Context}. 75afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu * @return A list of all {@link Account}s from the {@link EmailProvider}. 76002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo */ 77afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu private static List<Account> getAllEmailProviderAccounts(final Context context) { 78afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu final Cursor c = context.getContentResolver().query(Account.CONTENT_URI, 79afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu Account.CONTENT_PROJECTION, null, null, null); 80afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu if (c == null) { 81afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu return Collections.emptyList(); 82afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu } 83002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo 84afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu final ImmutableList.Builder<Account> builder = ImmutableList.builder(); 85afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu try { 86afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu while (c.moveToNext()) { 87afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu final Account account = new Account(); 88afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu account.restore(c); 89afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu builder.add(account); 90afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu } 91afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu } finally { 92afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu c.close(); 93afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu } 94afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu return builder.build(); 95002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo } 96f3ff0ba91076ef1fb087fc30fe65d9504011c2b3Marc Blank 978a574694606f0e5d781334d0d426fc379c51f3edMarc Blank /** 988a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * Compare our account list (obtained from EmailProvider) with the account list owned by 998a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * AccountManager. If there are any orphans (an account in one list without a corresponding 1008a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * account in the other list), delete the orphan, as these must remain in sync. 1018a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * 1028a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * Note that the duplication of account information is caused by the Email application's 1038a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * incomplete integration with AccountManager. 1048a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * 1058a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * This function may not be called from the main/UI thread, because it makes blocking calls 1068a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * into the account manager. 1078a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * 1088a574694606f0e5d781334d0d426fc379c51f3edMarc Blank * @param context The context in which to operate 1098a574694606f0e5d781334d0d426fc379c51f3edMarc Blank */ 1103f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon public static synchronized void reconcileAccounts(final Context context) { 111afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu final List<android.accounts.Account> amAccounts = getAllAmAccounts(context); 112afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu final List<Account> providerAccounts = getAllEmailProviderAccounts(context); 113afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu reconcileAccountsInternal(context, providerAccounts, amAccounts, true); 114afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu } 115afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu 116afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu /** 117afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu * Check if the AccountManager accounts list contains a specific account. 118afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu * @param accounts The list of {@link android.accounts.Account} objects. 119afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu * @param name The name of the account to find. 120afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu * @return Whether the account is in the list. 121afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu */ 122afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu private static boolean hasAmAccount(final List<android.accounts.Account> accounts, 123ed0ee50a12fdd36b813831da7a60774c3965b9c1Tony Mantler final String name, final String type) { 124afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu for (final android.accounts.Account account : accounts) { 125ed0ee50a12fdd36b813831da7a60774c3965b9c1Tony Mantler if (account.name.equalsIgnoreCase(name) && account.type.equalsIgnoreCase(type)) { 126afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu return true; 127afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu } 128afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu } 129afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu return false; 130afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu } 131afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu 132afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu /** 133afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu * Check if the EmailProvider accounts list contains a specific account. 134afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu * @param accounts The list of {@link Account} objects. 135afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu * @param name The name of the account to find. 136afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu * @return Whether the account is in the list. 137afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu */ 138afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu private static boolean hasEpAccount(final List<Account> accounts, final String name) { 139afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu for (final Account account : accounts) { 140afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu if (account.mEmailAddress.equalsIgnoreCase(name)) { 141afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu return true; 142afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu } 143afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu } 144afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu return false; 145002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo } 146002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo 147002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo /** 148002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo * Internal method to actually perform reconciliation, or simply check that it needs to be done 149002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo * and avoid doing any heavy work, depending on the value of the passed in 150002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo * {@code performReconciliation}. 151002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo */ 152002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo private static boolean reconcileAccountsInternal( 153afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu final Context context, 154afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu final List<Account> emailProviderAccounts, 155afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu final List<android.accounts.Account> accountManagerAccounts, 156afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu final boolean performReconciliation) { 157002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo boolean needsReconciling = false; 158dc7fe8964c5a8c26b60406bb682628d8a6d9183fTony Mantler int accountsDeleted = 0; 15924bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon boolean exchangeAccountDeleted = false; 16024bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon 16124bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon LogUtils.d(Logging.LOG_TAG, "reconcileAccountsInternal"); 16274dc106ae9ff3d3a92425b68ea28ee2a0b258e57Martin Hibdon // See if we should have the Eas authenticators enabled. 163002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo 16474dc106ae9ff3d3a92425b68ea28ee2a0b258e57Martin Hibdon if (!EmailServiceUtils.isServiceAvailable(context, 16574dc106ae9ff3d3a92425b68ea28ee2a0b258e57Martin Hibdon context.getString(R.string.protocol_eas))) { 166ebe49cfeaf0328aa95f5cb82b731f08d7bae7b09Anthony Lee EmailServiceUtils.disableExchangeComponents(context); 16774dc106ae9ff3d3a92425b68ea28ee2a0b258e57Martin Hibdon } else { 168ebe49cfeaf0328aa95f5cb82b731f08d7bae7b09Anthony Lee EmailServiceUtils.enableExchangeComponent(context); 16974dc106ae9ff3d3a92425b68ea28ee2a0b258e57Martin Hibdon } 1708a574694606f0e5d781334d0d426fc379c51f3edMarc Blank // First, look through our EmailProvider accounts to make sure there's a corresponding 1718a574694606f0e5d781334d0d426fc379c51f3edMarc Blank // AccountManager account 172afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu for (final Account providerAccount : emailProviderAccounts) { 173afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu final String providerAccountName = providerAccount.mEmailAddress; 1743e8e59798b718e034da8c250e706e6429c41c2a5Alon Albert final EmailServiceUtils.EmailServiceInfo infoForAccount = EmailServiceUtils 1753e8e59798b718e034da8c250e706e6429c41c2a5Alon Albert .getServiceInfoForAccount(context, providerAccount.mId); 1763e8e59798b718e034da8c250e706e6429c41c2a5Alon Albert 1773e8e59798b718e034da8c250e706e6429c41c2a5Alon Albert // We want to delete the account if there is no matching Account Manager account for it 1783e8e59798b718e034da8c250e706e6429c41c2a5Alon Albert // unless it is flagged as incomplete. We also want to delete it if we can't find 1793e8e59798b718e034da8c250e706e6429c41c2a5Alon Albert // an accountInfo object for it. 1803e8e59798b718e034da8c250e706e6429c41c2a5Alon Albert if (infoForAccount == null || !hasAmAccount( 1813e8e59798b718e034da8c250e706e6429c41c2a5Alon Albert accountManagerAccounts, providerAccountName, infoForAccount.accountType)) { 1823e8e59798b718e034da8c250e706e6429c41c2a5Alon Albert if (infoForAccount != null && 1833e8e59798b718e034da8c250e706e6429c41c2a5Alon Albert (providerAccount.mFlags & Account.FLAGS_INCOMPLETE) != 0) { 1844265ade29a684543ac5b048dda90c4733c58568aTony Mantler LogUtils.w(Logging.LOG_TAG, 1854265ade29a684543ac5b048dda90c4733c58568aTony Mantler "Account reconciler noticed incomplete account; ignoring"); 1864265ade29a684543ac5b048dda90c4733c58568aTony Mantler continue; 1878a574694606f0e5d781334d0d426fc379c51f3edMarc Blank } 188002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo 189002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo needsReconciling = true; 190002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo if (performReconciliation) { 191002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo // This account has been deleted in the AccountManager! 192560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.d(Logging.LOG_TAG, 193002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo "Account deleted in AccountManager; deleting from provider: " + 194002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo providerAccountName); 19524bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon // See if this is an exchange account 19624bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon final HostAuth auth = providerAccount.getOrCreateHostAuthRecv(context); 19724bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon LogUtils.d(Logging.LOG_TAG, "deleted account with hostAuth " + auth); 19824bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon if (auth != null && TextUtils.equals(auth.mProtocol, 19924bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon context.getString(R.string.protocol_eas))) { 20024bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon exchangeAccountDeleted = true; 20124bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon } 202ac1d3249fbb50714ad1bee5aec41968574befd90Tony Mantler // Cancel all notifications for this account 203ac1d3249fbb50714ad1bee5aec41968574befd90Tony Mantler NotificationController.cancelNotifications(context, providerAccount); 204ac1d3249fbb50714ad1bee5aec41968574befd90Tony Mantler 205afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu context.getContentResolver().delete( 206afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu EmailProvider.uiUri("uiaccount", providerAccount.mId), null, null); 207d8302b01faa8fc7f175c93e90458aa84e8a663c7Scott Kennedy 208dc7fe8964c5a8c26b60406bb682628d8a6d9183fTony Mantler accountsDeleted++; 20924bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon 210002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo } 2118a574694606f0e5d781334d0d426fc379c51f3edMarc Blank } 2128a574694606f0e5d781334d0d426fc379c51f3edMarc Blank } 2138a574694606f0e5d781334d0d426fc379c51f3edMarc Blank // Now, look through AccountManager accounts to make sure we have a corresponding cached EAS 2148a574694606f0e5d781334d0d426fc379c51f3edMarc Blank // account from EmailProvider 215afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu for (final android.accounts.Account accountManagerAccount : accountManagerAccounts) { 216afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu final String accountManagerAccountName = accountManagerAccount.name; 217afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu if (!hasEpAccount(emailProviderAccounts, accountManagerAccountName)) { 2188a574694606f0e5d781334d0d426fc379c51f3edMarc Blank // This account has been deleted from the EmailProvider database 219002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo needsReconciling = true; 220002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo 221002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo if (performReconciliation) { 222560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.d(Logging.LOG_TAG, 223002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo "Account deleted from provider; deleting from AccountManager: " + 224002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo accountManagerAccountName); 225002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo // Delete the account 226002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo AccountManagerFuture<Boolean> blockingResult = AccountManager.get(context) 227afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu .removeAccount(accountManagerAccount, null, null); 228002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo try { 229002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo // Note: All of the potential errors from removeAccount() are simply logged 230002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo // here, as there is nothing to actually do about them. 231002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo blockingResult.getResult(); 232002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo } catch (OperationCanceledException e) { 233560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(Logging.LOG_TAG, e.toString()); 234002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo } catch (AuthenticatorException e) { 235560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(Logging.LOG_TAG, e.toString()); 236002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo } catch (IOException e) { 237560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(Logging.LOG_TAG, e.toString()); 238002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo } 2398a574694606f0e5d781334d0d426fc379c51f3edMarc Blank } 2403f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon } else { 2413f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon // Fix up the Calendar and Contacts syncing. It used to be possible for IMAP and 2423f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon // POP accounts to get calendar and contacts syncing enabled. 2433f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon // See b/11818312 2443f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon final String accountType = accountManagerAccount.type; 2453f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon final String protocol = EmailServiceUtils.getProtocolFromAccountType( 2463f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon context, accountType); 2473f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon final EmailServiceInfo info = EmailServiceUtils.getServiceInfo(context, protocol); 2483f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon if (!info.syncCalendar) { 2493f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon ContentResolver.setIsSyncable(accountManagerAccount, 2503f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon CalendarContract.AUTHORITY, 0); 2513f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon } 2523f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon if (!info.syncContacts) { 2533f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon ContentResolver.setIsSyncable(accountManagerAccount, 2543f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon ContactsContract.AUTHORITY, 0); 2553f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon } 2568a574694606f0e5d781334d0d426fc379c51f3edMarc Blank } 2578a574694606f0e5d781334d0d426fc379c51f3edMarc Blank } 258002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo 259e817be135332c4060b5985ff830e3ce555043a43Paul Westbrook final String composeActivityName = 260e817be135332c4060b5985ff830e3ce555043a43Paul Westbrook context.getString(R.string.reconciliation_compose_activity_name); 261e817be135332c4060b5985ff830e3ce555043a43Paul Westbrook if (!TextUtils.isEmpty(composeActivityName)) { 262e817be135332c4060b5985ff830e3ce555043a43Paul Westbrook // If there are no accounts remaining after reconciliation, disable the compose activity 263e817be135332c4060b5985ff830e3ce555043a43Paul Westbrook final boolean enableCompose = emailProviderAccounts.size() - accountsDeleted > 0; 264e817be135332c4060b5985ff830e3ce555043a43Paul Westbrook final ComponentName componentName = new ComponentName(context, composeActivityName); 265e817be135332c4060b5985ff830e3ce555043a43Paul Westbrook context.getPackageManager().setComponentEnabledSetting(componentName, 266e817be135332c4060b5985ff830e3ce555043a43Paul Westbrook enableCompose ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 267e817be135332c4060b5985ff830e3ce555043a43Paul Westbrook PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 268e817be135332c4060b5985ff830e3ce555043a43Paul Westbrook PackageManager.DONT_KILL_APP); 269e817be135332c4060b5985ff830e3ce555043a43Paul Westbrook LogUtils.d(LogUtils.TAG, "Setting compose activity to " 270e817be135332c4060b5985ff830e3ce555043a43Paul Westbrook + (enableCompose ? "enabled" : "disabled")); 271e817be135332c4060b5985ff830e3ce555043a43Paul Westbrook } 272e817be135332c4060b5985ff830e3ce555043a43Paul Westbrook 273dc7fe8964c5a8c26b60406bb682628d8a6d9183fTony Mantler 27424bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon // If an account has been deleted, the simplest thing is just to kill our process. 27524bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon // Otherwise we might have a service running trying to do something for the account 27624bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon // which has been deleted, which can get NPEs. It's not as clean is it could be, but 27724bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon // it still works pretty well because there is nowhere in the email app to delete the 27824bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon // account. You have to go to Settings, so it's not user visible that the Email app 27924bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon // has been killed. 280dc7fe8964c5a8c26b60406bb682628d8a6d9183fTony Mantler if (accountsDeleted > 0) { 28124bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon LogUtils.i(Logging.LOG_TAG, "Restarting because account deleted"); 28224bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon if (exchangeAccountDeleted) { 28324bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon EmailServiceUtils.killService(context, context.getString(R.string.protocol_eas)); 28424bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon } 28524bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon System.exit(-1); 28624bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon } 28724bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon 288002a1802cad235ffa8f7152e0d0a5a2ebad14f63Ben Komalo return needsReconciling; 2898a574694606f0e5d781334d0d426fc379c51f3edMarc Blank } 2908a574694606f0e5d781334d0d426fc379c51f3edMarc Blank} 291