PopImapSyncAdapterService.java revision 1b8e0fa23f6e9957f0b8753dd3f5b95d3f5d98ea
15c523858385176c33a7456bb84035de78552d22dMarc Blank/* 25c523858385176c33a7456bb84035de78552d22dMarc Blank * Copyright (C) 2010 The Android Open Source Project 35c523858385176c33a7456bb84035de78552d22dMarc Blank * 45c523858385176c33a7456bb84035de78552d22dMarc Blank * Licensed under the Apache License, Version 2.0 (the "License"); 55c523858385176c33a7456bb84035de78552d22dMarc Blank * you may not use this file except in compliance with the License. 65c523858385176c33a7456bb84035de78552d22dMarc Blank * You may obtain a copy of the License at 75c523858385176c33a7456bb84035de78552d22dMarc Blank * 85c523858385176c33a7456bb84035de78552d22dMarc Blank * http://www.apache.org/licenses/LICENSE-2.0 95c523858385176c33a7456bb84035de78552d22dMarc Blank * 105c523858385176c33a7456bb84035de78552d22dMarc Blank * Unless required by applicable law or agreed to in writing, software 115c523858385176c33a7456bb84035de78552d22dMarc Blank * distributed under the License is distributed on an "AS IS" BASIS, 125c523858385176c33a7456bb84035de78552d22dMarc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135c523858385176c33a7456bb84035de78552d22dMarc Blank * See the License for the specific language governing permissions and 145c523858385176c33a7456bb84035de78552d22dMarc Blank * limitations under the License. 155c523858385176c33a7456bb84035de78552d22dMarc Blank */ 165c523858385176c33a7456bb84035de78552d22dMarc Blank 175c523858385176c33a7456bb84035de78552d22dMarc Blankpackage com.android.email.service; 185c523858385176c33a7456bb84035de78552d22dMarc Blank 195c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.app.Service; 205c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.content.AbstractThreadedSyncAdapter; 215c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.content.ContentProviderClient; 225c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.content.ContentResolver; 235c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.content.ContentUris; 245c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.content.ContentValues; 255c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.content.Context; 265c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.content.Intent; 275c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.content.SyncResult; 285c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.database.Cursor; 295c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.net.Uri; 305c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.os.Bundle; 315c523858385176c33a7456bb84035de78552d22dMarc Blankimport android.os.IBinder; 325c523858385176c33a7456bb84035de78552d22dMarc Blank 335c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.email.R; 345c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.emailcommon.TempDirectory; 355c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.emailcommon.mail.MessagingException; 365c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.emailcommon.provider.Account; 375c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.emailcommon.provider.EmailContent; 385c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.emailcommon.provider.EmailContent.AccountColumns; 395c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.emailcommon.provider.EmailContent.Message; 405c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.emailcommon.provider.Mailbox; 415c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.emailcommon.service.EmailServiceProxy; 42560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedyimport com.android.mail.utils.LogUtils; 435c523858385176c33a7456bb84035de78552d22dMarc Blank 445c523858385176c33a7456bb84035de78552d22dMarc Blankimport java.util.ArrayList; 455c523858385176c33a7456bb84035de78552d22dMarc Blank 465c523858385176c33a7456bb84035de78552d22dMarc Blankpublic class PopImapSyncAdapterService extends Service { 47d1a87bc02d65dde9e635848531e09aadc79ff538Paul Westbrook private static final String TAG = "PopImapSyncService"; 481484c6663db7b194eea9341ec8ecab6b44985c7cYu Ping Hu private SyncAdapterImpl mSyncAdapter = null; 495c523858385176c33a7456bb84035de78552d22dMarc Blank 505c523858385176c33a7456bb84035de78552d22dMarc Blank public PopImapSyncAdapterService() { 515c523858385176c33a7456bb84035de78552d22dMarc Blank super(); 525c523858385176c33a7456bb84035de78552d22dMarc Blank } 535c523858385176c33a7456bb84035de78552d22dMarc Blank 545c523858385176c33a7456bb84035de78552d22dMarc Blank private static class SyncAdapterImpl extends AbstractThreadedSyncAdapter { 555c523858385176c33a7456bb84035de78552d22dMarc Blank public SyncAdapterImpl(Context context) { 565c523858385176c33a7456bb84035de78552d22dMarc Blank super(context, true /* autoInitialize */); 575c523858385176c33a7456bb84035de78552d22dMarc Blank } 585c523858385176c33a7456bb84035de78552d22dMarc Blank 595c523858385176c33a7456bb84035de78552d22dMarc Blank @Override 605c523858385176c33a7456bb84035de78552d22dMarc Blank public void onPerformSync(android.accounts.Account account, Bundle extras, 615c523858385176c33a7456bb84035de78552d22dMarc Blank String authority, ContentProviderClient provider, SyncResult syncResult) { 621b8e0fa23f6e9957f0b8753dd3f5b95d3f5d98eaScott Kennedy PopImapSyncAdapterService.performSync(getContext(), account, extras, provider, 631b8e0fa23f6e9957f0b8753dd3f5b95d3f5d98eaScott Kennedy syncResult); 645c523858385176c33a7456bb84035de78552d22dMarc Blank } 655c523858385176c33a7456bb84035de78552d22dMarc Blank } 665c523858385176c33a7456bb84035de78552d22dMarc Blank 675c523858385176c33a7456bb84035de78552d22dMarc Blank @Override 685c523858385176c33a7456bb84035de78552d22dMarc Blank public void onCreate() { 695c523858385176c33a7456bb84035de78552d22dMarc Blank super.onCreate(); 701484c6663db7b194eea9341ec8ecab6b44985c7cYu Ping Hu mSyncAdapter = new SyncAdapterImpl(getApplicationContext()); 715c523858385176c33a7456bb84035de78552d22dMarc Blank } 725c523858385176c33a7456bb84035de78552d22dMarc Blank 735c523858385176c33a7456bb84035de78552d22dMarc Blank @Override 745c523858385176c33a7456bb84035de78552d22dMarc Blank public IBinder onBind(Intent intent) { 751484c6663db7b194eea9341ec8ecab6b44985c7cYu Ping Hu return mSyncAdapter.getSyncAdapterBinder(); 765c523858385176c33a7456bb84035de78552d22dMarc Blank } 775c523858385176c33a7456bb84035de78552d22dMarc Blank 785c523858385176c33a7456bb84035de78552d22dMarc Blank /** 795c523858385176c33a7456bb84035de78552d22dMarc Blank * @return whether or not this mailbox retrieves its data from the server (as opposed to just 805c523858385176c33a7456bb84035de78552d22dMarc Blank * a local mailbox that is never synced). 815c523858385176c33a7456bb84035de78552d22dMarc Blank */ 825c523858385176c33a7456bb84035de78552d22dMarc Blank private static boolean loadsFromServer(Context context, Mailbox m, String protocol) { 835c523858385176c33a7456bb84035de78552d22dMarc Blank String legacyImapProtocol = context.getString(R.string.protocol_legacy_imap); 8454347010fbbdd3ae1dea5b0e282514c640e16a5fMarc Blank String pop3Protocol = context.getString(R.string.protocol_pop3); 855c523858385176c33a7456bb84035de78552d22dMarc Blank if (legacyImapProtocol.equals(protocol)) { 865c523858385176c33a7456bb84035de78552d22dMarc Blank // TODO: actually use a sync flag when creating the mailboxes. Right now we use an 875c523858385176c33a7456bb84035de78552d22dMarc Blank // approximation for IMAP. 885c523858385176c33a7456bb84035de78552d22dMarc Blank return m.mType != Mailbox.TYPE_DRAFTS 895c523858385176c33a7456bb84035de78552d22dMarc Blank && m.mType != Mailbox.TYPE_OUTBOX 905c523858385176c33a7456bb84035de78552d22dMarc Blank && m.mType != Mailbox.TYPE_SEARCH; 915c523858385176c33a7456bb84035de78552d22dMarc Blank 9254347010fbbdd3ae1dea5b0e282514c640e16a5fMarc Blank } else if (pop3Protocol.equals(protocol)) { 935c523858385176c33a7456bb84035de78552d22dMarc Blank return Mailbox.TYPE_INBOX == m.mType; 945c523858385176c33a7456bb84035de78552d22dMarc Blank } 955c523858385176c33a7456bb84035de78552d22dMarc Blank 965c523858385176c33a7456bb84035de78552d22dMarc Blank return false; 975c523858385176c33a7456bb84035de78552d22dMarc Blank } 985c523858385176c33a7456bb84035de78552d22dMarc Blank 995c523858385176c33a7456bb84035de78552d22dMarc Blank private static void sync(Context context, long mailboxId, SyncResult syncResult, 10017d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu boolean uiRefresh, int deltaMessageCount) { 1015c523858385176c33a7456bb84035de78552d22dMarc Blank TempDirectory.setTempDirectory(context); 1025c523858385176c33a7456bb84035de78552d22dMarc Blank Mailbox mailbox = Mailbox.restoreMailboxWithId(context, mailboxId); 1035c523858385176c33a7456bb84035de78552d22dMarc Blank if (mailbox == null) return; 1045c523858385176c33a7456bb84035de78552d22dMarc Blank Account account = Account.restoreAccountWithId(context, mailbox.mAccountKey); 1055c523858385176c33a7456bb84035de78552d22dMarc Blank if (account == null) return; 1065c523858385176c33a7456bb84035de78552d22dMarc Blank ContentResolver resolver = context.getContentResolver(); 1075c523858385176c33a7456bb84035de78552d22dMarc Blank String protocol = account.getProtocol(context); 1085c523858385176c33a7456bb84035de78552d22dMarc Blank if ((mailbox.mType != Mailbox.TYPE_OUTBOX) && 1095c523858385176c33a7456bb84035de78552d22dMarc Blank !loadsFromServer(context, mailbox, protocol)) { 1105c523858385176c33a7456bb84035de78552d22dMarc Blank // This is an update to a message in a non-syncing mailbox; delete this from the 1115c523858385176c33a7456bb84035de78552d22dMarc Blank // updates table and return 1125c523858385176c33a7456bb84035de78552d22dMarc Blank resolver.delete(Message.UPDATED_CONTENT_URI, Message.MAILBOX_KEY + "=?", 1135c523858385176c33a7456bb84035de78552d22dMarc Blank new String[] {Long.toString(mailbox.mId)}); 1145c523858385176c33a7456bb84035de78552d22dMarc Blank return; 1155c523858385176c33a7456bb84035de78552d22dMarc Blank } 116560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.d(TAG, "Mailbox: " + mailbox.mDisplayName); 1175c523858385176c33a7456bb84035de78552d22dMarc Blank 1185c523858385176c33a7456bb84035de78552d22dMarc Blank Uri mailboxUri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailboxId); 1195c523858385176c33a7456bb84035de78552d22dMarc Blank ContentValues values = new ContentValues(); 1205c523858385176c33a7456bb84035de78552d22dMarc Blank // Set mailbox sync state 1215c523858385176c33a7456bb84035de78552d22dMarc Blank values.put(Mailbox.UI_SYNC_STATUS, 1225c523858385176c33a7456bb84035de78552d22dMarc Blank uiRefresh ? EmailContent.SYNC_STATUS_USER : EmailContent.SYNC_STATUS_BACKGROUND); 1235c523858385176c33a7456bb84035de78552d22dMarc Blank resolver.update(mailboxUri, values, null, null); 1245c523858385176c33a7456bb84035de78552d22dMarc Blank try { 1255c523858385176c33a7456bb84035de78552d22dMarc Blank try { 1265c523858385176c33a7456bb84035de78552d22dMarc Blank String legacyImapProtocol = context.getString(R.string.protocol_legacy_imap); 1275c523858385176c33a7456bb84035de78552d22dMarc Blank if (mailbox.mType == Mailbox.TYPE_OUTBOX) { 1285c523858385176c33a7456bb84035de78552d22dMarc Blank EmailServiceStub.sendMailImpl(context, account.mId); 1295c523858385176c33a7456bb84035de78552d22dMarc Blank } else if (protocol.equals(legacyImapProtocol)) { 13017d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu ImapService.synchronizeMailboxSynchronous(context, account, mailbox, 13117d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu deltaMessageCount); 1325c523858385176c33a7456bb84035de78552d22dMarc Blank } else { 13317d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu Pop3Service.synchronizeMailboxSynchronous(context, account, mailbox, 13417d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu deltaMessageCount); 1355c523858385176c33a7456bb84035de78552d22dMarc Blank } 1365c523858385176c33a7456bb84035de78552d22dMarc Blank } catch (MessagingException e) { 1375c523858385176c33a7456bb84035de78552d22dMarc Blank int cause = e.getExceptionType(); 1385c523858385176c33a7456bb84035de78552d22dMarc Blank switch(cause) { 1395c523858385176c33a7456bb84035de78552d22dMarc Blank case MessagingException.IOERROR: 1405c523858385176c33a7456bb84035de78552d22dMarc Blank syncResult.stats.numIoExceptions++; 1415c523858385176c33a7456bb84035de78552d22dMarc Blank break; 1425c523858385176c33a7456bb84035de78552d22dMarc Blank case MessagingException.AUTHENTICATION_FAILED: 1435c523858385176c33a7456bb84035de78552d22dMarc Blank syncResult.stats.numAuthExceptions++; 1445c523858385176c33a7456bb84035de78552d22dMarc Blank break; 1455c523858385176c33a7456bb84035de78552d22dMarc Blank } 1465c523858385176c33a7456bb84035de78552d22dMarc Blank } 1475c523858385176c33a7456bb84035de78552d22dMarc Blank } finally { 14817d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu // Always clear our sync state and update sync time. 1495c523858385176c33a7456bb84035de78552d22dMarc Blank values.put(Mailbox.UI_SYNC_STATUS, EmailContent.SYNC_STATUS_NONE); 15017d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu values.put(Mailbox.SYNC_TIME, System.currentTimeMillis()); 1515c523858385176c33a7456bb84035de78552d22dMarc Blank resolver.update(mailboxUri, values, null, null); 1525c523858385176c33a7456bb84035de78552d22dMarc Blank } 1535c523858385176c33a7456bb84035de78552d22dMarc Blank } 1545c523858385176c33a7456bb84035de78552d22dMarc Blank 1555c523858385176c33a7456bb84035de78552d22dMarc Blank /** 1565c523858385176c33a7456bb84035de78552d22dMarc Blank * Partial integration with system SyncManager; we initiate manual syncs upon request 1575c523858385176c33a7456bb84035de78552d22dMarc Blank */ 1585c523858385176c33a7456bb84035de78552d22dMarc Blank private static void performSync(Context context, android.accounts.Account account, 1591b8e0fa23f6e9957f0b8753dd3f5b95d3f5d98eaScott Kennedy Bundle extras, ContentProviderClient provider, SyncResult syncResult) { 1605c523858385176c33a7456bb84035de78552d22dMarc Blank // Find an EmailProvider account with the Account's email address 1615c523858385176c33a7456bb84035de78552d22dMarc Blank Cursor c = null; 1625c523858385176c33a7456bb84035de78552d22dMarc Blank try { 1635c523858385176c33a7456bb84035de78552d22dMarc Blank c = provider.query(com.android.emailcommon.provider.Account.CONTENT_URI, 1645c523858385176c33a7456bb84035de78552d22dMarc Blank Account.CONTENT_PROJECTION, AccountColumns.EMAIL_ADDRESS + "=?", 1655c523858385176c33a7456bb84035de78552d22dMarc Blank new String[] {account.name}, null); 1665c523858385176c33a7456bb84035de78552d22dMarc Blank if (c != null && c.moveToNext()) { 1675c523858385176c33a7456bb84035de78552d22dMarc Blank Account acct = new Account(); 1685c523858385176c33a7456bb84035de78552d22dMarc Blank acct.restore(c); 1695c523858385176c33a7456bb84035de78552d22dMarc Blank if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD)) { 170560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.d(TAG, "Upload sync request for " + acct.mDisplayName); 1715c523858385176c33a7456bb84035de78552d22dMarc Blank // See if any boxes have mail... 1725c523858385176c33a7456bb84035de78552d22dMarc Blank ArrayList<Long> mailboxesToUpdate; 1735c523858385176c33a7456bb84035de78552d22dMarc Blank Cursor updatesCursor = provider.query(Message.UPDATED_CONTENT_URI, 1745c523858385176c33a7456bb84035de78552d22dMarc Blank new String[] {Message.MAILBOX_KEY}, 1755c523858385176c33a7456bb84035de78552d22dMarc Blank Message.ACCOUNT_KEY + "=?", 1765c523858385176c33a7456bb84035de78552d22dMarc Blank new String[] {Long.toString(acct.mId)}, 1775c523858385176c33a7456bb84035de78552d22dMarc Blank null); 1785c523858385176c33a7456bb84035de78552d22dMarc Blank try { 1795c523858385176c33a7456bb84035de78552d22dMarc Blank if ((updatesCursor == null) || (updatesCursor.getCount() == 0)) return; 1805c523858385176c33a7456bb84035de78552d22dMarc Blank mailboxesToUpdate = new ArrayList<Long>(); 1815c523858385176c33a7456bb84035de78552d22dMarc Blank while (updatesCursor.moveToNext()) { 1825c523858385176c33a7456bb84035de78552d22dMarc Blank Long mailboxId = updatesCursor.getLong(0); 1835c523858385176c33a7456bb84035de78552d22dMarc Blank if (!mailboxesToUpdate.contains(mailboxId)) { 1845c523858385176c33a7456bb84035de78552d22dMarc Blank mailboxesToUpdate.add(mailboxId); 1855c523858385176c33a7456bb84035de78552d22dMarc Blank } 1865c523858385176c33a7456bb84035de78552d22dMarc Blank } 1875c523858385176c33a7456bb84035de78552d22dMarc Blank } finally { 1885c523858385176c33a7456bb84035de78552d22dMarc Blank if (updatesCursor != null) { 1895c523858385176c33a7456bb84035de78552d22dMarc Blank updatesCursor.close(); 1905c523858385176c33a7456bb84035de78552d22dMarc Blank } 1915c523858385176c33a7456bb84035de78552d22dMarc Blank } 1925c523858385176c33a7456bb84035de78552d22dMarc Blank for (long mailboxId: mailboxesToUpdate) { 19317d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu sync(context, mailboxId, syncResult, false, 0); 1945c523858385176c33a7456bb84035de78552d22dMarc Blank } 1955c523858385176c33a7456bb84035de78552d22dMarc Blank } else { 196560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.d(TAG, "Sync request for " + acct.mDisplayName); 197560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.d(TAG, extras.toString()); 1989e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu long mailboxId = 1999e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu extras.getLong(Mailbox.SYNC_EXTRA_MAILBOX_ID, Mailbox.NO_MAILBOX); 2005c523858385176c33a7456bb84035de78552d22dMarc Blank if (mailboxId == Mailbox.NO_MAILBOX) { 20122130ad565886c29666be55b5fdcbe0be9894b6eYu Ping Hu // Update folders. 20222130ad565886c29666be55b5fdcbe0be9894b6eYu Ping Hu EmailServiceProxy service = 20322130ad565886c29666be55b5fdcbe0be9894b6eYu Ping Hu EmailServiceUtils.getServiceForAccount(context, null, acct.mId); 20422130ad565886c29666be55b5fdcbe0be9894b6eYu Ping Hu service.updateFolderList(acct.mId); 2055c523858385176c33a7456bb84035de78552d22dMarc Blank mailboxId = Mailbox.findMailboxOfType(context, acct.mId, 2065c523858385176c33a7456bb84035de78552d22dMarc Blank Mailbox.TYPE_INBOX); 2075c523858385176c33a7456bb84035de78552d22dMarc Blank } 2085c523858385176c33a7456bb84035de78552d22dMarc Blank if (mailboxId == Mailbox.NO_MAILBOX) return; 2095c523858385176c33a7456bb84035de78552d22dMarc Blank boolean uiRefresh = 2105c523858385176c33a7456bb84035de78552d22dMarc Blank extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false); 21117d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu int deltaMessageCount = 2129e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu extras.getInt(Mailbox.SYNC_EXTRA_DELTA_MESSAGE_COUNT, 0); 21317d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu sync(context, mailboxId, syncResult, uiRefresh, deltaMessageCount); 2145c523858385176c33a7456bb84035de78552d22dMarc Blank } 2155c523858385176c33a7456bb84035de78552d22dMarc Blank } 2165c523858385176c33a7456bb84035de78552d22dMarc Blank } catch (Exception e) { 2175c523858385176c33a7456bb84035de78552d22dMarc Blank e.printStackTrace(); 2185c523858385176c33a7456bb84035de78552d22dMarc Blank } finally { 2195c523858385176c33a7456bb84035de78552d22dMarc Blank if (c != null) { 2205c523858385176c33a7456bb84035de78552d22dMarc Blank c.close(); 2215c523858385176c33a7456bb84035de78552d22dMarc Blank } 2225c523858385176c33a7456bb84035de78552d22dMarc Blank } 2235c523858385176c33a7456bb84035de78552d22dMarc Blank } 2245c523858385176c33a7456bb84035de78552d22dMarc Blank}