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.Context; 22ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.Intent; 23ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.SyncResult; 24ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.os.Bundle; 25ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.os.IBinder; 26dd316c9ade8257b2489c78fa3eb2763c9042b5ddYu Ping Huimport android.os.RemoteException; 276285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Huimport android.text.format.DateUtils; 283eef378426c7c88608f53f5a268baed40259ccf6Alon Albertimport android.util.Log; 29ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu 30c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.provider.Account; 314d8774462ace9a45154b2df418b9f2fe7a9c685dBen Komaloimport com.android.emailcommon.provider.Mailbox; 32fa84f281d166cd7d43ca88adf89751ea9acfc51cAlon Albertimport com.android.emailcommon.service.EmailServiceStatus; 335f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport com.android.emailcommon.service.IEmailService; 345f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Huimport com.android.exchange.Eas; 35942b7d73f2f5b3d6c651e39463e615fe6902a910Scott Kennedyimport com.android.mail.utils.LogUtils; 365f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu 37bbafcf7dbcb92063aa207113451c1d29235bc5ddMarc Blankpublic class EmailSyncAdapterService extends AbstractSyncAdapterService { 385f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu 39110837ebff288a75f9bda067c38e2c46797d99b5Alon Albert private static final String TAG = Eas.LOG_TAG; 405f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu 411bf63ddc8f033de0a818ba969eafcfe89c5d2873Martin Hibdon // The call to ServiceConnection.onServiceConnected is asynchronous to bindService. It's 421bf63ddc8f033de0a818ba969eafcfe89c5d2873Martin Hibdon // possible for that to be delayed if, in which case, a call to onPerformSync 431bf63ddc8f033de0a818ba969eafcfe89c5d2873Martin Hibdon // could occur before we have a connection to the service. 441bf63ddc8f033de0a818ba969eafcfe89c5d2873Martin Hibdon // In onPerformSync, if we don't yet have our EasService, we will wait for up to 10 451bf63ddc8f033de0a818ba969eafcfe89c5d2873Martin Hibdon // seconds for it to appear. If it takes longer than that, we will fail the sync. 461bf63ddc8f033de0a818ba969eafcfe89c5d2873Martin Hibdon private static final long MAX_WAIT_FOR_SERVICE_MS = 10 * DateUtils.SECOND_IN_MILLIS; 471bf63ddc8f033de0a818ba969eafcfe89c5d2873Martin Hibdon 4861ebb38e67421fd122c81f046bf11778b61a2113Martin Hibdon // TODO: Do we need to use this? 49502ae63959c6a6253d05de8716417deef497392cMartin Hibdon private static final long SYNC_ERROR_BACKOFF_MILLIS = 5 * DateUtils.MINUTE_IN_MILLIS; 50502ae63959c6a6253d05de8716417deef497392cMartin Hibdon 515f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu /** 5261ebb38e67421fd122c81f046bf11778b61a2113Martin Hibdon * TODO: restore this functionality. 536285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu * The amount of time between periodic syncs intended to ensure that push hasn't died. 546285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu */ 556285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu private static final long KICK_SYNC_INTERVAL = 566285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu DateUtils.HOUR_IN_MILLIS / DateUtils.SECOND_IN_MILLIS; 570b1a8c91bd3abe4390a7bec47600f96e441185f0Yu Ping Hu /** Controls whether we do a periodic "kick" to restart the ping. */ 582d926648d59ef70d04d832a1ef2d023ff45dfd72Yu Ping Hu private static final boolean SCHEDULE_KICK = true; 590b1a8c91bd3abe4390a7bec47600f96e441185f0Yu Ping Hu 6024e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu private static final Object sSyncAdapterLock = new Object(); 6124e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu private static AbstractThreadedSyncAdapter sSyncAdapter = null; 6224e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu 632674530d1879be7ae2df5105f07a93a5557ec389Marc Blank public EmailSyncAdapterService() { 642674530d1879be7ae2df5105f07a93a5557ec389Marc Blank super(); 652674530d1879be7ae2df5105f07a93a5557ec389Marc Blank } 662674530d1879be7ae2df5105f07a93a5557ec389Marc Blank 67ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu @Override 68ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu public void onCreate() { 69f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.v(TAG, "EmailSyncAdapterService.onCreate()"); 70ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu super.onCreate(); 71f2bfcf5e111fc8e29d2dc9765ef2b1826a7d125dAlon Albert startService(new Intent(this, EmailSyncAdapterService.class)); 72ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu } 73ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu 749696d7f701599644d1c108863d6195af88da2c30Yu Ping Hu @Override 755550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert public void onDestroy() { 76f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.v(TAG, "EmailSyncAdapterService.onDestroy()"); 775550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert super.onDestroy(); 785550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert } 795550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert 805550c7f729db4e1728b53a1d8a73083e756f3805Alon Albert @Override 815f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu public IBinder onBind(Intent intent) { 825f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu return super.onBind(intent); 835f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu } 845f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu 855f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu @Override 8624e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu protected AbstractThreadedSyncAdapter getSyncAdapter() { 8724e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu synchronized (sSyncAdapterLock) { 8824e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu if (sSyncAdapter == null) { 8924e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu sSyncAdapter = new SyncAdapterImpl(this); 9024e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu } 9124e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu return sSyncAdapter; 9224e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu } 939696d7f701599644d1c108863d6195af88da2c30Yu Ping Hu } 949696d7f701599644d1c108863d6195af88da2c30Yu Ping Hu 955f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu // TODO: Handle cancelSync() appropriately. 965f6b6438ebb60e3eb00731ab13083d393a302ed9Yu Ping Hu private class SyncAdapterImpl extends AbstractThreadedSyncAdapter { 972674530d1879be7ae2df5105f07a93a5557ec389Marc Blank public SyncAdapterImpl(Context context) { 982674530d1879be7ae2df5105f07a93a5557ec389Marc Blank super(context, true /* autoInitialize */); 992674530d1879be7ae2df5105f07a93a5557ec389Marc Blank } 1002674530d1879be7ae2df5105f07a93a5557ec389Marc Blank 1012674530d1879be7ae2df5105f07a93a5557ec389Marc Blank @Override 102456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu public void onPerformSync(final android.accounts.Account acct, final Bundle extras, 103456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu final String authority, final ContentProviderClient provider, 104456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu final SyncResult syncResult) { 1053eef378426c7c88608f53f5a268baed40259ccf6Alon Albert if (LogUtils.isLoggable(TAG, Log.DEBUG)) { 106f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.d(TAG, "onPerformSync email: %s, %s", acct.toString(), extras.toString()); 1073eef378426c7c88608f53f5a268baed40259ccf6Alon Albert } else { 108f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.i(TAG, "onPerformSync email: %s", extras.toString()); 1093eef378426c7c88608f53f5a268baed40259ccf6Alon Albert } 110f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon if (!waitForService()) { 111f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon // The service didn't connect, nothing we can do. 112f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon return; 1131bf63ddc8f033de0a818ba969eafcfe89c5d2873Martin Hibdon } 1141bf63ddc8f033de0a818ba969eafcfe89c5d2873Martin Hibdon 115c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // TODO: Perform any connectivity checks, bail early if we don't have proper network 116c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // for this sync operation. 11792c06e3394732f9de61b5f6619800f9ea1a75760Martin Hibdon // FLAG: Do we actually need to do this? I don't think the sync manager will invoke 11892c06e3394732f9de61b5f6619800f9ea1a75760Martin Hibdon // a sync if we don't have good network. 1192674530d1879be7ae2df5105f07a93a5557ec389Marc Blank 120f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon final Account emailAccount = Account.restoreAccountWithAddress( 121f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon EmailSyncAdapterService.this, acct.name); 122db1cd8456a0cf273890cd3da10d0d5f00aadbb45Anthony Lee if (emailAccount == null) { 123db1cd8456a0cf273890cd3da10d0d5f00aadbb45Anthony Lee // There could be a timing issue with onPerformSync() being called and 124db1cd8456a0cf273890cd3da10d0d5f00aadbb45Anthony Lee // the account being removed from our database. 125db1cd8456a0cf273890cd3da10d0d5f00aadbb45Anthony Lee LogUtils.w(TAG, 126db1cd8456a0cf273890cd3da10d0d5f00aadbb45Anthony Lee "onPerformSync() - Could not find an Account, skipping email sync."); 127db1cd8456a0cf273890cd3da10d0d5f00aadbb45Anthony Lee return; 128db1cd8456a0cf273890cd3da10d0d5f00aadbb45Anthony Lee } 12977b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu 130c1e77ad19eb6e815cbb9f944b2e734bd40432928Yu Ping Hu // Push only means this sync request should only refresh the ping (either because 131c1e77ad19eb6e815cbb9f944b2e734bd40432928Yu Ping Hu // settings changed, or we need to restart it for some reason). 132c1e77ad19eb6e815cbb9f944b2e734bd40432928Yu Ping Hu final boolean pushOnly = Mailbox.isPushOnlyExtras(extras); 133c1e77ad19eb6e815cbb9f944b2e734bd40432928Yu Ping Hu 13461ebb38e67421fd122c81f046bf11778b61a2113Martin Hibdon if (pushOnly) { 1353eef378426c7c88608f53f5a268baed40259ccf6Alon Albert LogUtils.d(TAG, "onPerformSync: mailbox push only"); 1361bf63ddc8f033de0a818ba969eafcfe89c5d2873Martin Hibdon try { 137f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon mEasService.pushModify(emailAccount.mId); 1381bf63ddc8f033de0a818ba969eafcfe89c5d2873Martin Hibdon return; 1391bf63ddc8f033de0a818ba969eafcfe89c5d2873Martin Hibdon } catch (final RemoteException re) { 1401bf63ddc8f033de0a818ba969eafcfe89c5d2873Martin Hibdon LogUtils.e(TAG, re, "While trying to pushModify within onPerformSync"); 1411bf63ddc8f033de0a818ba969eafcfe89c5d2873Martin Hibdon // TODO: how to handle this? 1428c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu } 143ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu return; 14461ebb38e67421fd122c81f046bf11778b61a2113Martin Hibdon } else { 14561ebb38e67421fd122c81f046bf11778b61a2113Martin Hibdon try { 146f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon final int result = mEasService.sync(emailAccount.mId, extras); 14761ebb38e67421fd122c81f046bf11778b61a2113Martin Hibdon writeResultToSyncResult(result, syncResult); 1486cb6c70ea47035a27bd1d808babe39a2d1829c8dYu Ping Hu if (syncResult.stats.numAuthExceptions > 0 && 14961ebb38e67421fd122c81f046bf11778b61a2113Martin Hibdon result != EmailServiceStatus.PROVISIONING_ERROR) { 150f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon showAuthNotification(emailAccount.mId, emailAccount.mEmailAddress); 1516cb6c70ea47035a27bd1d808babe39a2d1829c8dYu Ping Hu } 15261ebb38e67421fd122c81f046bf11778b61a2113Martin Hibdon } catch (RemoteException e) { 15361ebb38e67421fd122c81f046bf11778b61a2113Martin Hibdon LogUtils.e(TAG, e, "While trying to pushModify within onPerformSync"); 15497a217631c5540bb7c40b3d184483cc35fe8d762Yu Ping Hu } 1558c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu } 156456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu 157f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.d(TAG, "onPerformSync email: finished"); 15877b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu } 1592cc96b73358378d57c53a45d6da63a77b618a45dYu Ping Hu } 1600b90e8d0cebf3e40c894f2e84b8cd3aa82d83765Yu Ping Hu} 161