1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.exchange.service;
18 
19 import android.content.AbstractThreadedSyncAdapter;
20 import android.content.ContentProviderClient;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.SyncResult;
24 import android.os.Bundle;
25 import android.os.IBinder;
26 import android.os.RemoteException;
27 import android.text.format.DateUtils;
28 import android.util.Log;
29 
30 import com.android.emailcommon.provider.Account;
31 import com.android.emailcommon.provider.Mailbox;
32 import com.android.emailcommon.service.EmailServiceStatus;
33 import com.android.emailcommon.service.IEmailService;
34 import com.android.exchange.Eas;
35 import com.android.mail.utils.LogUtils;
36 
37 public class EmailSyncAdapterService extends AbstractSyncAdapterService {
38 
39     private static final String TAG = Eas.LOG_TAG;
40 
41     private static final Object sSyncAdapterLock = new Object();
42     private static AbstractThreadedSyncAdapter sSyncAdapter = null;
43 
EmailSyncAdapterService()44     public EmailSyncAdapterService() {
45         super();
46     }
47 
48     @Override
onCreate()49     public void onCreate() {
50         LogUtils.v(TAG, "EmailSyncAdapterService.onCreate()");
51         super.onCreate();
52         startService(new Intent(this, EmailSyncAdapterService.class));
53     }
54 
55     @Override
onDestroy()56     public void onDestroy() {
57         LogUtils.v(TAG, "EmailSyncAdapterService.onDestroy()");
58         super.onDestroy();
59     }
60 
61     @Override
onBind(Intent intent)62     public IBinder onBind(Intent intent) {
63         return super.onBind(intent);
64     }
65 
66     @Override
getSyncAdapter()67     protected AbstractThreadedSyncAdapter getSyncAdapter() {
68         synchronized (sSyncAdapterLock) {
69             if (sSyncAdapter == null) {
70                 sSyncAdapter = new SyncAdapterImpl(this);
71             }
72             return sSyncAdapter;
73         }
74     }
75 
76     // TODO: Handle cancelSync() appropriately.
77     private class SyncAdapterImpl extends AbstractThreadedSyncAdapter {
SyncAdapterImpl(Context context)78         public SyncAdapterImpl(Context context) {
79             super(context, true /* autoInitialize */);
80         }
81 
82         @Override
onPerformSync(final android.accounts.Account acct, final Bundle extras, final String authority, final ContentProviderClient provider, final SyncResult syncResult)83         public void onPerformSync(final android.accounts.Account acct, final Bundle extras,
84                 final String authority, final ContentProviderClient provider,
85                 final SyncResult syncResult) {
86             if (LogUtils.isLoggable(TAG, Log.DEBUG)) {
87                 LogUtils.d(TAG, "onPerformSync email: %s, %s", acct.toString(), extras.toString());
88             } else {
89                 LogUtils.i(TAG, "onPerformSync email: %s", extras.toString());
90             }
91             if (!waitForService()) {
92                 // The service didn't connect, nothing we can do.
93                 return;
94             }
95 
96             // TODO: Perform any connectivity checks, bail early if we don't have proper network
97             // for this sync operation.
98             // FLAG: Do we actually need to do this? I don't think the sync manager will invoke
99             // a sync if we don't have good network.
100 
101             final Account emailAccount = Account.restoreAccountWithAddress(
102                     EmailSyncAdapterService.this, acct.name);
103             if (emailAccount == null) {
104                 // There could be a timing issue with onPerformSync() being called and
105                 // the account being removed from our database.
106                 LogUtils.w(TAG,
107                         "onPerformSync() - Could not find an Account, skipping email sync.");
108                 return;
109             }
110 
111             // Push only means this sync request should only refresh the ping (either because
112             // settings changed, or we need to restart it for some reason).
113             final boolean pushOnly = Mailbox.isPushOnlyExtras(extras);
114 
115             if (pushOnly) {
116                 LogUtils.d(TAG, "onPerformSync: mailbox push only");
117                 try {
118                     mEasService.pushModify(emailAccount.mId);
119                     return;
120                 } catch (final RemoteException re) {
121                     LogUtils.e(TAG, re, "While trying to pushModify within onPerformSync");
122                     // TODO: how to handle this?
123                 }
124                 return;
125             } else {
126                 try {
127                     final int result = mEasService.sync(emailAccount.mId, extras);
128                     writeResultToSyncResult(result, syncResult);
129                     if (syncResult.stats.numAuthExceptions > 0 &&
130                             result != EmailServiceStatus.PROVISIONING_ERROR) {
131                         showAuthNotification(emailAccount.mId, emailAccount.mEmailAddress);
132                     }
133                 } catch (RemoteException e) {
134                      LogUtils.e(TAG, e, "While trying to pushModify within onPerformSync");
135                 }
136             }
137 
138             LogUtils.d(TAG, "onPerformSync email: finished");
139         }
140     }
141 }
142