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