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