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