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 17package com.android.exchange; 18 19import com.android.email.provider.EmailContent; 20import com.android.email.provider.EmailContent.AccountColumns; 21import com.android.email.provider.EmailContent.Mailbox; 22import com.android.email.provider.EmailContent.MailboxColumns; 23 24import android.accounts.Account; 25import android.accounts.OperationCanceledException; 26import android.app.Service; 27import android.content.AbstractThreadedSyncAdapter; 28import android.content.ContentProviderClient; 29import android.content.ContentResolver; 30import android.content.Context; 31import android.content.Intent; 32import android.content.SyncResult; 33import android.database.Cursor; 34import android.os.Bundle; 35import android.os.IBinder; 36import android.provider.Calendar.Events; 37import android.util.Log; 38 39public 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._SYNC_DIRTY + "=1 AND " + Events._SYNC_ACCOUNT + "=?"; 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 SyncManager to start a calendar 93 * sync when we get the signal from the system 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(EmailContent.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 SyncManager.serviceRequest(mailboxCursor.getLong(ID_SYNC_KEY_MAILBOX_ID), 142 SyncManager.SYNC_UPSYNC); 143 } 144 } finally { 145 mailboxCursor.close(); 146 } 147 } 148 } finally { 149 accountCursor.close(); 150 } 151 } 152}