15862a85e17e81866ca82a9905577931947fbd44eMarc Blank/* 25862a85e17e81866ca82a9905577931947fbd44eMarc Blank * Copyright (C) 2010 The Android Open Source Project 35862a85e17e81866ca82a9905577931947fbd44eMarc Blank * 45862a85e17e81866ca82a9905577931947fbd44eMarc Blank * Licensed under the Apache License, Version 2.0 (the "License"); 55862a85e17e81866ca82a9905577931947fbd44eMarc Blank * you may not use this file except in compliance with the License. 65862a85e17e81866ca82a9905577931947fbd44eMarc Blank * You may obtain a copy of the License at 75862a85e17e81866ca82a9905577931947fbd44eMarc Blank * 85862a85e17e81866ca82a9905577931947fbd44eMarc Blank * http://www.apache.org/licenses/LICENSE-2.0 95862a85e17e81866ca82a9905577931947fbd44eMarc Blank * 105862a85e17e81866ca82a9905577931947fbd44eMarc Blank * Unless required by applicable law or agreed to in writing, software 115862a85e17e81866ca82a9905577931947fbd44eMarc Blank * distributed under the License is distributed on an "AS IS" BASIS, 125862a85e17e81866ca82a9905577931947fbd44eMarc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135862a85e17e81866ca82a9905577931947fbd44eMarc Blank * See the License for the specific language governing permissions and 145862a85e17e81866ca82a9905577931947fbd44eMarc Blank * limitations under the License. 155862a85e17e81866ca82a9905577931947fbd44eMarc Blank */ 165862a85e17e81866ca82a9905577931947fbd44eMarc Blank 17bbafcf7dbcb92063aa207113451c1d29235bc5ddMarc Blankpackage com.android.exchange.service; 185862a85e17e81866ca82a9905577931947fbd44eMarc Blank 195862a85e17e81866ca82a9905577931947fbd44eMarc Blankimport android.content.AbstractThreadedSyncAdapter; 205862a85e17e81866ca82a9905577931947fbd44eMarc Blankimport android.content.ContentProviderClient; 215862a85e17e81866ca82a9905577931947fbd44eMarc Blankimport android.content.ContentResolver; 225862a85e17e81866ca82a9905577931947fbd44eMarc Blankimport android.content.Context; 23f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdonimport android.content.ServiceConnection; 245862a85e17e81866ca82a9905577931947fbd44eMarc Blankimport android.content.SyncResult; 255862a85e17e81866ca82a9905577931947fbd44eMarc Blankimport android.database.Cursor; 265862a85e17e81866ca82a9905577931947fbd44eMarc Blankimport android.os.Bundle; 27f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdonimport android.os.RemoteException; 28693ed7fdd5a7ec7af87d105b76267c78a8acc3dbRoboErikimport android.provider.CalendarContract.Events; 293eef378426c7c88608f53f5a268baed40259ccf6Alon Albertimport android.util.Log; 305862a85e17e81866ca82a9905577931947fbd44eMarc Blank 31f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdonimport com.android.emailcommon.provider.Account; 327372782488977df778a33d990401ce9e397f646bMarc Blankimport com.android.emailcommon.provider.EmailContent.MailboxColumns; 337372782488977df778a33d990401ce9e397f646bMarc Blankimport com.android.emailcommon.provider.Mailbox; 34f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdonimport com.android.emailcommon.service.EmailServiceStatus; 35bbafcf7dbcb92063aa207113451c1d29235bc5ddMarc Blankimport com.android.exchange.Eas; 36942b7d73f2f5b3d6c651e39463e615fe6902a910Scott Kennedyimport com.android.mail.utils.LogUtils; 377372782488977df778a33d990401ce9e397f646bMarc Blank 38bbafcf7dbcb92063aa207113451c1d29235bc5ddMarc Blankpublic class CalendarSyncAdapterService extends AbstractSyncAdapterService { 39f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon private static final String TAG = LogUtils.TAG; 405862a85e17e81866ca82a9905577931947fbd44eMarc Blank private static final String ACCOUNT_AND_TYPE_CALENDAR = 415862a85e17e81866ca82a9905577931947fbd44eMarc Blank MailboxColumns.ACCOUNT_KEY + "=? AND " + MailboxColumns.TYPE + '=' + Mailbox.TYPE_CALENDAR; 426146169557f782f0f51fd19f839bdebc6e1fdaabMarc Blank private static final String DIRTY_IN_ACCOUNT = 439e86eb14c6e1f7d7730f8ca6953fdfd95fe2b143RoboErik Events.DIRTY + "=1 AND " + Events.ACCOUNT_NAME + "=?"; 445862a85e17e81866ca82a9905577931947fbd44eMarc Blank 4524e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu private static final Object sSyncAdapterLock = new Object(); 4624e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu private static AbstractThreadedSyncAdapter sSyncAdapter = null; 4724e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu 485862a85e17e81866ca82a9905577931947fbd44eMarc Blank public CalendarSyncAdapterService() { 495862a85e17e81866ca82a9905577931947fbd44eMarc Blank super(); 505862a85e17e81866ca82a9905577931947fbd44eMarc Blank } 515862a85e17e81866ca82a9905577931947fbd44eMarc Blank 529696d7f701599644d1c108863d6195af88da2c30Yu Ping Hu @Override 5324e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu protected AbstractThreadedSyncAdapter getSyncAdapter() { 5424e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu synchronized (sSyncAdapterLock) { 5524e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu if (sSyncAdapter == null) { 5624e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu sSyncAdapter = new SyncAdapterImpl(this); 5724e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu } 5824e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu return sSyncAdapter; 5924e1187f8511d301fa586759cd1b3bd5ad2ccf41Yu Ping Hu } 609696d7f701599644d1c108863d6195af88da2c30Yu Ping Hu } 619696d7f701599644d1c108863d6195af88da2c30Yu Ping Hu 62f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon private class SyncAdapterImpl extends AbstractThreadedSyncAdapter { 635862a85e17e81866ca82a9905577931947fbd44eMarc Blank public SyncAdapterImpl(Context context) { 645862a85e17e81866ca82a9905577931947fbd44eMarc Blank super(context, true /* autoInitialize */); 655862a85e17e81866ca82a9905577931947fbd44eMarc Blank } 665862a85e17e81866ca82a9905577931947fbd44eMarc Blank 675862a85e17e81866ca82a9905577931947fbd44eMarc Blank @Override 68f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon public void onPerformSync(android.accounts.Account acct, Bundle extras, 695862a85e17e81866ca82a9905577931947fbd44eMarc Blank String authority, ContentProviderClient provider, SyncResult syncResult) { 703eef378426c7c88608f53f5a268baed40259ccf6Alon Albert if (LogUtils.isLoggable(TAG, Log.DEBUG)) { 71f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.d(TAG, "onPerformSync calendar: %s, %s", 72f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon acct.toString(), extras.toString()); 733eef378426c7c88608f53f5a268baed40259ccf6Alon Albert } else { 74f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.i(TAG, "onPerformSync calendar: %s", extras.toString()); 753eef378426c7c88608f53f5a268baed40259ccf6Alon Albert } 765862a85e17e81866ca82a9905577931947fbd44eMarc Blank 77f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon if (!waitForService()) { 78f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon // The service didn't connect, nothing we can do. 7999d00f13bbbb02bb4db4fa71afb700eb178a2238Paul Westbrook return; 8099d00f13bbbb02bb4db4fa71afb700eb178a2238Paul Westbrook } 81f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon final Account emailAccount = Account.restoreAccountWithAddress( 82f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon CalendarSyncAdapterService.this, acct.name); 83db1cd8456a0cf273890cd3da10d0d5f00aadbb45Anthony Lee if (emailAccount == null) { 84db1cd8456a0cf273890cd3da10d0d5f00aadbb45Anthony Lee // There could be a timing issue with onPerformSync() being called and 85db1cd8456a0cf273890cd3da10d0d5f00aadbb45Anthony Lee // the account being removed from our database. 86db1cd8456a0cf273890cd3da10d0d5f00aadbb45Anthony Lee LogUtils.w(TAG, 87db1cd8456a0cf273890cd3da10d0d5f00aadbb45Anthony Lee "onPerformSync() - Could not find an Account, skipping calendar sync."); 88db1cd8456a0cf273890cd3da10d0d5f00aadbb45Anthony Lee return; 89db1cd8456a0cf273890cd3da10d0d5f00aadbb45Anthony Lee } 90f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon 91f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon // TODO: is this still needed? 92f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD)) { 93f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon final Cursor c = getContentResolver().query(Events.CONTENT_URI, 94f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon new String[] {Events._ID}, DIRTY_IN_ACCOUNT, 95f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon new String[] {acct.name}, null); 96f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon if (c == null) { 97f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.e(TAG, "Null changes cursor in CalendarSyncAdapterService"); 985862a85e17e81866ca82a9905577931947fbd44eMarc Blank return; 995862a85e17e81866ca82a9905577931947fbd44eMarc Blank } 100f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon try { 101f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon if (!c.moveToFirst()) { 102f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon if (Eas.USER_LOG) { 103f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.d(TAG, "No changes for " + acct.name); 104f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon } 105f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon return; 106f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon } 107f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon } finally { 108f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon c.close(); 109f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon } 1105862a85e17e81866ca82a9905577931947fbd44eMarc Blank } 1115862a85e17e81866ca82a9905577931947fbd44eMarc Blank 112f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon // TODO: move this logic to some common place. 113f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon // Push only means this sync request should only refresh the ping (either because 114f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon // settings changed, or we need to restart it for some reason). 115f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon final boolean pushOnly = Mailbox.isPushOnlyExtras(extras); 116f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon 117f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon if (pushOnly) { 118f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.d(TAG, "onPerformSync calendar: mailbox push only"); 119f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon if (mEasService != null) { 120f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon try { 121f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon mEasService.pushModify(emailAccount.mId); 122f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon return; 123f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon } catch (final RemoteException re) { 124f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.e(TAG, re, "While trying to pushModify within onPerformSync"); 125f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon // TODO: how to handle this? 126f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon } 127f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon } 128f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon return; 129f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon } else { 130f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon try { 131f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon final int result = mEasService.sync(emailAccount.mId, extras); 132f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon writeResultToSyncResult(result, syncResult); 133f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon if (syncResult.stats.numAuthExceptions > 0 && 134f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon result != EmailServiceStatus.PROVISIONING_ERROR) { 135f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon showAuthNotification(emailAccount.mId, emailAccount.mEmailAddress); 136f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon } 137f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon } catch (RemoteException e) { 138f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.e(TAG, e, "While trying to pushModify within onPerformSync"); 139f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon } 140f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon } 141f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon 142f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.d(TAG, "onPerformSync calendar: finished"); 14377b653fa1b5baabddb76802f0333c78f80c29aceYu Ping Hu } 144de96f1cd298fd7cfb9766a71b0a8e05c955ec8dbMartin Hibdon } 1456e66ab513197793c34f5dcda159043da39224ff9Yu Ping Hu} 146