MailService.java revision 4f813fb12937de74d3ccec730b8de0c9de7a87e0
1/* 2 * Copyright (C) 2008 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.email.service; 18 19import android.accounts.AccountManager; 20import android.accounts.AccountManagerCallback; 21import android.app.Service; 22import android.content.Context; 23import android.content.Intent; 24import android.database.Cursor; 25import android.os.Bundle; 26import android.os.IBinder; 27import android.util.Log; 28 29import com.android.email.Controller; 30import com.android.email.Email; 31import com.android.email.SingleRunningTask; 32import com.android.email.provider.AccountReconciler; 33import com.android.emailcommon.AccountManagerTypes; 34import com.android.emailcommon.provider.Account; 35import com.android.emailcommon.provider.HostAuth; 36import com.android.emailcommon.utility.EmailAsyncTask; 37import com.google.common.annotations.VisibleForTesting; 38 39import java.util.ArrayList; 40import java.util.List; 41 42/** 43 * Legacy service, now used mainly for account reconciliation 44 */ 45public class MailService extends Service { 46 private static final String LOG_TAG = "Email-MailService"; 47 48 private static final String ACTION_SEND_PENDING_MAIL = 49 "com.android.email.intent.action.MAIL_SERVICE_SEND_PENDING"; 50 51 private static final String EXTRA_ACCOUNT = "com.android.email.intent.extra.ACCOUNT"; 52 53 /** 54 * Entry point for AttachmentDownloadService to ask that pending mail be sent 55 * @param context the caller's context 56 * @param accountId the account whose pending mail should be sent 57 */ 58 public static void actionSendPendingMail(Context context, long accountId) { 59 Intent i = new Intent(); 60 i.setClass(context, MailService.class); 61 i.setAction(MailService.ACTION_SEND_PENDING_MAIL); 62 i.putExtra(MailService.EXTRA_ACCOUNT, accountId); 63 context.startService(i); 64 } 65 66 @Override 67 public int onStartCommand(final Intent intent, int flags, final int startId) { 68 super.onStartCommand(intent, flags, startId); 69 70 EmailAsyncTask.runAsyncParallel(new Runnable() { 71 @Override 72 public void run() { 73 reconcilePopImapAccountsSync(MailService.this); 74 } 75 }); 76 77 String action = intent.getAction(); 78 final long accountId = intent.getLongExtra(EXTRA_ACCOUNT, -1); 79 80 if (ACTION_SEND_PENDING_MAIL.equals(action)) { 81 if (Email.DEBUG) { 82 Log.d(LOG_TAG, "action: send pending mail"); 83 } 84 EmailAsyncTask.runAsyncParallel(new Runnable() { 85 @Override 86 public void run() { 87 Controller.getInstance(getApplicationContext()).sendPendingMessages(accountId); 88 } 89 }); 90 stopSelf(startId); 91 } 92 93 // Returning START_NOT_STICKY means that if a mail check is killed (e.g. due to memory 94 // pressure, there will be no explicit restart. This is OK; Note that we set a watchdog 95 // alarm before each mailbox check. If the mailbox check never completes, the watchdog 96 // will fire and get things running again. 97 return START_NOT_STICKY; 98 } 99 100 @Override 101 public IBinder onBind(Intent intent) { 102 return null; 103 } 104 105 public static ArrayList<Account> getPopImapAccountList(Context context) { 106 ArrayList<Account> providerAccounts = new ArrayList<Account>(); 107 Cursor c = context.getContentResolver().query(Account.CONTENT_URI, Account.ID_PROJECTION, 108 null, null, null); 109 try { 110 while (c.moveToNext()) { 111 long accountId = c.getLong(Account.CONTENT_ID_COLUMN); 112 String protocol = Account.getProtocol(context, accountId); 113 if ((protocol != null) && ("pop3".equals(protocol) || "imap".equals(protocol))) { 114 Account account = Account.restoreAccountWithId(context, accountId); 115 if (account != null) { 116 providerAccounts.add(account); 117 } 118 } 119 } 120 } finally { 121 c.close(); 122 } 123 return providerAccounts; 124 } 125 126 private static final SingleRunningTask<Context> sReconcilePopImapAccountsSyncExecutor = 127 new SingleRunningTask<Context>("ReconcilePopImapAccountsSync") { 128 @Override 129 protected void runInternal(Context context) { 130 android.accounts.Account[] accountManagerAccounts = AccountManager.get(context) 131 .getAccountsByType(AccountManagerTypes.TYPE_POP_IMAP); 132 ArrayList<Account> providerAccounts = getPopImapAccountList(context); 133 MailService.reconcileAccountsWithAccountManager(context, providerAccounts, 134 accountManagerAccounts, context); 135 136 } 137 }; 138 139 /** 140 * Reconcile POP/IMAP accounts. 141 */ 142 public static void reconcilePopImapAccountsSync(Context context) { 143 sReconcilePopImapAccountsSyncExecutor.run(context); 144 } 145 146 /** 147 * Determines whether or not POP/IMAP accounts need reconciling or not. This is a safe operation 148 * to perform on the UI thread. 149 */ 150 public static boolean hasMismatchInPopImapAccounts(Context context) { 151 android.accounts.Account[] accountManagerAccounts = AccountManager.get(context) 152 .getAccountsByType(AccountManagerTypes.TYPE_POP_IMAP); 153 ArrayList<Account> providerAccounts = getPopImapAccountList(context); 154 return AccountReconciler.accountsNeedReconciling( 155 context, providerAccounts, accountManagerAccounts); 156 } 157 158 /** 159 * See Utility.reconcileAccounts for details 160 * @param context The context in which to operate 161 * @param emailProviderAccounts the exchange provider accounts to work from 162 * @param accountManagerAccounts The account manager accounts to work from 163 * @param providerContext the provider's context (in unit tests, this may differ from context) 164 */ 165 @VisibleForTesting 166 public static void reconcileAccountsWithAccountManager(Context context, 167 List<Account> emailProviderAccounts, android.accounts.Account[] accountManagerAccounts, 168 Context providerContext) { 169 AccountReconciler.reconcileAccounts(context, emailProviderAccounts, accountManagerAccounts, 170 providerContext); 171 } 172 173 public static void setupAccountManagerAccount(Context context, Account account, 174 boolean email, boolean calendar, boolean contacts, 175 AccountManagerCallback<Bundle> callback) { 176 Bundle options = new Bundle(); 177 HostAuth hostAuthRecv = HostAuth.restoreHostAuthWithId(context, account.mHostAuthKeyRecv); 178 if (hostAuthRecv == null) return; 179 // Set up username/password 180 options.putString(EasAuthenticatorService.OPTIONS_USERNAME, account.mEmailAddress); 181 options.putString(EasAuthenticatorService.OPTIONS_PASSWORD, hostAuthRecv.mPassword); 182 options.putBoolean(EasAuthenticatorService.OPTIONS_CONTACTS_SYNC_ENABLED, contacts); 183 options.putBoolean(EasAuthenticatorService.OPTIONS_CALENDAR_SYNC_ENABLED, calendar); 184 options.putBoolean(EasAuthenticatorService.OPTIONS_EMAIL_SYNC_ENABLED, email); 185 String accountType = hostAuthRecv.mProtocol.equals("eas") ? 186 AccountManagerTypes.TYPE_EXCHANGE : 187 AccountManagerTypes.TYPE_POP_IMAP; 188 AccountManager.get(context).addAccount(accountType, null, null, options, null, callback, 189 null); 190 } 191} 192