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; 18 19 import android.accounts.Account; 20 import android.accounts.OperationCanceledException; 21 import android.app.Service; 22 import android.content.AbstractThreadedSyncAdapter; 23 import android.content.ContentProviderClient; 24 import android.content.ContentResolver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.SyncResult; 28 import android.database.Cursor; 29 import android.os.Bundle; 30 import android.os.IBinder; 31 import android.provider.CalendarContract.Events; 32 import android.util.Log; 33 34 import com.android.emailcommon.provider.EmailContent; 35 import com.android.emailcommon.provider.EmailContent.AccountColumns; 36 import com.android.emailcommon.provider.EmailContent.MailboxColumns; 37 import com.android.emailcommon.provider.Mailbox; 38 39 public class CalendarSyncAdapterService extends Service { 40 private static final String TAG = "EAS CalendarSyncAdapterService"; 41 private static SyncAdapterImpl sSyncAdapter = null; 42 private static final Object sSyncAdapterLock = new Object(); 43 44 private static final String ACCOUNT_AND_TYPE_CALENDAR = 45 MailboxColumns.ACCOUNT_KEY + "=? AND " + MailboxColumns.TYPE + '=' + Mailbox.TYPE_CALENDAR; 46 private static final String DIRTY_IN_ACCOUNT = 47 Events.DIRTY + "=1 AND " + Events.ACCOUNT_NAME + "=?"; 48 private static final String[] ID_SYNC_KEY_PROJECTION = 49 new String[] {MailboxColumns.ID, MailboxColumns.SYNC_KEY}; 50 private static final int ID_SYNC_KEY_MAILBOX_ID = 0; 51 private static final int ID_SYNC_KEY_SYNC_KEY = 1; 52 53 public CalendarSyncAdapterService() { 54 super(); 55 } 56 57 private static class SyncAdapterImpl extends AbstractThreadedSyncAdapter { 58 private Context mContext; 59 60 public SyncAdapterImpl(Context context) { 61 super(context, true /* autoInitialize */); 62 mContext = context; 63 } 64 65 @Override 66 public void onPerformSync(Account account, Bundle extras, 67 String authority, ContentProviderClient provider, SyncResult syncResult) { 68 try { 69 CalendarSyncAdapterService.performSync(mContext, account, extras, 70 authority, provider, syncResult); 71 } catch (OperationCanceledException e) { 72 } 73 } 74 } 75 76 @Override 77 public void onCreate() { 78 super.onCreate(); 79 synchronized (sSyncAdapterLock) { 80 if (sSyncAdapter == null) { 81 sSyncAdapter = new SyncAdapterImpl(getApplicationContext()); 82 } 83 } 84 } 85 86 @Override 87 public IBinder onBind(Intent intent) { 88 return sSyncAdapter.getSyncAdapterBinder(); 89 } 90 91 /** 92 * Partial integration with system SyncManager; we tell our EAS ExchangeService to start a 93 * calendar sync when we get the signal from SyncManager. 94 * The missing piece at this point is integration with the push/ping mechanism in EAS; this will 95 * be put in place at a later time. 96 */ 97 private static void performSync(Context context, Account account, Bundle extras, 98 String authority, ContentProviderClient provider, SyncResult syncResult) 99 throws OperationCanceledException { 100 ContentResolver cr = context.getContentResolver(); 101 boolean logging = Eas.USER_LOG; 102 if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD)) { 103 Cursor c = cr.query(Events.CONTENT_URI, 104 new String[] {Events._ID}, DIRTY_IN_ACCOUNT, new String[] {account.name}, null); 105 try { 106 if (!c.moveToFirst()) { 107 if (logging) { 108 Log.d(TAG, "No changes for " + account.name); 109 } 110 return; 111 } 112 } finally { 113 c.close(); 114 } 115 } 116 117 // Find the (EmailProvider) account associated with this email address 118 Cursor accountCursor = 119 cr.query(com.android.emailcommon.provider.Account.CONTENT_URI, 120 EmailContent.ID_PROJECTION, AccountColumns.EMAIL_ADDRESS + "=?", 121 new String[] {account.name}, null); 122 try { 123 if (accountCursor.moveToFirst()) { 124 long accountId = accountCursor.getLong(0); 125 // Now, find the calendar mailbox associated with the account 126 Cursor mailboxCursor = cr.query(Mailbox.CONTENT_URI, ID_SYNC_KEY_PROJECTION, 127 ACCOUNT_AND_TYPE_CALENDAR, new String[] {Long.toString(accountId)}, null); 128 try { 129 if (mailboxCursor.moveToFirst()) { 130 if (logging) { 131 Log.d(TAG, "Upload sync requested for " + account.name); 132 } 133 String syncKey = mailboxCursor.getString(ID_SYNC_KEY_SYNC_KEY); 134 if ((syncKey == null) || (syncKey.equals("0"))) { 135 if (logging) { 136 Log.d(TAG, "Can't sync; mailbox in initial state"); 137 } 138 return; 139 } 140 // Ask for a sync from our sync manager 141 ExchangeService.serviceRequest(mailboxCursor.getLong( 142 ID_SYNC_KEY_MAILBOX_ID), ExchangeService.SYNC_UPSYNC); 143 } 144 } finally { 145 mailboxCursor.close(); 146 } 147 } 148 } finally { 149 accountCursor.close(); 150 } 151 } 152 }