EmailSyncAdapterService.java revision 97a217631c5540bb7c40b3d184483cc35fe8d762
12674530d1879be7ae2df5105f07a93a5557ec389Marc Blank/*
22674530d1879be7ae2df5105f07a93a5557ec389Marc Blank * Copyright (C) 2010 The Android Open Source Project
32674530d1879be7ae2df5105f07a93a5557ec389Marc Blank *
42674530d1879be7ae2df5105f07a93a5557ec389Marc Blank * Licensed under the Apache License, Version 2.0 (the "License");
52674530d1879be7ae2df5105f07a93a5557ec389Marc Blank * you may not use this file except in compliance with the License.
62674530d1879be7ae2df5105f07a93a5557ec389Marc Blank * You may obtain a copy of the License at
72674530d1879be7ae2df5105f07a93a5557ec389Marc Blank *
82674530d1879be7ae2df5105f07a93a5557ec389Marc Blank *      http://www.apache.org/licenses/LICENSE-2.0
92674530d1879be7ae2df5105f07a93a5557ec389Marc Blank *
102674530d1879be7ae2df5105f07a93a5557ec389Marc Blank * Unless required by applicable law or agreed to in writing, software
112674530d1879be7ae2df5105f07a93a5557ec389Marc Blank * distributed under the License is distributed on an "AS IS" BASIS,
122674530d1879be7ae2df5105f07a93a5557ec389Marc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132674530d1879be7ae2df5105f07a93a5557ec389Marc Blank * See the License for the specific language governing permissions and
142674530d1879be7ae2df5105f07a93a5557ec389Marc Blank * limitations under the License.
152674530d1879be7ae2df5105f07a93a5557ec389Marc Blank */
162674530d1879be7ae2df5105f07a93a5557ec389Marc Blank
17bbafcf7dbcb92063aa207113451c1d29235bc5ddMarc Blankpackage com.android.exchange.service;
182674530d1879be7ae2df5105f07a93a5557ec389Marc Blank
19502ae63959c6a6253d05de8716417deef497392cMartin Hibdonimport android.app.AlarmManager;
20185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albertimport android.app.Notification;
21185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albertimport android.app.Notification.Builder;
22185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albertimport android.app.NotificationManager;
23185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albertimport android.app.PendingIntent;
24ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.AbstractThreadedSyncAdapter;
25dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Huimport android.content.ComponentName;
26ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.ContentProviderClient;
27ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.ContentResolver;
28e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Huimport android.content.ContentValues;
29ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.Context;
30ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.Intent;
31dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Huimport android.content.ServiceConnection;
32ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.SyncResult;
33ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.database.Cursor;
34185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albertimport android.net.Uri;
35ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Huimport android.os.AsyncTask;
36ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.os.Bundle;
37ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.os.IBinder;
38dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Huimport android.os.RemoteException;
39502ae63959c6a6253d05de8716417deef497392cMartin Hibdonimport android.os.SystemClock;
406285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Huimport android.provider.CalendarContract;
416285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Huimport android.provider.ContactsContract;
42be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdonimport android.text.TextUtils;
436285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Huimport android.text.format.DateUtils;
443eef378426c7c88608f53f5a268baed40259ccf6Alon Albertimport android.util.Log;
45ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
46bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Huimport com.android.emailcommon.TempDirectory;
47c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.provider.Account;
48bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Huimport com.android.emailcommon.provider.EmailContent;
49c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.provider.EmailContent.AccountColumns;
5061cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdonimport com.android.emailcommon.provider.EmailContent.Message;
5161cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdonimport com.android.emailcommon.provider.EmailContent.MessageColumns;
5261cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdonimport com.android.emailcommon.provider.EmailContent.SyncColumns;
535f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport com.android.emailcommon.provider.HostAuth;
544d8774462ace9a45154b2df418b9f2fe7a9c685dBen Komaloimport com.android.emailcommon.provider.Mailbox;
55fa84f281d166cd7d43ca88adf89751ea9acfc51cAlon Albertimport com.android.emailcommon.service.EmailServiceStatus;
565f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport com.android.emailcommon.service.IEmailService;
575f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport com.android.emailcommon.service.IEmailServiceCallback;
585f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport com.android.emailcommon.service.SearchParams;
59be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdonimport com.android.emailcommon.service.ServiceProxy;
60185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albertimport com.android.emailcommon.utility.IntentUtilities;
61bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Huimport com.android.emailcommon.utility.Utility;
625f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport com.android.exchange.Eas;
63185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albertimport com.android.exchange.R.drawable;
64185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albertimport com.android.exchange.R.string;
65ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Huimport com.android.exchange.adapter.PingParser;
66328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Huimport com.android.exchange.eas.EasFolderSync;
67b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport com.android.exchange.eas.EasLoadAttachment;
686f0cf29be849d3a95a9168cb6fa09de12635e818Yu Ping Huimport com.android.exchange.eas.EasMoveItems;
69ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.exchange.eas.EasOperation;
7061cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdonimport com.android.exchange.eas.EasOutboxSync;
71ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.exchange.eas.EasPing;
720756a9ff8e69b8cc52374fa68efb2e81971ee5c4Martin Hibdonimport com.android.exchange.eas.EasSearch;
73c640541ba09b4ecd88f4fa9603dc2d9d474e7996Yu Ping Huimport com.android.exchange.eas.EasSync;
7497a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Huimport com.android.exchange.eas.EasSyncBase;
75fa84f281d166cd7d43ca88adf89751ea9acfc51cAlon Albertimport com.android.mail.providers.UIProvider;
76942b7d73f2f5b3d6c651e39463e615fe6902a910Scott Kennedyimport com.android.mail.utils.LogUtils;
775f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
785f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport java.util.HashMap;
796285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Huimport java.util.HashSet;
802674530d1879be7ae2df5105f07a93a5557ec389Marc Blank
812177272932413dd434ed1a393b22f452dc38740aYu Ping Hu/**
822177272932413dd434ed1a393b22f452dc38740aYu Ping Hu * Service for communicating with Exchange servers. There are three main parts of this class:
832177272932413dd434ed1a393b22f452dc38740aYu Ping Hu * TODO: Flesh out these comments.
842177272932413dd434ed1a393b22f452dc38740aYu Ping Hu * 1) An {@link AbstractThreadedSyncAdapter} to handle actually performing syncs.
852177272932413dd434ed1a393b22f452dc38740aYu Ping Hu * 2) Bookkeeping for running Ping requests, which handles push notifications.
862177272932413dd434ed1a393b22f452dc38740aYu Ping Hu * 3) An {@link IEmailService} Stub to handle RPC from the UI.
872177272932413dd434ed1a393b22f452dc38740aYu Ping Hu */
88bbafcf7dbcb92063aa207113451c1d29235bc5ddMarc Blankpublic class EmailSyncAdapterService extends AbstractSyncAdapterService {
895f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
90110837ebff288a75f9bda067c38e2c46797d99b5Alon Albert    private static final String TAG = Eas.LOG_TAG;
915f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
92dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu    /**
93dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu     * Temporary while converting to EasService. Do not check in set to true.
94dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu     * When true, delegates various operations to {@link EasService}, for use while developing the
95dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu     * new service.
96dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu     * The two following fields are used to support what happens when this is true.
97dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu     */
98dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu    private static final boolean DELEGATE_TO_EAS_SERVICE = false;
99dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu    private IEmailService mEasService;
100dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu    private ServiceConnection mConnection;
101dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu
102502ae63959c6a6253d05de8716417deef497392cMartin Hibdon    private static final String EXTRA_START_PING = "START_PING";
103db1ca5f71ea90df7179b981c71f3ec757207b92eYu Ping Hu    private static final String EXTRA_PING_ACCOUNT = "PING_ACCOUNT";
104502ae63959c6a6253d05de8716417deef497392cMartin Hibdon    private static final long SYNC_ERROR_BACKOFF_MILLIS = 5 * DateUtils.MINUTE_IN_MILLIS;
105502ae63959c6a6253d05de8716417deef497392cMartin Hibdon
1065f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    /**
1076285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu     * The amount of time between periodic syncs intended to ensure that push hasn't died.
1086285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu     */
1096285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu    private static final long KICK_SYNC_INTERVAL =
1106285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            DateUtils.HOUR_IN_MILLIS / DateUtils.SECOND_IN_MILLIS;
1116285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu
1120b1a8c91bd3abe4390a7bec47600f96e441185f0Yu Ping Hu    /** Controls whether we do a periodic "kick" to restart the ping. */
1132d926648d59ef70d04d832a1ef2d023ff45dfd72Yu Ping Hu    private static final boolean SCHEDULE_KICK = true;
1140b1a8c91bd3abe4390a7bec47600f96e441185f0Yu Ping Hu
115ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu    /** Projection used for getting email address for an account. */
116ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu    private static final String[] ACCOUNT_EMAIL_PROJECTION = { AccountColumns.EMAIL_ADDRESS };
117ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu
11824e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu    private static final Object sSyncAdapterLock = new Object();
11924e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu    private static AbstractThreadedSyncAdapter sSyncAdapter = null;
12024e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu
12161cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon    // Value for a message's server id when sending fails.
12261cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon    public static final int SEND_FAILED = 1;
12361cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon    public static final String MAILBOX_KEY_AND_NOT_SEND_FAILED =
12461cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon            MessageColumns.MAILBOX_KEY + "=? and (" + SyncColumns.SERVER_ID + " is null or " +
12561cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon            SyncColumns.SERVER_ID + "!=" + SEND_FAILED + ')';
12661cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon
127456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu    /**
1285f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * Bookkeeping for handling synchronization between pings and syncs.
1295f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * "Ping" refers to a hanging POST or GET that is used to receive push notifications. Ping is
1305f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * the term for the Exchange command, but this code should be generic enough to be easily
1315f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * extended to IMAP.
1325f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * "Sync" refers to an actual sync command to either fetch mail state, account state, or send
1335f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * mail (send is implemented as "sync the outbox").
1345f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * TODO: Outbox sync probably need not stop a ping in progress.
1355f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * Basic rules of how these interact (note that all rules are per account):
1365f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - Only one ping or sync may run at a time.
1375f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - Due to how {@link AbstractThreadedSyncAdapter} works, sync requests will not occur while
1385f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     *   a sync is in progress.
1395f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - On the other hand, ping requests may come in while handling a ping.
1405f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - "Ping request" is shorthand for "a request to change our ping parameters", which includes
1415f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     *   a request to stop receiving push notifications.
1425f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - If neither a ping nor a sync is running, then a request for either will run it.
1435f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - If a sync is running, new ping requests block until the sync completes.
1445f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - If a ping is running, a new sync request stops the ping and creates a pending ping
1455f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     *   (which blocks until the sync completes).
1465f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - If a ping is running, a new ping request stops the ping and either starts a new one or
1475f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     *   does nothing, as appopriate (since a ping request can be to stop pushing).
1485f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - As an optimization, while a ping request is waiting to run, subsequent ping requests are
1495f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     *   ignored (the pending ping will pick up the latest ping parameters at the time it runs).
1505f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     */
151400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu    public class SyncHandlerSynchronizer {
1525f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        /**
1535f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * Map of account id -> ping handler.
1545f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * For a given account id, there are three possible states:
1555f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * 1) If no ping or sync is currently running, there is no entry in the map for the account.
1565f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * 2) If a ping is running, there is an entry with the appropriate ping handler.
1575f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * 3) If there is a sync running, there is an entry with null as the value.
1585f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * We cannot have more than one ping or sync running at a time.
1595f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         */
160ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        private final HashMap<Long, PingTask> mPingHandlers = new HashMap<Long, PingTask>();
1615f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
1625f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        /**
1635f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * Wait until neither a sync nor a ping is running on this account, and then return.
1645f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * If there's a ping running, actively stop it. (For syncs, we have to just wait.)
1655f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * @param accountId The account we want to wait for.
1665f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         */
1675f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        private synchronized void waitUntilNoActivity(final long accountId) {
1685f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            while (mPingHandlers.containsKey(accountId)) {
169ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                final PingTask pingHandler = mPingHandlers.get(accountId);
1705f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                if (pingHandler != null) {
171ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    pingHandler.stop();
1725f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                }
1735f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                try {
1745f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                    wait();
175ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                } catch (final InterruptedException e) {
1765f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                    // TODO: When would this happen, and how should I handle it?
1775f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                }
1785f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            }
1795f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
1805f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
1815f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        /**
1825f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * Use this to see if we're currently syncing, as opposed to pinging or doing nothing.
1835f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * @param accountId The account to check.
1845f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * @return Whether that account is currently running a sync.
1855f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         */
1865f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        private synchronized boolean isRunningSync(final long accountId) {
1875f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            return (mPingHandlers.containsKey(accountId) && mPingHandlers.get(accountId) == null);
1885f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
1895f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
190ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        /**
191ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * If there are no running pings, stop the service.
192ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         */
193400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu        private void stopServiceIfNoPings() {
194ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            for (final PingTask pingHandler : mPingHandlers.values()) {
195400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu                if (pingHandler != null) {
196400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu                    return;
197400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu                }
198400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu            }
199400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu            EmailSyncAdapterService.this.stopSelf();
200400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu        }
201400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu
2025f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        /**
203ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * Called prior to starting a sync to update our bookkeeping. We don't actually run the sync
204ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * here; the caller must do that.
2055f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * @param accountId The account on which we are running a sync.
2065f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         */
2075f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public synchronized void startSync(final long accountId) {
2085f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            waitUntilNoActivity(accountId);
2095f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            mPingHandlers.put(accountId, null);
2105f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
2115f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
2125f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        /**
213ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * Starts or restarts a ping for an account, if the current account state indicates that it
214ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * wants to push.
215ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * @param account The account whose ping is being modified.
2165f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         */
217502ae63959c6a6253d05de8716417deef497392cMartin Hibdon        public synchronized void modifyPing(final boolean lastSyncHadError,
218502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                final Account account) {
219ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // If a sync is currently running, it will start a ping when it's done, so there's no
220ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // need to do anything right now.
221ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            if (isRunningSync(account.mId)) {
2225f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                return;
2235f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            }
2245f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
225d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu            // Don't ping if we're on security hold.
226d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu            if ((account.mFlags & Account.FLAGS_SECURITY_HOLD) != 0) {
227d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                return;
228d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu            }
229d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu
2306285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            // Don't ping for accounts that haven't performed initial sync.
2316285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            if (EmailContent.isInitialSyncKey(account.mSyncKey)) {
2325f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                return;
2335f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            }
2345f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
2356285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            // Determine if this account needs pushes. All of the following must be true:
2366285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            // - The account's sync interval must indicate that it wants push.
2376285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            // - At least one content type must be sync-enabled in the account manager.
2386285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            // - At least one mailbox of a sync-enabled type must have automatic sync enabled.
239ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            final EmailSyncAdapterService service = EmailSyncAdapterService.this;
2406285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            final android.accounts.Account amAccount = new android.accounts.Account(
2416285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                            account.mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE);
2426285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            boolean pushNeeded = false;
243ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            if (account.mSyncInterval == Account.CHECK_INTERVAL_PUSH) {
24477b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu                final HashSet<String> authsToSync = getAuthsToSync(amAccount);
2456285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                // If we have at least one sync-enabled content type, check for syncing mailboxes.
2466285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                if (!authsToSync.isEmpty()) {
2476285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                    final Cursor c = Mailbox.getMailboxesForPush(service.getContentResolver(),
2486285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                            account.mId);
2496285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                    if (c != null) {
2506285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                        try {
2516285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                            while (c.moveToNext()) {
2526285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                                final int mailboxType = c.getInt(Mailbox.CONTENT_TYPE_COLUMN);
2536285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                                if (authsToSync.contains(Mailbox.getAuthority(mailboxType))) {
2546285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                                    pushNeeded = true;
2556285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                                    break;
2566285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                                }
2576285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                            }
2586285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                        } finally {
2596285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                            c.close();
2606285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                        }
2616285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                    }
2626285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                }
2636285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            }
2646285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu
2656285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            // Stop, start, or restart the ping as needed, as well as the ping kicker periodic sync.
2666285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            final PingTask pingSyncHandler = mPingHandlers.get(account.mId);
2676285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            final Bundle extras = new Bundle(1);
2684427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon            extras.putBoolean(Mailbox.SYNC_EXTRA_PUSH_ONLY, true);
2696285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            if (pushNeeded) {
2706285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                // First start or restart the ping as appropriate.
2716285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                if (pingSyncHandler != null) {
2726285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                    pingSyncHandler.restart();
2736285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                } else {
2746285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                    // Start a new ping.
2756285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                    // Note: unlike startSync, we CANNOT allow the caller to do the actual work.
2766285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                    // If we return before the ping starts, there's a race condition where another
2776285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                    // ping or sync might start first. It only works for startSync because sync is
2786285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                    // higher priority than ping (i.e. a ping can't start while a sync is pending)
2796285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                    // and only one sync can run at a time.
280502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                    if (lastSyncHadError) {
281502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                        // Schedule an alarm to set up the ping in 5 minutes
282502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                        final Intent intent = new Intent(service, EmailSyncAdapterService.class);
283502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                        intent.setAction(Eas.EXCHANGE_SERVICE_INTENT_ACTION);
284502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                        intent.putExtra(EXTRA_START_PING, true);
285db1ca5f71ea90df7179b981c71f3ec757207b92eYu Ping Hu                        intent.putExtra(EXTRA_PING_ACCOUNT, amAccount);
286502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                        final PendingIntent pi = PendingIntent.getService(
287502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                                EmailSyncAdapterService.this, 0, intent,
288502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                                PendingIntent.FLAG_ONE_SHOT);
289502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                        final AlarmManager am = (AlarmManager)getSystemService(
290502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                                Context.ALARM_SERVICE);
291502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                        final long atTime = SystemClock.elapsedRealtime() +
292502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                                SYNC_ERROR_BACKOFF_MILLIS;
293502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                        am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, atTime, pi);
294502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                    } else {
295502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                        final PingTask pingHandler = new PingTask(service, account, amAccount,
296502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                                this);
297502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                        mPingHandlers.put(account.mId, pingHandler);
298502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                        pingHandler.start();
299502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                        // Whenever we have a running ping, make sure this service stays running.
300502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                        service.startService(new Intent(service, EmailSyncAdapterService.class));
301502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                    }
3026285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                }
3030b1a8c91bd3abe4390a7bec47600f96e441185f0Yu Ping Hu                if (SCHEDULE_KICK) {
3040b1a8c91bd3abe4390a7bec47600f96e441185f0Yu Ping Hu                    ContentResolver.addPeriodicSync(amAccount, EmailContent.AUTHORITY, extras,
3050b1a8c91bd3abe4390a7bec47600f96e441185f0Yu Ping Hu                               KICK_SYNC_INTERVAL);
3060b1a8c91bd3abe4390a7bec47600f96e441185f0Yu Ping Hu                }
3076285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu            } else {
3086285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                if (pingSyncHandler != null) {
3096285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                    pingSyncHandler.stop();
3106285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu                }
3110b1a8c91bd3abe4390a7bec47600f96e441185f0Yu Ping Hu                if (SCHEDULE_KICK) {
3120b1a8c91bd3abe4390a7bec47600f96e441185f0Yu Ping Hu                    ContentResolver.removePeriodicSync(amAccount, EmailContent.AUTHORITY, extras);
3130b1a8c91bd3abe4390a7bec47600f96e441185f0Yu Ping Hu                }
3145f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            }
3155f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
3165f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
3175f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        /**
318ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * Updates the synchronization bookkeeping when a sync is done.
319ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * @param account The account whose sync just finished.
3205f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         */
321502ae63959c6a6253d05de8716417deef497392cMartin Hibdon        public synchronized void syncComplete(final boolean lastSyncHadError,
322502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                final Account account) {
323502ae63959c6a6253d05de8716417deef497392cMartin Hibdon            LogUtils.d(TAG, "syncComplete, err: " + lastSyncHadError);
324ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            mPingHandlers.remove(account.mId);
325ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // Syncs can interrupt pings, so we should check if we need to start one now.
326502ae63959c6a6253d05de8716417deef497392cMartin Hibdon            // If the last sync had a fatal error, we will not immediately recreate the ping.
327502ae63959c6a6253d05de8716417deef497392cMartin Hibdon            // Instead, we'll set an alarm that will restart them in a few minutes. This prevents
328502ae63959c6a6253d05de8716417deef497392cMartin Hibdon            // a battery draining spin if there is some kind of protocol error or other
329502ae63959c6a6253d05de8716417deef497392cMartin Hibdon            // non-transient failure. (Actually, immediately pinging even for a transient error
330502ae63959c6a6253d05de8716417deef497392cMartin Hibdon            // isn't great)
331502ae63959c6a6253d05de8716417deef497392cMartin Hibdon            modifyPing(lastSyncHadError, account);
332ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            stopServiceIfNoPings();
333ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            notifyAll();
334ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        }
335ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
336ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        /**
337ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * Updates the synchronization bookkeeping when a ping is done. Also requests a ping-only
338ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * sync if necessary.
339ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * @param amAccount The {@link android.accounts.Account} for this account.
340ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu         * @param accountId The account whose ping just finished.
341ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * @param pingStatus The status value from {@link PingParser} for the last ping performed.
342ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         *                   This cannot be one of the values that results in another ping, so this
343ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         *                   function only needs to handle the terminal statuses.
344ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         */
345ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        public synchronized void pingComplete(final android.accounts.Account amAccount,
346ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                final long accountId, final int pingStatus) {
347ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            mPingHandlers.remove(accountId);
348ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
349ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // TODO: if (pingStatus == PingParser.STATUS_FAILED), notify UI.
350ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // TODO: if (pingStatus == PingParser.STATUS_REQUEST_TOO_MANY_FOLDERS), notify UI.
351ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
3523054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu            // TODO: Should this just re-request ping if status < 0? This would do the wrong thing
3533054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu            // for e.g. auth errors, though.
3543054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu            if (pingStatus == EasOperation.RESULT_REQUEST_FAILURE ||
3553054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu                    pingStatus == EasOperation.RESULT_OTHER_FAILURE) {
356ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                // Request a new ping through the SyncManager. This will do the right thing if the
357ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                // exception was due to loss of network connectivity, etc. (i.e. it will wait for
358ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                // network to restore and then request it).
359ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                EasPing.requestPing(amAccount);
360ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            } else {
361400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu                stopServiceIfNoPings();
3625f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            }
3635f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
364ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // TODO: It might be the case that only STATUS_CHANGES_FOUND and
365ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // STATUS_FOLDER_REFRESH_NEEDED need to notifyAll(). Think this through.
366ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            notifyAll();
3675f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
368ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
3695f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    }
370400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu    private final SyncHandlerSynchronizer mSyncHandlerMap = new SyncHandlerSynchronizer();
3715f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
3725f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    /**
3735f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * The binder for IEmailService.
3745f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     */
3755f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    private final IEmailService.Stub mBinder = new IEmailService.Stub() {
376ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu
377ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu        private String getEmailAddressForAccount(final long accountId) {
378ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            final String emailAddress = Utility.getFirstRowString(EmailSyncAdapterService.this,
379ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu                    Account.CONTENT_URI, ACCOUNT_EMAIL_PROJECTION, Account.ID_SELECTION,
380ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu                    new String[] {Long.toString(accountId)}, null, 0);
381ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            if (emailAddress == null) {
382ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu                LogUtils.e(TAG, "Could not find email address for account %d", accountId);
383ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            }
384ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            return emailAddress;
385ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu        }
386ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu
3875f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
3885f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public Bundle validate(final HostAuth hostAuth) {
389942b7d73f2f5b3d6c651e39463e615fe6902a910Scott Kennedy            LogUtils.d(TAG, "IEmailService.validate");
390dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu            if (mEasService != null) {
391dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                try {
392dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                    return mEasService.validate(hostAuth);
393dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                } catch (final RemoteException re) {
394dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                    LogUtils.e(TAG, re, "While asking EasService to handle validate");
395dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                }
396dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu            }
3976c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu            return new EasFolderSync(EmailSyncAdapterService.this, hostAuth).doValidate();
3985f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
3995f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
4005f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
401ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        public Bundle autoDiscover(final String username, final String password) {
402942b7d73f2f5b3d6c651e39463e615fe6902a910Scott Kennedy            LogUtils.d(TAG, "IEmailService.autoDiscover");
403ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            return new EasAutoDiscover(EmailSyncAdapterService.this, username, password)
404ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    .doAutodiscover();
4055f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
4065f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
4075f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
4085f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public void updateFolderList(final long accountId) {
409ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            LogUtils.d(TAG, "IEmailService.updateFolderList: %d", accountId);
410dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu            if (mEasService != null) {
411dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                try {
412dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                    mEasService.updateFolderList(accountId);
413dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                    return;
414dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                } catch (final RemoteException re) {
415dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                    LogUtils.e(TAG, re, "While asking EasService to updateFolderList");
416dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                }
417dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu            }
418ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            final String emailAddress = getEmailAddressForAccount(accountId);
419bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu            if (emailAddress != null) {
4204cf04b79eeb69c8d6917635b5ecad79460af27f0Yu Ping Hu                final Bundle extras = new Bundle(1);
4214cf04b79eeb69c8d6917635b5ecad79460af27f0Yu Ping Hu                extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
422bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu                ContentResolver.requestSync(new android.accounts.Account(
423bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu                        emailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE),
4244cf04b79eeb69c8d6917635b5ecad79460af27f0Yu Ping Hu                        EmailContent.AUTHORITY, extras);
425bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu            }
4265f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
4275f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
4285f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
4295f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public void setLogging(final int flags) {
4305f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            // TODO: fix this?
4315f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            // Protocol logging
4325f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            Eas.setUserDebug(flags);
4335f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            // Sync logging
4345f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            //setUserDebug(flags);
4355f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
4365f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
4375f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
438b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee        public void loadAttachment(final IEmailServiceCallback callback, final long accountId,
439b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee                final long attachmentId, final boolean background) {
440c35d2fa94faa0f9abeded869a01108bac2bcedccYu Ping Hu            LogUtils.d(TAG, "IEmailService.loadAttachment: %d", attachmentId);
441da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu            // TODO: Prevent this from happening in parallel with a sync?
442b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee            final EasLoadAttachment operation = new EasLoadAttachment(EmailSyncAdapterService.this,
443b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee                    accountId, attachmentId, callback);
4448c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu            operation.performOperation();
4455f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
4465f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
4475f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
4485f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public void sendMeetingResponse(final long messageId, final int response) {
44962c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu            LogUtils.d(TAG, "IEmailService.sendMeetingResponse: %d, %d", messageId, response);
45062c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu            EasMeetingResponder.sendMeetingResponse(EmailSyncAdapterService.this, messageId,
45162c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu                    response);
4525f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
4535f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
4545f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        /**
4555f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * Delete PIM (calendar, contacts) data for the specified account
4565f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         *
457ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu         * @param emailAddress the email address for the account whose data should be deleted
4585f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         */
4595f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
460ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu        public void deleteAccountPIMData(final String emailAddress) {
461942b7d73f2f5b3d6c651e39463e615fe6902a910Scott Kennedy            LogUtils.d(TAG, "IEmailService.deleteAccountPIMData");
462ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            if (emailAddress != null) {
463ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu                final Context context = EmailSyncAdapterService.this;
464ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu                EasContactsSyncHandler.wipeAccountFromContentProvider(context, emailAddress);
465ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu                EasCalendarSyncHandler.wipeAccountFromContentProvider(context, emailAddress);
4665f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            }
467ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            // TODO: Run account reconciler?
4685f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
4695f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
4705f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
4715f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public int searchMessages(final long accountId, final SearchParams searchParams,
4725f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                final long destMailboxId) {
473b3ee6545d55cd02161cb8acf054f3edbec02dacfPaul Westbrook            LogUtils.d(TAG, "IEmailService.searchMessages");
4740756a9ff8e69b8cc52374fa68efb2e81971ee5c4Martin Hibdon            final EasSearch operation = new EasSearch(EmailSyncAdapterService.this, accountId,
4750756a9ff8e69b8cc52374fa68efb2e81971ee5c4Martin Hibdon                    searchParams, destMailboxId);
4760756a9ff8e69b8cc52374fa68efb2e81971ee5c4Martin Hibdon            operation.performOperation();
4770756a9ff8e69b8cc52374fa68efb2e81971ee5c4Martin Hibdon            return operation.getTotalResults();
478e2788afb86984dae29255fd9c7e24c78d90dbdadYu Ping Hu            // TODO: may need an explicit callback to replace the one to IEmailServiceCallback.
4795f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
4805f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
4815f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
4825f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public void sendMail(final long accountId) {}
48321c759804d49b1f9383e43bccead12de663e31adYu Ping Hu
48421c759804d49b1f9383e43bccead12de663e31adYu Ping Hu        @Override
4858c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu        public void pushModify(final long accountId) {
4868c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu            LogUtils.d(TAG, "IEmailService.pushModify");
4878c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu            if (mEasService != null) {
4888c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                try {
4898c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    mEasService.pushModify(accountId);
4908c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    return;
4918c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                } catch (final RemoteException re) {
4928c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    LogUtils.e(TAG, re, "While asking EasService to handle pushModify");
4938c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                }
4948c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu            }
4958c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu            final Account account = Account.restoreAccountWithId(EmailSyncAdapterService.this,
4968c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    accountId);
4978c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu            if (account != null) {
4988c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                mSyncHandlerMap.modifyPing(false, account);
4998c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu            }
5008c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu        }
5018c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu
5028c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu        @Override
5038c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu        public void sync(final long accountId, final boolean updateFolderList,
5048c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                final int mailboxType, final long[] folders) {}
5055f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    };
5065f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
5072674530d1879be7ae2df5105f07a93a5557ec389Marc Blank    public EmailSyncAdapterService() {
5082674530d1879be7ae2df5105f07a93a5557ec389Marc Blank        super();
5092674530d1879be7ae2df5105f07a93a5557ec389Marc Blank    }
5102674530d1879be7ae2df5105f07a93a5557ec389Marc Blank
511ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu    /**
512ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu     * {@link AsyncTask} for restarting pings for all accounts that need it.
513ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu     */
5141e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon    private static final String PUSH_ACCOUNTS_SELECTION =
5151e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon            AccountColumns.SYNC_INTERVAL + "=" + Integer.toString(Account.CHECK_INTERVAL_PUSH);
5161e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon    private class RestartPingsTask extends AsyncTask<Void, Void, Void> {
517ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
518ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        private final ContentResolver mContentResolver;
519ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        private final SyncHandlerSynchronizer mSyncHandlerMap;
5201e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon        private boolean mAnyAccounts;
521ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
522ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        public RestartPingsTask(final ContentResolver contentResolver,
523ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                final SyncHandlerSynchronizer syncHandlerMap) {
524ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            mContentResolver = contentResolver;
525ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            mSyncHandlerMap = syncHandlerMap;
526ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        }
527ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
528ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        @Override
529ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        protected Void doInBackground(Void... params) {
530ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            final Cursor c = mContentResolver.query(Account.CONTENT_URI,
531ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                    Account.CONTENT_PROJECTION, PUSH_ACCOUNTS_SELECTION, null, null);
532ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            if (c != null) {
533ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                try {
5341e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon                    mAnyAccounts = (c.getCount() != 0);
535ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                    while (c.moveToNext()) {
536ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                        final Account account = new Account();
537ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                        account.restore(c);
538502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                        mSyncHandlerMap.modifyPing(false, account);
539ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                    }
540ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                } finally {
541ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                    c.close();
542ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                }
5431e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon            } else {
5441e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon                mAnyAccounts = false;
545ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            }
546ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            return null;
547ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        }
5481e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon
5491e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon        @Override
5501e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon        protected void onPostExecute(Void result) {
5511e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon            if (!mAnyAccounts) {
5521e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon                LogUtils.d(TAG, "stopping for no accounts");
5531e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon                EmailSyncAdapterService.this.stopSelf();
5541e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon            }
5551e8e65ee854d2184597362f5b8b5332ca257c434Martin Hibdon        }
556ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu    }
557ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
558ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu    @Override
559ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu    public void onCreate() {
5603eef378426c7c88608f53f5a268baed40259ccf6Alon Albert        LogUtils.v(TAG, "onCreate()");
561ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        super.onCreate();
562f2bfcf5e111fc8e29d2dc9765ef2b1826a7d125dAlon Albert        startService(new Intent(this, EmailSyncAdapterService.class));
563ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        // Restart push for all accounts that need it.
564ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        new RestartPingsTask(getContentResolver(), mSyncHandlerMap).executeOnExecutor(
565ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                AsyncTask.THREAD_POOL_EXECUTOR);
566dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu        if (DELEGATE_TO_EAS_SERVICE) {
567dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu            // TODO: This block is temporary to support the transition to EasService.
568dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu            mConnection = new ServiceConnection() {
569dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                @Override
570dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                public void onServiceConnected(ComponentName name,  IBinder binder) {
571dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                    mEasService = IEmailService.Stub.asInterface(binder);
572dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                }
573dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu
574dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                @Override
575dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                public void onServiceDisconnected(ComponentName name) {
576dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                    mEasService = null;
577dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu                }
578dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu            };
579dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu            bindService(new Intent(this, EasService.class), mConnection, Context.BIND_AUTO_CREATE);
580dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu        }
581ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu    }
582ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
5839696d7f701599644d1c108863d6195af88da2c30Yu Ping Hu    @Override
5845550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert    public void onDestroy() {
5853eef378426c7c88608f53f5a268baed40259ccf6Alon Albert        LogUtils.v(TAG, "onDestroy()");
5865550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert        super.onDestroy();
5875550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert        for (PingTask task : mSyncHandlerMap.mPingHandlers.values()) {
5885550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert            if (task != null) {
5895550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert                task.stop();
5905550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert            }
5915550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert        }
592dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu        if (DELEGATE_TO_EAS_SERVICE) {
593dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu            // TODO: This block is temporary to support the transition to EasService.
594dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu            unbindService(mConnection);
595dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Hu        }
5965550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert    }
5975550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert
5985550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert    @Override
5995f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    public IBinder onBind(Intent intent) {
6005f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        if (intent.getAction().equals(Eas.EXCHANGE_SERVICE_INTENT_ACTION)) {
6015f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            return mBinder;
6025f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
6035f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        return super.onBind(intent);
6045f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    }
6055f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
6065f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    @Override
607be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon    public int onStartCommand(Intent intent, int flags, int startId) {
608be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon        if (intent != null &&
609be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon                TextUtils.equals(Eas.EXCHANGE_SERVICE_INTENT_ACTION, intent.getAction())) {
610be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon            if (intent.getBooleanExtra(ServiceProxy.EXTRA_FORCE_SHUTDOWN, false)) {
611be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon                // We've been asked to forcibly shutdown. This happens if email accounts are
612be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon                // deleted, otherwise we can get errors if services are still running for
613be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon                // accounts that are now gone.
614be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon                // TODO: This is kind of a hack, it would be nicer if we could handle it correctly
615be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon                // if accounts disappear out from under us.
616be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon                LogUtils.d(TAG, "Forced shutdown, killing process");
617be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon                System.exit(-1);
618502ae63959c6a6253d05de8716417deef497392cMartin Hibdon            } else if (intent.getBooleanExtra(EXTRA_START_PING, false)) {
619502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                LogUtils.d(TAG, "Restarting ping from alarm");
620502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                // We've been woken up by an alarm to restart our ping. This happens if a sync
621502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                // fails, rather that instantly starting the ping, we'll hold off for a few minutes.
622db1ca5f71ea90df7179b981c71f3ec757207b92eYu Ping Hu                final android.accounts.Account account =
623db1ca5f71ea90df7179b981c71f3ec757207b92eYu Ping Hu                        intent.getParcelableExtra(EXTRA_PING_ACCOUNT);
624db1ca5f71ea90df7179b981c71f3ec757207b92eYu Ping Hu                EasPing.requestPing(account);
625be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon            }
626be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon        }
627be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon        return super.onStartCommand(intent, flags, startId);
628be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon    }
629be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon
630be755d1832ce79b58f831aec08385e30c248f46dMartin Hibdon    @Override
63124e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu    protected AbstractThreadedSyncAdapter getSyncAdapter() {
63224e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu        synchronized (sSyncAdapterLock) {
63324e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu            if (sSyncAdapter == null) {
63424e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu                sSyncAdapter = new SyncAdapterImpl(this);
63524e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu            }
63624e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu            return sSyncAdapter;
63724e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu        }
6389696d7f701599644d1c108863d6195af88da2c30Yu Ping Hu    }
6399696d7f701599644d1c108863d6195af88da2c30Yu Ping Hu
6405f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    // TODO: Handle cancelSync() appropriately.
6415f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    private class SyncAdapterImpl extends AbstractThreadedSyncAdapter {
6422674530d1879be7ae2df5105f07a93a5557ec389Marc Blank        public SyncAdapterImpl(Context context) {
6432674530d1879be7ae2df5105f07a93a5557ec389Marc Blank            super(context, true /* autoInitialize */);
6442674530d1879be7ae2df5105f07a93a5557ec389Marc Blank        }
6452674530d1879be7ae2df5105f07a93a5557ec389Marc Blank
6462674530d1879be7ae2df5105f07a93a5557ec389Marc Blank        @Override
647456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu        public void onPerformSync(final android.accounts.Account acct, final Bundle extras,
648456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                final String authority, final ContentProviderClient provider,
649456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                final SyncResult syncResult) {
6503eef378426c7c88608f53f5a268baed40259ccf6Alon Albert            if (LogUtils.isLoggable(TAG, Log.DEBUG)) {
6513eef378426c7c88608f53f5a268baed40259ccf6Alon Albert                LogUtils.d(TAG, "onPerformSync: %s, %s", acct.toString(), extras.toString());
6523eef378426c7c88608f53f5a268baed40259ccf6Alon Albert            } else {
6533eef378426c7c88608f53f5a268baed40259ccf6Alon Albert                LogUtils.i(TAG, "onPerformSync: %s", extras.toString());
6543eef378426c7c88608f53f5a268baed40259ccf6Alon Albert            }
655bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu            TempDirectory.setTempDirectory(EmailSyncAdapterService.this);
656bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu
657c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // TODO: Perform any connectivity checks, bail early if we don't have proper network
658c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // for this sync operation.
6592674530d1879be7ae2df5105f07a93a5557ec389Marc Blank
660c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final Context context = getContext();
661c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final ContentResolver cr = context.getContentResolver();
662c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
663c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // Get the EmailContent Account
664c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final Account account;
665c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final Cursor accountCursor = cr.query(Account.CONTENT_URI, Account.CONTENT_PROJECTION,
666c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    AccountColumns.EMAIL_ADDRESS + "=?", new String[] {acct.name}, null);
6670b90e8d0cebf3e40c894f2e84b8cd3aa82d83765Yu Ping Hu            try {
668c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                if (!accountCursor.moveToFirst()) {
669c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    // Could not load account.
670c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    // TODO: improve error handling.
6713eef378426c7c88608f53f5a268baed40259ccf6Alon Albert                    LogUtils.w(TAG, "onPerformSync: could not load account");
672c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    return;
6732674530d1879be7ae2df5105f07a93a5557ec389Marc Blank                }
674c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                account = new Account();
675c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                account.restore(accountCursor);
6760b90e8d0cebf3e40c894f2e84b8cd3aa82d83765Yu Ping Hu            } finally {
6770b90e8d0cebf3e40c894f2e84b8cd3aa82d83765Yu Ping Hu                accountCursor.close();
6782674530d1879be7ae2df5105f07a93a5557ec389Marc Blank            }
67977b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu
68077b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu            // Figure out what we want to sync, based on the extras and our account sync status.
68177b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu            final boolean isInitialSync = EmailContent.isInitialSyncKey(account.mSyncKey);
6824427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon            final long[] mailboxIds = Mailbox.getMailboxIdsFromBundle(extras);
68377b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu            final int mailboxType = extras.getInt(Mailbox.SYNC_EXTRA_MAILBOX_TYPE,
68477b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu                    Mailbox.TYPE_NONE);
685fa84f281d166cd7d43ca88adf89751ea9acfc51cAlon Albert            final boolean hasCallbackMethod =
686fa84f281d166cd7d43ca88adf89751ea9acfc51cAlon Albert                    extras.containsKey(EmailServiceStatus.SYNC_EXTRAS_CALLBACK_METHOD);
687fa84f281d166cd7d43ca88adf89751ea9acfc51cAlon Albert            if (hasCallbackMethod && mailboxIds != null) {
688fa84f281d166cd7d43ca88adf89751ea9acfc51cAlon Albert                for (long mailboxId : mailboxIds) {
689fa84f281d166cd7d43ca88adf89751ea9acfc51cAlon Albert                    EmailServiceStatus.syncMailboxStatus(cr, extras, mailboxId,
690fa84f281d166cd7d43ca88adf89751ea9acfc51cAlon Albert                            EmailServiceStatus.IN_PROGRESS, 0, UIProvider.LastSyncResult.SUCCESS);
691fa84f281d166cd7d43ca88adf89751ea9acfc51cAlon Albert                }
692fa84f281d166cd7d43ca88adf89751ea9acfc51cAlon Albert            }
69377b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu
694c1e77ad19eb6e815cbb9f944b2e734bd40432928Yu Ping Hu            // Push only means this sync request should only refresh the ping (either because
695c1e77ad19eb6e815cbb9f944b2e734bd40432928Yu Ping Hu            // settings changed, or we need to restart it for some reason).
696c1e77ad19eb6e815cbb9f944b2e734bd40432928Yu Ping Hu            final boolean pushOnly = Mailbox.isPushOnlyExtras(extras);
697c1e77ad19eb6e815cbb9f944b2e734bd40432928Yu Ping Hu            // Account only means just do a FolderSync.
698c1e77ad19eb6e815cbb9f944b2e734bd40432928Yu Ping Hu            final boolean accountOnly = Mailbox.isAccountOnlyExtras(extras);
699c1e77ad19eb6e815cbb9f944b2e734bd40432928Yu Ping Hu
700c1e77ad19eb6e815cbb9f944b2e734bd40432928Yu Ping Hu            // A "full sync" means that we didn't request a more specific type of sync.
701c1e77ad19eb6e815cbb9f944b2e734bd40432928Yu Ping Hu            final boolean isFullSync = (!pushOnly && !accountOnly && mailboxIds == null &&
702c1e77ad19eb6e815cbb9f944b2e734bd40432928Yu Ping Hu                    mailboxType == Mailbox.TYPE_NONE);
7034427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon
70477b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu            // A FolderSync is necessary for full sync, initial sync, and account only sync.
7054427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon            final boolean isFolderSync = (isFullSync || isInitialSync || accountOnly);
70677b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu
70777b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu            // If we're just twiddling the push, we do the lightweight thing and bail early.
7084427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon            if (pushOnly && !isFolderSync) {
7093eef378426c7c88608f53f5a268baed40259ccf6Alon Albert                LogUtils.d(TAG, "onPerformSync: mailbox push only");
7108c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                if (mEasService != null) {
7118c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    try {
7128c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                        mEasService.pushModify(account.mId);
7138c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                        return;
7148c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    } catch (final RemoteException re) {
7158c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                        LogUtils.e(TAG, re, "While trying to pushModify within onPerformSync");
7168c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    }
7178c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                }
7188c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                mSyncHandlerMap.modifyPing(false, account);
719ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                return;
720ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            }
721c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
7225f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            // Do the bookkeeping for starting a sync, including stopping a ping if necessary.
7235f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            mSyncHandlerMap.startSync(account.mId);
7245f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
7258c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu            try {
7268c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                // Perform a FolderSync if necessary.
7278c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                // TODO: We permit FolderSync even during security hold, because it's necessary to
7288c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                // resolve some holds. Ideally we would only do it for the holds that require it.
7298c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                if (isFolderSync) {
7308c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    final EasFolderSync folderSync = new EasFolderSync(context, account);
7318c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    final int result = folderSync.doFolderSync();
7328c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    if (result < 0) {
7338c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                        EasFolderSync.writeResultToSyncResult(result, syncResult);
7348c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                        return;
7358c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    }
7368c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                }
73777b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu
7388c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                // Do not permit further syncs if we're on security hold.
7398c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                if ((account.mFlags & Account.FLAGS_SECURITY_HOLD) != 0) {
7408c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    return;
7418c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                }
74277b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu
743d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                // Perform email upsync for this account. Moves first, then state changes.
744d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                if (!isInitialSync) {
745d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                    EasMoveItems move = new EasMoveItems(context, account);
7468c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    final int moveResult = move.upsyncMovedMessages();
7478c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    if (moveResult < 0) {
7488c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                        EasMoveItems.writeResultToSyncResult(moveResult, syncResult);
7498c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                        return;
7508c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    }
7518c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu
752d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                    // TODO: EasSync should eventually handle both up and down; for now, it's used
753d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                    // purely for upsync.
754d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                    EasSync upsync = new EasSync(context, account);
7558c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    final int upsyncResult = upsync.upsync();
7568c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    if (upsyncResult < 0) {
7578c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                        EasSync.writeResultToSyncResult(upsyncResult, syncResult);
7588c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                        return;
7598c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                    }
760d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                }
7615f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
762d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                if (mailboxIds != null) {
763d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                    // Sync the mailbox that was explicitly requested.
764d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                    for (final long mailboxId : mailboxIds) {
76597a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                        final int result = syncMailbox(context, cr, acct, account, mailboxId,
766d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                                extras, syncResult, null, true);
76797a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                        EasSyncBase.writeResultToSyncResult(result, syncResult);
768d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                        if (hasCallbackMethod) {
76997a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                            final int uiResult;
770d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                            if (syncResult.hasError()) {
77197a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                if (syncResult.stats.numIoExceptions > 0) {
77297a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                    uiResult = UIProvider.LastSyncResult.CONNECTION_ERROR;
77397a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                } else if (syncResult.stats.numAuthExceptions > 0) {
77497a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                    uiResult = UIProvider.LastSyncResult.AUTH_ERROR;
775d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                                }  else {
77697a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                    uiResult = UIProvider.LastSyncResult.INTERNAL_ERROR;
777d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                                }
778d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                            } else {
77997a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                uiResult = UIProvider.LastSyncResult.SUCCESS;
780fa84f281d166cd7d43ca88adf89751ea9acfc51cAlon Albert                            }
781d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                            EmailServiceStatus.syncMailboxStatus(
78297a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                    cr, extras, mailboxId,EmailServiceStatus.SUCCESS, 0, uiResult);
78397a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                        }
78497a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                        if (syncResult.hasError()) {
78597a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                            break;
786fa84f281d166cd7d43ca88adf89751ea9acfc51cAlon Albert                        }
787fa84f281d166cd7d43ca88adf89751ea9acfc51cAlon Albert                    }
788d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                } else if (!accountOnly && !pushOnly) {
789d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                    // We have to sync multiple folders.
790d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                    final Cursor c;
791d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                    if (isFullSync) {
792d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                        // Full account sync includes all mailboxes that participate in system sync.
793d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                        c = Mailbox.getMailboxIdsForSync(cr, account.mId);
794d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                    } else {
795d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                        // Type-filtered sync should only get the mailboxes of a specific type.
796d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                        c = Mailbox.getMailboxIdsForSyncByType(cr, account.mId, mailboxType);
797d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                    }
798d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                    if (c != null) {
799d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                        try {
800d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                            final HashSet<String> authsToSync = getAuthsToSync(acct);
801d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                            while (c.moveToNext()) {
80297a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                final int result = syncMailbox(context, cr, acct, account,
803d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                                        c.getLong(0), extras, syncResult, authsToSync, false);
80497a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                EasSyncBase.writeResultToSyncResult(result, syncResult);
80597a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                if (syncResult.hasError()) {
80697a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                    break;
807d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                                }
808502ae63959c6a6253d05de8716417deef497392cMartin Hibdon                            }
809d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                        } finally {
810d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                            c.close();
811456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                        }
812456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                    }
813c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
8148c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu            } finally {
8158c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                // Clean up the bookkeeping, including restarting ping if necessary.
81697a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                mSyncHandlerMap.syncComplete(syncResult.hasError(), account);
81797a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu
81897a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                // If any operations had an auth error, notify the user.
81997a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                if (syncResult.stats.numAuthExceptions > 0) {
82097a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                    showAuthNotification(account.mId, account.mEmailAddress);
82197a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                }
8225f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
8238c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu                LogUtils.d(TAG, "onPerformSync: finished");
8248c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu            }
8252674530d1879be7ae2df5105f07a93a5557ec389Marc Blank        }
826456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu
827e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu        /**
828e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu         * Update the mailbox's sync status with the provider and, if we're finished with the sync,
829e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu         * write the last sync time as well.
830e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu         * @param context Our {@link Context}.
831e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu         * @param mailbox The mailbox whose sync status to update.
832e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu         * @param cv A {@link ContentValues} object to use for updating the provider.
833e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu         * @param syncStatus The status for the current sync.
834e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu         */
835e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu        private void updateMailbox(final Context context, final Mailbox mailbox,
836e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu                final ContentValues cv, final int syncStatus) {
837e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu            cv.put(Mailbox.UI_SYNC_STATUS, syncStatus);
838e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu            if (syncStatus == EmailContent.SYNC_STATUS_NONE) {
839e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu                cv.put(Mailbox.SYNC_TIME, System.currentTimeMillis());
840e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu            }
841e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu            mailbox.update(context, cv);
842e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu        }
843e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu
84497a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu        private int syncMailbox(final Context context, final ContentResolver cr,
845456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                final android.accounts.Account acct, final Account account, final long mailboxId,
84677b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu                final Bundle extras, final SyncResult syncResult, final HashSet<String> authsToSync,
84777b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu                final boolean isMailboxSync) {
848456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu            final Mailbox mailbox = Mailbox.restoreMailboxWithId(context, mailboxId);
849456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu            if (mailbox == null) {
85097a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                return EasSyncBase.RESULT_HARD_DATA_FAILURE;
8515cc7ea3e24f1c05f71a3223ac6fa8b69d211735cYu Ping Hu            }
8525cc7ea3e24f1c05f71a3223ac6fa8b69d211735cYu Ping Hu
8535cc7ea3e24f1c05f71a3223ac6fa8b69d211735cYu Ping Hu            if (mailbox.mAccountKey != account.mId) {
8545cc7ea3e24f1c05f71a3223ac6fa8b69d211735cYu Ping Hu                LogUtils.e(TAG, "Mailbox does not match account: %s, %s", acct.toString(),
8555cc7ea3e24f1c05f71a3223ac6fa8b69d211735cYu Ping Hu                        extras.toString());
85697a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                return EasSyncBase.RESULT_HARD_DATA_FAILURE;
857456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu            }
85877b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu            if (authsToSync != null && !authsToSync.contains(Mailbox.getAuthority(mailbox.mType))) {
85977b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu                // We are asking for an account sync, but this mailbox type is not configured for
860d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                // sync. Do NOT treat this as a sync error for ping backoff purposes.
86197a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                return EasSyncBase.RESULT_DONE;
86277b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu            }
863456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu
864baa15392f32753fc1320b7215a22bff18a95ffefMartin Hibdon            if (mailbox.mType == Mailbox.TYPE_DRAFTS) {
865baa15392f32753fc1320b7215a22bff18a95ffefMartin Hibdon                // TODO: Because we don't have bidirectional sync working, trying to downsync
866baa15392f32753fc1320b7215a22bff18a95ffefMartin Hibdon                // the drafts folder is confusing. b/11158759
867baa15392f32753fc1320b7215a22bff18a95ffefMartin Hibdon                // For now, just disable all syncing of DRAFTS type folders.
868baa15392f32753fc1320b7215a22bff18a95ffefMartin Hibdon                // Automatic syncing should always be disabled, but we also stop it here to ensure
869baa15392f32753fc1320b7215a22bff18a95ffefMartin Hibdon                // that we won't sync even if the user attempts to force a sync from the UI.
870d99c1068f74ed00b32edcf6392a51d840153526fYu Ping Hu                // Do NOT treat as a sync error for ping backoff purposes.
871baa15392f32753fc1320b7215a22bff18a95ffefMartin Hibdon                LogUtils.d(TAG, "Skipping sync of DRAFTS folder");
87297a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                return EasSyncBase.RESULT_DONE;
873baa15392f32753fc1320b7215a22bff18a95ffefMartin Hibdon            }
87497a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu
875e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu            // Non-mailbox syncs are whole account syncs initiated by the AccountManager and are
876e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu            // treated as background syncs.
877e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu            // TODO: Push will be treated as "user" syncs, and probably should be background.
8785586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu            final ContentValues cv = new ContentValues(2);
8795586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu            updateMailbox(context, mailbox, cv, isMailboxSync ?
8805586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu                    EmailContent.SYNC_STATUS_USER : EmailContent.SYNC_STATUS_BACKGROUND);
88197a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu            try {
88297a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                if (mailbox.mType == Mailbox.TYPE_OUTBOX) {
88397a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                    return syncOutbox(context, cr, account, mailbox);
884456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                }
885185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert
88697a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                if(mailbox.isSyncable()) {
88797a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                    // TODO: This conditional logic is temporary until EasSyncHandler is obsolete.
88897a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                    if (mailbox.mType == Mailbox.TYPE_INBOX || mailbox.mType == Mailbox.TYPE_MAIL ||
88997a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                            mailbox.mType == Mailbox.TYPE_SENT) {
89097a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                        final EasSyncBase operation = new EasSyncBase(context, account, mailbox);
89197a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                        return operation.performOperation();
89297a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                    } else {
89397a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                        // TODO: This branch goes away after all conversions are done.
89497a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                        final EasSyncHandler syncHandler = EasSyncHandler.getEasSyncHandler(context,
89597a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                cr, acct, account, mailbox, extras, syncResult);
89697a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                        if (syncHandler != null) {
89797a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                            if (!syncHandler.performSync(syncResult)) {
89897a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                // This is ass-backwards, but it's a hack until this code goes away.
89997a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                if (syncResult.stats.numIoExceptions > 0) {
90097a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                    return EasSyncBase.RESULT_REQUEST_FAILURE;
90197a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                }
90297a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                if (syncResult.stats.numAuthExceptions > 0) {
90397a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                    return EasSyncBase.RESULT_AUTHENTICATION_ERROR;
90497a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                }
90597a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                if (syncResult.stats.numParseExceptions > 0) {
90697a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                    return EasSyncBase.RESULT_OTHER_FAILURE;
90797a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                                }
90897a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                            }
90997a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                        }
91097a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                    }
91197a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                }
91297a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu            } finally {
91397a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu                updateMailbox(context, mailbox, cv, EmailContent.SYNC_STATUS_NONE);
914185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert            }
91597a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu
91697a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu            return EasSyncBase.RESULT_DONE;
917456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu        }
9182674530d1879be7ae2df5105f07a93a5557ec389Marc Blank    }
91961cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon
92061cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon    private int syncOutbox(Context context, ContentResolver cr, Account account, Mailbox mailbox) {
92161cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon        // Get a cursor to Outbox messages
92261cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon        final Cursor c = cr.query(Message.CONTENT_URI,
92361cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                Message.CONTENT_PROJECTION, MAILBOX_KEY_AND_NOT_SEND_FAILED,
92461cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                new String[] {Long.toString(mailbox.mId)}, null);
92561cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon        try {
92661cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon            // Loop through the messages, sending each one
92761cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon            while (c.moveToNext()) {
92861cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                final Message message = new Message();
92961cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                message.restore(c);
93061cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                if (Utility.hasUnloadedAttachments(context, message.mId)) {
93161cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                    // We'll just have to wait on this...
93261cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                    continue;
93361cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                }
93461cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon
93561cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                // TODO: Fix -- how do we want to signal to UI that we started syncing?
93661cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                // Note the entire callback mechanism here needs improving.
93761cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                //sendMessageStatus(message.mId, null, EmailServiceStatus.IN_PROGRESS, 0);
93861cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon
93961cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                EasOperation op = new EasOutboxSync(context, account, message, true);
94061cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                int result = op.performOperation();
94161cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                if (result == EasOutboxSync.RESULT_ITEM_NOT_FOUND) {
94261cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                    // This can happen if we are using smartReply, and the message we are referring
94361cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                    // to has disappeared from the server. Try again with smartReply disabled.
94461cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                    op = new EasOutboxSync(context, account, message, false);
94561cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                    result = op.performOperation();
94661cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                }
94761cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                if (result != EasOutboxSync.RESULT_OK) {
94861cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                    LogUtils.w(TAG, "Aborting outbox synx for error %d", result);
94961cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                    return result;
95061cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon                }
95161cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon            }
95261cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon        } finally {
95361cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon            // TODO: Some sort of sendMessageStatus() is needed here.
95461cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon            c.close();
95561cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon        }
95661cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon        return EasOutboxSync.RESULT_OK;
95761cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon    }
95861cb606031183d98cef654d1aaa3461f48746ad6Martin Hibdon
959185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert    private void showAuthNotification(long accountId, String accountName) {
960185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert        final PendingIntent pendingIntent = PendingIntent.getActivity(
961185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert                this,
962185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert                0,
963185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert                createAccountSettingsIntent(accountId, accountName),
964185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert                0);
965185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert
966185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert        final Notification notification = new Builder(this)
967185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert                .setContentTitle(this.getString(string.auth_error_notification_title))
968185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert                .setContentText(this.getString(
969185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert                        string.auth_error_notification_text, accountName))
970185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert                .setSmallIcon(drawable.stat_notify_auth)
971185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert                .setContentIntent(pendingIntent)
972185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert                .setAutoCancel(true)
973185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert                .build();
974185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert
975185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert        final NotificationManager nm = (NotificationManager)
976185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert                this.getSystemService(Context.NOTIFICATION_SERVICE);
977185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert        nm.notify("AuthError", 0, notification);
978185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert    }
979185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert
980185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert    /**
981185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert     * Create and return an intent to display (and edit) settings for a specific account, or -1
982185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert     * for any/all accounts.  If an account name string is provided, a warning dialog will be
983185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert     * displayed as well.
984185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert     */
985185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert    public static Intent createAccountSettingsIntent(long accountId, String accountName) {
986185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert        final Uri.Builder builder = IntentUtilities.createActivityIntentUrlBuilder(
987185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert                IntentUtilities.PATH_SETTINGS);
988185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert        IntentUtilities.setAccountId(builder, accountId);
989185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert        IntentUtilities.setAccountName(builder, accountName);
990185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert        return new Intent(Intent.ACTION_EDIT, builder.build());
991185672ab3d117a9e0fb8f76ef1faa2583efc7dadAlon Albert    }
99277b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu
99377b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu    /**
99477b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu     * Determine which content types are set to sync for an account.
99577b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu     * @param account The account whose sync settings we're looking for.
99677b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu     * @return The authorities for the content types we want to sync for account.
99777b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu     */
99877b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu    private static HashSet<String> getAuthsToSync(final android.accounts.Account account) {
99977b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu        final HashSet<String> authsToSync = new HashSet();
100077b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu        if (ContentResolver.getSyncAutomatically(account, EmailContent.AUTHORITY)) {
100177b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu            authsToSync.add(EmailContent.AUTHORITY);
100277b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu        }
100377b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu        if (ContentResolver.getSyncAutomatically(account, CalendarContract.AUTHORITY)) {
100477b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu            authsToSync.add(CalendarContract.AUTHORITY);
100577b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu        }
100677b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu        if (ContentResolver.getSyncAutomatically(account, ContactsContract.AUTHORITY)) {
100777b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu            authsToSync.add(ContactsContract.AUTHORITY);
100877b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu        }
100977b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu        return authsToSync;
101077b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu    }
10110b90e8d0cebf3e40c894f2e84b8cd3aa82d83765Yu Ping Hu}
1012