EmailSyncAdapterService.java revision 328ca0d959f7e729e96f19538c8f3af8fe782a09
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
19ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.AbstractThreadedSyncAdapter;
20ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.ContentProviderClient;
21ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.ContentResolver;
22e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Huimport android.content.ContentValues;
23ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.Context;
24ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.Intent;
25ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.SyncResult;
26ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.database.Cursor;
27ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Huimport android.os.AsyncTask;
28ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.os.Bundle;
29ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.os.IBinder;
30ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
315f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport com.android.emailcommon.Api;
32bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Huimport com.android.emailcommon.TempDirectory;
33c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.provider.Account;
34bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Huimport com.android.emailcommon.provider.EmailContent;
35c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.provider.EmailContent.AccountColumns;
365f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport com.android.emailcommon.provider.HostAuth;
374d8774462ace9a45154b2df418b9f2fe7a9c685dBen Komaloimport com.android.emailcommon.provider.Mailbox;
385f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport com.android.emailcommon.service.IEmailService;
395f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport com.android.emailcommon.service.IEmailServiceCallback;
405f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport com.android.emailcommon.service.SearchParams;
41bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Huimport com.android.emailcommon.utility.Utility;
425f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport com.android.exchange.Eas;
43ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Huimport com.android.exchange.adapter.PingParser;
44b3ee6545d55cd02161cb8acf054f3edbec02dacfPaul Westbrookimport com.android.exchange.adapter.Search;
45328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Huimport com.android.exchange.eas.EasFolderSync;
46ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.exchange.eas.EasOperation;
47ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.exchange.eas.EasPing;
485f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport com.android.mail.providers.UIProvider.AccountCapabilities;
49942b7d73f2f5b3d6c651e39463e615fe6902a910Scott Kennedyimport com.android.mail.utils.LogUtils;
505f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
515f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport java.util.HashMap;
522674530d1879be7ae2df5105f07a93a5557ec389Marc Blank
532177272932413dd434ed1a393b22f452dc38740aYu Ping Hu/**
542177272932413dd434ed1a393b22f452dc38740aYu Ping Hu * Service for communicating with Exchange servers. There are three main parts of this class:
552177272932413dd434ed1a393b22f452dc38740aYu Ping Hu * TODO: Flesh out these comments.
562177272932413dd434ed1a393b22f452dc38740aYu Ping Hu * 1) An {@link AbstractThreadedSyncAdapter} to handle actually performing syncs.
572177272932413dd434ed1a393b22f452dc38740aYu Ping Hu * 2) Bookkeeping for running Ping requests, which handles push notifications.
582177272932413dd434ed1a393b22f452dc38740aYu Ping Hu * 3) An {@link IEmailService} Stub to handle RPC from the UI.
592177272932413dd434ed1a393b22f452dc38740aYu Ping Hu */
60bbafcf7dbcb92063aa207113451c1d29235bc5ddMarc Blankpublic class EmailSyncAdapterService extends AbstractSyncAdapterService {
615f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
6287aa63eab6bb5abe86746d3f60c7ea1847393003Paul Westbrook    private static final String TAG = "EASEmailSyncAdaptSvc";
635f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
645f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    /**
65456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu     * If sync extras do not include a mailbox id, then we want to perform a full sync.
66456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu     */
67456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu    private static final long FULL_ACCOUNT_SYNC = Mailbox.NO_MAILBOX;
68456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu
69ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu    /** Projection used for getting email address for an account. */
70ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu    private static final String[] ACCOUNT_EMAIL_PROJECTION = { AccountColumns.EMAIL_ADDRESS };
71ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu
72456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu    /**
735f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * Bookkeeping for handling synchronization between pings and syncs.
745f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * "Ping" refers to a hanging POST or GET that is used to receive push notifications. Ping is
755f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * the term for the Exchange command, but this code should be generic enough to be easily
765f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * extended to IMAP.
775f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * "Sync" refers to an actual sync command to either fetch mail state, account state, or send
785f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * mail (send is implemented as "sync the outbox").
795f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * TODO: Outbox sync probably need not stop a ping in progress.
805f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * Basic rules of how these interact (note that all rules are per account):
815f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - Only one ping or sync may run at a time.
825f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - Due to how {@link AbstractThreadedSyncAdapter} works, sync requests will not occur while
835f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     *   a sync is in progress.
845f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - On the other hand, ping requests may come in while handling a ping.
855f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - "Ping request" is shorthand for "a request to change our ping parameters", which includes
865f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     *   a request to stop receiving push notifications.
875f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - If neither a ping nor a sync is running, then a request for either will run it.
885f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - If a sync is running, new ping requests block until the sync completes.
895f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - If a ping is running, a new sync request stops the ping and creates a pending ping
905f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     *   (which blocks until the sync completes).
915f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - If a ping is running, a new ping request stops the ping and either starts a new one or
925f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     *   does nothing, as appopriate (since a ping request can be to stop pushing).
935f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * - As an optimization, while a ping request is waiting to run, subsequent ping requests are
945f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     *   ignored (the pending ping will pick up the latest ping parameters at the time it runs).
955f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     */
96400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu    public class SyncHandlerSynchronizer {
975f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        /**
985f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * Map of account id -> ping handler.
995f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * For a given account id, there are three possible states:
1005f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * 1) If no ping or sync is currently running, there is no entry in the map for the account.
1015f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * 2) If a ping is running, there is an entry with the appropriate ping handler.
1025f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * 3) If there is a sync running, there is an entry with null as the value.
1035f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * We cannot have more than one ping or sync running at a time.
1045f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         */
105ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        private final HashMap<Long, PingTask> mPingHandlers = new HashMap<Long, PingTask>();
1065f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
1075f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        /**
1085f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * Wait until neither a sync nor a ping is running on this account, and then return.
1095f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * If there's a ping running, actively stop it. (For syncs, we have to just wait.)
1105f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * @param accountId The account we want to wait for.
1115f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         */
1125f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        private synchronized void waitUntilNoActivity(final long accountId) {
1135f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            while (mPingHandlers.containsKey(accountId)) {
114ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                final PingTask pingHandler = mPingHandlers.get(accountId);
1155f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                if (pingHandler != null) {
116ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    pingHandler.stop();
1175f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                }
1185f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                try {
1195f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                    wait();
120ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                } catch (final InterruptedException e) {
1215f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                    // TODO: When would this happen, and how should I handle it?
1225f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                }
1235f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            }
1245f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
1255f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
1265f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        /**
1275f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * Use this to see if we're currently syncing, as opposed to pinging or doing nothing.
1285f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * @param accountId The account to check.
1295f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * @return Whether that account is currently running a sync.
1305f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         */
1315f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        private synchronized boolean isRunningSync(final long accountId) {
1325f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            return (mPingHandlers.containsKey(accountId) && mPingHandlers.get(accountId) == null);
1335f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
1345f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
135ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        /**
136ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * If there are no running pings, stop the service.
137ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         */
138400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu        private void stopServiceIfNoPings() {
139ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            for (final PingTask pingHandler : mPingHandlers.values()) {
140400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu                if (pingHandler != null) {
141400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu                    return;
142400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu                }
143400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu            }
144400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu            EmailSyncAdapterService.this.stopSelf();
145400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu        }
146400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu
1475f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        /**
148ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * Called prior to starting a sync to update our bookkeeping. We don't actually run the sync
149ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * here; the caller must do that.
1505f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * @param accountId The account on which we are running a sync.
1515f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         */
1525f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public synchronized void startSync(final long accountId) {
1535f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            waitUntilNoActivity(accountId);
1545f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            mPingHandlers.put(accountId, null);
1555f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
1565f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
1575f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        /**
158ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * Starts or restarts a ping for an account, if the current account state indicates that it
159ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * wants to push.
160ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * @param account The account whose ping is being modified.
1615f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         */
162ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        public synchronized void modifyPing(final Account account) {
163ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // If a sync is currently running, it will start a ping when it's done, so there's no
164ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // need to do anything right now.
165ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            if (isRunningSync(account.mId)) {
1665f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                return;
1675f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            }
1685f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
169ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // If a ping is currently running, tell it to restart to pick up new params.
170ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            final PingTask pingSyncHandler = mPingHandlers.get(account.mId);
171ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            if (pingSyncHandler != null) {
172ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                pingSyncHandler.restart();
1735f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                return;
1745f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            }
1755f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
176ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // If we're here, then there's neither a sync nor a ping running. Start a new ping.
177ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            final EmailSyncAdapterService service = EmailSyncAdapterService.this;
178ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            if (account.mSyncInterval == Account.CHECK_INTERVAL_PUSH) {
179ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                // TODO: Also check if we have any mailboxes that WANT push.
180ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                // This account needs to ping.
181ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                // Note: unlike startSync, we CANNOT allow the caller to do the actual work.
182ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                // If we return before the ping starts, there's a race condition where another
183ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                // ping or sync might start first. It only works for startSync because sync is
184ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                // higher priority than ping (i.e. a ping can't start while a sync is pending)
185ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                // and only one sync can run at a time.
186ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                final PingTask pingHandler = new PingTask(service, account, this);
187ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                mPingHandlers.put(account.mId, pingHandler);
188ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                pingHandler.start();
189ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                // Whenever we have a running ping, make sure this service stays running.
190ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                service.startService(new Intent(service, EmailSyncAdapterService.class));
1915f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            }
1925f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
1935f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
1945f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        /**
195ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * Updates the synchronization bookkeeping when a sync is done.
196ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * @param account The account whose sync just finished.
1975f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         */
198ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        public synchronized void syncComplete(final Account account) {
199ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            mPingHandlers.remove(account.mId);
200ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // Syncs can interrupt pings, so we should check if we need to start one now.
201ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            modifyPing(account);
202ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            stopServiceIfNoPings();
203ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            notifyAll();
204ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        }
205ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
206ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        /**
207ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * Updates the synchronization bookkeeping when a ping is done. Also requests a ping-only
208ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * sync if necessary.
209ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * @param amAccount The {@link android.accounts.Account} for this account.
210ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu         * @param accountId The account whose ping just finished.
211ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         * @param pingStatus The status value from {@link PingParser} for the last ping performed.
212ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         *                   This cannot be one of the values that results in another ping, so this
213ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         *                   function only needs to handle the terminal statuses.
214ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu         */
215ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        public synchronized void pingComplete(final android.accounts.Account amAccount,
216ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                final long accountId, final int pingStatus) {
217ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            mPingHandlers.remove(accountId);
218ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
219ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // TODO: if (pingStatus == PingParser.STATUS_FAILED), notify UI.
220ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // TODO: if (pingStatus == PingParser.STATUS_REQUEST_TOO_MANY_FOLDERS), notify UI.
221ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
222ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            if (pingStatus == EasOperation.RESULT_REQUEST_FAILURE) {
223ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                // Request a new ping through the SyncManager. This will do the right thing if the
224ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                // exception was due to loss of network connectivity, etc. (i.e. it will wait for
225ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                // network to restore and then request it).
226ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                EasPing.requestPing(amAccount);
227ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            } else {
228400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu                stopServiceIfNoPings();
2295f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            }
2305f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
231ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // TODO: It might be the case that only STATUS_CHANGES_FOUND and
232ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // STATUS_FOLDER_REFRESH_NEEDED need to notifyAll(). Think this through.
233ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            notifyAll();
2345f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
235ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
2365f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    }
237400d8d752257eb65632e8840f5912d933e386c99Yu Ping Hu    private final SyncHandlerSynchronizer mSyncHandlerMap = new SyncHandlerSynchronizer();
2385f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
2395f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    /**
2405f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     * The binder for IEmailService.
2415f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu     */
2425f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    private final IEmailService.Stub mBinder = new IEmailService.Stub() {
243ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu
244ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu        private String getEmailAddressForAccount(final long accountId) {
245ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            final String emailAddress = Utility.getFirstRowString(EmailSyncAdapterService.this,
246ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu                    Account.CONTENT_URI, ACCOUNT_EMAIL_PROJECTION, Account.ID_SELECTION,
247ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu                    new String[] {Long.toString(accountId)}, null, 0);
248ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            if (emailAddress == null) {
249ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu                LogUtils.e(TAG, "Could not find email address for account %d", accountId);
250ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            }
251ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            return emailAddress;
252ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu        }
253ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu
2545f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
2555f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public Bundle validate(final HostAuth hostAuth) {
256942b7d73f2f5b3d6c651e39463e615fe6902a910Scott Kennedy            LogUtils.d(TAG, "IEmailService.validate");
257bc278f1e81ef1d44c28093e830ebe84faa960843Yu Ping Hu            return new EasAccountValidator(EmailSyncAdapterService.this, hostAuth).validate();
2585f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
2595f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
2605f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
261ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        public Bundle autoDiscover(final String username, final String password) {
262942b7d73f2f5b3d6c651e39463e615fe6902a910Scott Kennedy            LogUtils.d(TAG, "IEmailService.autoDiscover");
263ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            return new EasAutoDiscover(EmailSyncAdapterService.this, username, password)
264ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    .doAutodiscover();
2655f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
2665f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
2675f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
2685f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public void updateFolderList(final long accountId) {
269ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            LogUtils.d(TAG, "IEmailService.updateFolderList: %d", accountId);
270ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            final String emailAddress = getEmailAddressForAccount(accountId);
271bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu            if (emailAddress != null) {
272bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu                ContentResolver.requestSync(new android.accounts.Account(
273bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu                        emailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE),
274bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu                        EmailContent.AUTHORITY, new Bundle());
275bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu            }
2765f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
2775f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
2785f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
2795f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public void setLogging(final int flags) {
2805f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            // TODO: fix this?
2815f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            // Protocol logging
2825f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            Eas.setUserDebug(flags);
2835f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            // Sync logging
2845f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            //setUserDebug(flags);
2855f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
2865f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
2875f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
288359b3673e053a4f051997a809d8419c75f02c18bYu Ping Hu        public void loadAttachment(final IEmailServiceCallback callback, final long attachmentId,
289359b3673e053a4f051997a809d8419c75f02c18bYu Ping Hu                final boolean background) {
290c35d2fa94faa0f9abeded869a01108bac2bcedccYu Ping Hu            LogUtils.d(TAG, "IEmailService.loadAttachment: %d", attachmentId);
291da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu            // TODO: Prevent this from happening in parallel with a sync?
292da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu            EasAttachmentLoader.loadAttachment(EmailSyncAdapterService.this, attachmentId,
293da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu                    callback);
2945f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
2955f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
2965f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
2975f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public void sendMeetingResponse(final long messageId, final int response) {
29862c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu            LogUtils.d(TAG, "IEmailService.sendMeetingResponse: %d, %d", messageId, response);
29962c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu            EasMeetingResponder.sendMeetingResponse(EmailSyncAdapterService.this, messageId,
30062c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu                    response);
3015f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
3025f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
3035f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        /**
3045f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         * Delete PIM (calendar, contacts) data for the specified account
3055f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         *
306ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu         * @param emailAddress the email address for the account whose data should be deleted
3075f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu         */
3085f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
309ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu        public void deleteAccountPIMData(final String emailAddress) {
310942b7d73f2f5b3d6c651e39463e615fe6902a910Scott Kennedy            LogUtils.d(TAG, "IEmailService.deleteAccountPIMData");
311ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            if (emailAddress != null) {
312ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu                final Context context = EmailSyncAdapterService.this;
313ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu                EasContactsSyncHandler.wipeAccountFromContentProvider(context, emailAddress);
314ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu                EasCalendarSyncHandler.wipeAccountFromContentProvider(context, emailAddress);
3155f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            }
316ea55e973f5820f03931143f8d2df413c70bf4284Yu Ping Hu            // TODO: Run account reconciler?
3175f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
3185f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
3195f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
3205f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public int searchMessages(final long accountId, final SearchParams searchParams,
3215f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                final long destMailboxId) {
322b3ee6545d55cd02161cb8acf054f3edbec02dacfPaul Westbrook            LogUtils.d(TAG, "IEmailService.searchMessages");
323b3ee6545d55cd02161cb8acf054f3edbec02dacfPaul Westbrook            return Search.searchMessages(EmailSyncAdapterService.this, accountId, searchParams,
3245f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                    destMailboxId);
325e2788afb86984dae29255fd9c7e24c78d90dbdadYu Ping Hu            // TODO: may need an explicit callback to replace the one to IEmailServiceCallback.
3265f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
3275f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
3285f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
3295f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public void sendMail(final long accountId) {}
3305f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
3315f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
3325f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public int getCapabilities(final Account acct) {
3335f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            String easVersion = acct.mProtocolVersion;
3345f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            Double easVersionDouble = 2.5D;
3355f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            if (easVersion != null) {
3365f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                try {
3375f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                    easVersionDouble = Double.parseDouble(easVersion);
3385f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                } catch (NumberFormatException e) {
3395f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                    // Stick with 2.5
3405f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                }
3415f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            }
3425f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            if (easVersionDouble >= 12.0D) {
3435f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                return AccountCapabilities.SYNCABLE_FOLDERS |
3445f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                        AccountCapabilities.SERVER_SEARCH |
3455f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                        AccountCapabilities.FOLDER_SERVER_SEARCH |
3465f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                        AccountCapabilities.SANITIZED_HTML |
3475f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                        AccountCapabilities.SMART_REPLY |
3485f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                        AccountCapabilities.SERVER_SEARCH |
3495928ffc5b48ada2e0edb37d21c8c7c92b5b290b7Yu Ping Hu                        AccountCapabilities.UNDO |
3505928ffc5b48ada2e0edb37d21c8c7c92b5b290b7Yu Ping Hu                        AccountCapabilities.DISCARD_CONVERSATION_DRAFTS;
3515f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            } else {
3525f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                return AccountCapabilities.SYNCABLE_FOLDERS |
3535f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                        AccountCapabilities.SANITIZED_HTML |
3545f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu                        AccountCapabilities.SMART_REPLY |
3555928ffc5b48ada2e0edb37d21c8c7c92b5b290b7Yu Ping Hu                        AccountCapabilities.UNDO |
3565928ffc5b48ada2e0edb37d21c8c7c92b5b290b7Yu Ping Hu                        AccountCapabilities.DISCARD_CONVERSATION_DRAFTS;
3575f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            }
3585f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
3595f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
3605f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
3615f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public void serviceUpdated(final String emailAddress) {
3625f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            // Not required for EAS
3635f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
3645f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
3655f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        // All IEmailService messages below are UNCALLED in Email.
3665f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        // TODO: Remove.
3675f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Deprecated
3685f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
3695f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public int getApiLevel() {
3705f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            return Api.LEVEL;
3715f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
3725f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
3735f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Deprecated
3745f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
3755f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public void startSync(long mailboxId, boolean userRequest, int deltaMessageCount) {}
3765f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
3775f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Deprecated
3785f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
3795f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public void stopSync(long mailboxId) {}
3805f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
3815f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Deprecated
3825f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
3835f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public void loadMore(long messageId) {}
3845f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
3855f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Deprecated
3865f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
3875f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public boolean createFolder(long accountId, String name) {
3885f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            return false;
3895f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
3905f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
3915f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Deprecated
3925f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
3935f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public boolean deleteFolder(long accountId, String name) {
3945f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            return false;
3955f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
3965f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
3975f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Deprecated
3985f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
3995f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public boolean renameFolder(long accountId, String oldName, String newName) {
4005f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            return false;
4015f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
4025f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
4035f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Deprecated
4045f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        @Override
4055f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        public void hostChanged(long accountId) {}
4065f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    };
4075f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
4082674530d1879be7ae2df5105f07a93a5557ec389Marc Blank    public EmailSyncAdapterService() {
4092674530d1879be7ae2df5105f07a93a5557ec389Marc Blank        super();
4102674530d1879be7ae2df5105f07a93a5557ec389Marc Blank    }
4112674530d1879be7ae2df5105f07a93a5557ec389Marc Blank
412ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu    /**
413ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu     * {@link AsyncTask} for restarting pings for all accounts that need it.
414ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu     */
415ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu    private static class RestartPingsTask extends AsyncTask<Void, Void, Void> {
416ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        private static final String PUSH_ACCOUNTS_SELECTION =
417ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                AccountColumns.SYNC_INTERVAL + "=" + Integer.toString(Account.CHECK_INTERVAL_PUSH);
418ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
419ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        private final ContentResolver mContentResolver;
420ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        private final SyncHandlerSynchronizer mSyncHandlerMap;
421ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
422ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        public RestartPingsTask(final ContentResolver contentResolver,
423ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                final SyncHandlerSynchronizer syncHandlerMap) {
424ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            mContentResolver = contentResolver;
425ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            mSyncHandlerMap = syncHandlerMap;
426ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        }
427ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
428ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        @Override
429ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        protected Void doInBackground(Void... params) {
430ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            final Cursor c = mContentResolver.query(Account.CONTENT_URI,
431ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                    Account.CONTENT_PROJECTION, PUSH_ACCOUNTS_SELECTION, null, null);
432ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            if (c != null) {
433ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                try {
434ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                    while (c.moveToNext()) {
435ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                        final Account account = new Account();
436ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                        account.restore(c);
437ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                        mSyncHandlerMap.modifyPing(account);
438ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                    }
439ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                } finally {
440ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                    c.close();
441ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                }
442ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            }
443ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            return null;
444ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        }
445ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu    }
446ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
447ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu    @Override
448ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu    public void onCreate() {
449ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        super.onCreate();
450ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        // Restart push for all accounts that need it.
451ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu        new RestartPingsTask(getContentResolver(), mSyncHandlerMap).executeOnExecutor(
452ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                AsyncTask.THREAD_POOL_EXECUTOR);
453ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu    }
454ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
4559696d7f701599644d1c108863d6195af88da2c30Yu Ping Hu    @Override
4565f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    public IBinder onBind(Intent intent) {
4575f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        if (intent.getAction().equals(Eas.EXCHANGE_SERVICE_INTENT_ACTION)) {
4585f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            return mBinder;
4595f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        }
4605f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu        return super.onBind(intent);
4615f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    }
4625f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
4635f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    @Override
4649696d7f701599644d1c108863d6195af88da2c30Yu Ping Hu    protected AbstractThreadedSyncAdapter newSyncAdapter() {
4659696d7f701599644d1c108863d6195af88da2c30Yu Ping Hu        return new SyncAdapterImpl(this);
4669696d7f701599644d1c108863d6195af88da2c30Yu Ping Hu    }
4679696d7f701599644d1c108863d6195af88da2c30Yu Ping Hu
4685f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    // TODO: Handle cancelSync() appropriately.
4695f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu    private class SyncAdapterImpl extends AbstractThreadedSyncAdapter {
4702674530d1879be7ae2df5105f07a93a5557ec389Marc Blank        public SyncAdapterImpl(Context context) {
4712674530d1879be7ae2df5105f07a93a5557ec389Marc Blank            super(context, true /* autoInitialize */);
4722674530d1879be7ae2df5105f07a93a5557ec389Marc Blank        }
4732674530d1879be7ae2df5105f07a93a5557ec389Marc Blank
4742674530d1879be7ae2df5105f07a93a5557ec389Marc Blank        @Override
475456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu        public void onPerformSync(final android.accounts.Account acct, final Bundle extras,
476456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                final String authority, final ContentProviderClient provider,
477456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                final SyncResult syncResult) {
478456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu            LogUtils.i(TAG, "performSync: extras = %s", extras.toString());
479bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu            TempDirectory.setTempDirectory(EmailSyncAdapterService.this);
480bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu
481c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // TODO: Perform any connectivity checks, bail early if we don't have proper network
482c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // for this sync operation.
4832674530d1879be7ae2df5105f07a93a5557ec389Marc Blank
484c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final Context context = getContext();
485c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final ContentResolver cr = context.getContentResolver();
486c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
487c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // Get the EmailContent Account
488c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final Account account;
489c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final Cursor accountCursor = cr.query(Account.CONTENT_URI, Account.CONTENT_PROJECTION,
490c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    AccountColumns.EMAIL_ADDRESS + "=?", new String[] {acct.name}, null);
4910b90e8d0cebf3e40c894f2e84b8cd3aa82d83765Yu Ping Hu            try {
492c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                if (!accountCursor.moveToFirst()) {
493c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    // Could not load account.
494c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    // TODO: improve error handling.
495c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    return;
4962674530d1879be7ae2df5105f07a93a5557ec389Marc Blank                }
497c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                account = new Account();
498c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                account.restore(accountCursor);
4990b90e8d0cebf3e40c894f2e84b8cd3aa82d83765Yu Ping Hu            } finally {
5000b90e8d0cebf3e40c894f2e84b8cd3aa82d83765Yu Ping Hu                accountCursor.close();
5012674530d1879be7ae2df5105f07a93a5557ec389Marc Blank            }
502ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // Get the mailbox that we want to sync.
503ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // There are four possibilities for Mailbox.SYNC_EXTRA_MAILBOX_ID:
504ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // 1) Mailbox.SYNC_EXTRA_MAILBOX_ID_PUSH_ONLY: Restart push if appropriate.
505ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // 2) Mailbox.SYNC_EXTRA_MAILBOX_ID_ACCOUNT_ONLY: Sync only the account data.
506ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // 3) Not present: Perform a full account sync.
507ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // 4) Non-negative value: It's an actual mailbox id, sync that mailbox only.
508ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            final long mailboxId = extras.getLong(Mailbox.SYNC_EXTRA_MAILBOX_ID, FULL_ACCOUNT_SYNC);
509ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu
510ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // If we're just twiddling the push, we do the lightweight thing and just bail.
511ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            if (mailboxId == Mailbox.SYNC_EXTRA_MAILBOX_ID_PUSH_ONLY) {
512ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                mSyncHandlerMap.modifyPing(account);
513ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                return;
514ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            }
515c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
5165f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            // Do the bookkeeping for starting a sync, including stopping a ping if necessary.
5175f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            mSyncHandlerMap.startSync(account.mId);
5185f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
5195f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            // TODO: Should we refresh the account here? It may have changed while waiting for any
5205f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            // pings to stop. It may not matter since the things that may have been twiddled might
5215f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu            // not affect syncing.
5225f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
523456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu            if (mailboxId == FULL_ACCOUNT_SYNC ||
524456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                    mailboxId == Mailbox.SYNC_EXTRA_MAILBOX_ID_ACCOUNT_ONLY) {
525328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                final EasFolderSync folderSync = new EasFolderSync(context, account);
526328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                folderSync.doFolderSync(syncResult);
52740350a7cea38385bc47eec399ae0d08aeeb01620Yu Ping Hu
528ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu                if (mailboxId == FULL_ACCOUNT_SYNC) {
529456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                    // Full account sync includes all mailboxes that participate in system sync.
530456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                    final Cursor c = Mailbox.getMailboxIdsForSync(cr, account.mId);
531456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                    if (c != null) {
532456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                        try {
533456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                            while (c.moveToNext()) {
534456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                                syncMailbox(context, cr, acct, account, c.getLong(0), extras,
535e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu                                        syncResult, false);
536456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                            }
537456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                        } finally {
538456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                            c.close();
539456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                        }
540456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                    }
541c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
542c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            } else {
543c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                // Sync the mailbox that was explicitly requested.
544e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu                syncMailbox(context, cr, acct, account, mailboxId, extras, syncResult, true);
545c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
5465f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
547ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            // Clean up the bookkeeping, including restarting ping if necessary.
548ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu            mSyncHandlerMap.syncComplete(account);
5495f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu
550c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // TODO: It may make sense to have common error handling here. Two possible mechanisms:
551c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // 1) performSync return value can signal some useful info.
552c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // 2) syncResult can contain useful info.
5532674530d1879be7ae2df5105f07a93a5557ec389Marc Blank        }
554456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu
555e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu        /**
556e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu         * Update the mailbox's sync status with the provider and, if we're finished with the sync,
557e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu         * write the last sync time as well.
558e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu         * @param context Our {@link Context}.
559e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu         * @param mailbox The mailbox whose sync status to update.
560e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu         * @param cv A {@link ContentValues} object to use for updating the provider.
561e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu         * @param syncStatus The status for the current sync.
562e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu         */
563e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu        private void updateMailbox(final Context context, final Mailbox mailbox,
564e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu                final ContentValues cv, final int syncStatus) {
565e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu            cv.put(Mailbox.UI_SYNC_STATUS, syncStatus);
566e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu            if (syncStatus == EmailContent.SYNC_STATUS_NONE) {
567e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu                cv.put(Mailbox.SYNC_TIME, System.currentTimeMillis());
568e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu            }
569e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu            mailbox.update(context, cv);
570e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu        }
571e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu
572456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu        private boolean syncMailbox(final Context context, final ContentResolver cr,
573456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                final android.accounts.Account acct, final Account account, final long mailboxId,
574e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu                final Bundle extras, final SyncResult syncResult, final boolean isMailboxSync) {
575456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu            final Mailbox mailbox = Mailbox.restoreMailboxWithId(context, mailboxId);
576456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu            if (mailbox == null) {
577456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                return false;
578456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu            }
579456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu
5805586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu            final boolean success;
581e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu            // Non-mailbox syncs are whole account syncs initiated by the AccountManager and are
582e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu            // treated as background syncs.
583e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu            // TODO: Push will be treated as "user" syncs, and probably should be background.
5845586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu            final ContentValues cv = new ContentValues(2);
5855586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu            updateMailbox(context, mailbox, cv, isMailboxSync ?
5865586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu                    EmailContent.SYNC_STATUS_USER : EmailContent.SYNC_STATUS_BACKGROUND);
587e2a704dca25a36ff177f9908b047602af8ddffe3Yu Ping Hu
588456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu            if (mailbox.mType == Mailbox.TYPE_OUTBOX) {
589456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                final EasOutboxSyncHandler outboxSyncHandler =
590456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                        new EasOutboxSyncHandler(context, account, mailbox);
591456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                outboxSyncHandler.performSync();
5925586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu                success = true;
5935586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu            } else if(mailbox.isSyncable()) {
594456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                final EasSyncHandler syncHandler = EasSyncHandler.getEasSyncHandler(context, cr,
595456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                        acct, account, mailbox, extras, syncResult);
5965586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu                success = (syncHandler != null);
5975586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu                if (syncHandler != null) {
5985586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu                    syncHandler.performSync();
599456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu                }
6005586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu            } else {
6015586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu                success = false;
602456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu            }
6035586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu            updateMailbox(context, mailbox, cv, EmailContent.SYNC_STATUS_NONE);
6045586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu            return success;
605456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu        }
6062674530d1879be7ae2df5105f07a93a5557ec389Marc Blank    }
6070b90e8d0cebf3e40c894f2e84b8cd3aa82d83765Yu Ping Hu}
608