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