MailService.java revision 96c5af40d639d629267794f4f0338a267ff94ce5
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 java.util.ArrayList; 20import java.util.HashMap; 21 22import android.app.AlarmManager; 23import android.app.Notification; 24import android.app.NotificationManager; 25import android.app.PendingIntent; 26import android.app.Service; 27import android.content.Context; 28import android.content.Intent; 29import android.net.Uri; 30import android.os.IBinder; 31import android.os.SystemClock; 32import android.text.TextUtils; 33import android.util.Config; 34import android.util.Log; 35 36import com.android.email.Account; 37import com.android.email.Email; 38import com.android.email.MessagingController; 39import com.android.email.MessagingListener; 40import com.android.email.Preferences; 41import com.android.email.R; 42import com.android.email.activity.Accounts; 43import com.android.email.activity.FolderMessageList; 44 45/** 46 */ 47public class MailService extends Service { 48 private static final String ACTION_CHECK_MAIL = "com.android.email.intent.action.MAIL_SERVICE_WAKEUP"; 49 private static final String ACTION_RESCHEDULE = "com.android.email.intent.action.MAIL_SERVICE_RESCHEDULE"; 50 private static final String ACTION_CANCEL = "com.android.email.intent.action.MAIL_SERVICE_CANCEL"; 51 52 private Listener mListener = new Listener(); 53 54 private int mStartId; 55 56 public static void actionReschedule(Context context) { 57 Intent i = new Intent(); 58 i.setClass(context, MailService.class); 59 i.setAction(MailService.ACTION_RESCHEDULE); 60 context.startService(i); 61 } 62 63 public static void actionCancel(Context context) { 64 Intent i = new Intent(); 65 i.setClass(context, MailService.class); 66 i.setAction(MailService.ACTION_CANCEL); 67 context.startService(i); 68 } 69 70 @Override 71 public void onStart(Intent intent, int startId) { 72 super.onStart(intent, startId); 73 this.mStartId = startId; 74 75 MessagingController controller = MessagingController.getInstance(getApplication()); 76 controller.addListener(mListener); 77 if (ACTION_CHECK_MAIL.equals(intent.getAction())) { 78 if (Config.LOGD && Email.DEBUG) { 79 Log.d(Email.LOG_TAG, "*** MailService: checking mail"); 80 } 81 // Only check mail for accounts that have enabled automatic checking. There is still 82 // a bug here in that we check every enabled account, on every refresh - irrespective 83 // of that account's refresh frequency - but this fixes the worst case of checking 84 // accounts that should not have been checked at all. 85 // Also note: Due to the organization of this service, you must gather the accounts 86 // and make a single call to controller.checkMail(). 87 ArrayList<Account> accountsToCheck = new ArrayList<Account>(); 88 for (Account account : Preferences.getPreferences(this).getAccounts()) { 89 if (account.getAutomaticCheckIntervalMinutes() != -1) { 90 accountsToCheck.add(account); 91 } 92 } 93 Account[] accounts = accountsToCheck.toArray(new Account[accountsToCheck.size()]); 94 controller.checkMail(this, accounts, mListener); 95 } 96 else if (ACTION_CANCEL.equals(intent.getAction())) { 97 if (Config.LOGD && Email.DEBUG) { 98 Log.d(Email.LOG_TAG, "*** MailService: cancel"); 99 } 100 cancel(); 101 stopSelf(startId); 102 } 103 else if (ACTION_RESCHEDULE.equals(intent.getAction())) { 104 if (Config.LOGD && Email.DEBUG) { 105 Log.d(Email.LOG_TAG, "*** MailService: reschedule"); 106 } 107 reschedule(); 108 stopSelf(startId); 109 } 110 } 111 112 @Override 113 public void onDestroy() { 114 super.onDestroy(); 115 MessagingController.getInstance(getApplication()).removeListener(mListener); 116 } 117 118 private void cancel() { 119 AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE); 120 Intent i = new Intent(); 121 i.setClassName("com.android.email", "com.android.email.service.MailService"); 122 i.setAction(ACTION_CHECK_MAIL); 123 PendingIntent pi = PendingIntent.getService(this, 0, i, 0); 124 alarmMgr.cancel(pi); 125 } 126 127 private void reschedule() { 128 AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE); 129 Intent i = new Intent(); 130 i.setClassName("com.android.email", "com.android.email.service.MailService"); 131 i.setAction(ACTION_CHECK_MAIL); 132 PendingIntent pi = PendingIntent.getService(this, 0, i, 0); 133 134 int shortestInterval = -1; 135 for (Account account : Preferences.getPreferences(this).getAccounts()) { 136 if (account.getAutomaticCheckIntervalMinutes() != -1 137 && (account.getAutomaticCheckIntervalMinutes() < shortestInterval || shortestInterval == -1)) { 138 shortestInterval = account.getAutomaticCheckIntervalMinutes(); 139 } 140 } 141 142 if (shortestInterval == -1) { 143 alarmMgr.cancel(pi); 144 } 145 else { 146 alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() 147 + (shortestInterval * (60 * 1000)), pi); 148 } 149 } 150 151 public IBinder onBind(Intent intent) { 152 return null; 153 } 154 155 class Listener extends MessagingListener { 156 HashMap<Account, Integer> accountsWithNewMail = new HashMap<Account, Integer>(); 157 158 // TODO this should be redone because account is usually null, not very interesting. 159 // I think it would make more sense to pass Account[] here in case anyone uses it 160 // In any case, it should be noticed that this is called once per cycle 161 @Override 162 public void checkMailStarted(Context context, Account account) { 163 accountsWithNewMail.clear(); 164 } 165 166 // Called once per checked account 167 @Override 168 public void checkMailFailed(Context context, Account account, String reason) { 169 if (Config.LOGD && Email.DEBUG) { 170 Log.d(Email.LOG_TAG, "*** MailService: checkMailFailed: " + reason); 171 } 172 reschedule(); 173 stopSelf(mStartId); 174 } 175 176 // Called once per checked account 177 @Override 178 public void synchronizeMailboxFinished( 179 Account account, 180 String folder, 181 int totalMessagesInMailbox, 182 int numNewMessages) { 183 if (Config.LOGD && Email.DEBUG) { 184 Log.d(Email.LOG_TAG, "*** MailService: synchronizeMailboxFinished: total=" + 185 totalMessagesInMailbox + " new=" + numNewMessages); 186 } 187 if (account.isNotifyNewMail() && numNewMessages > 0) { 188 accountsWithNewMail.put(account, numNewMessages); 189 } 190 } 191 192 // TODO this should be redone because account is usually null, not very interesting. 193 // I think it would make more sense to pass Account[] here in case anyone uses it 194 // In any case, it should be noticed that this is called once per cycle 195 @Override 196 public void checkMailFinished(Context context, Account account) { 197 if (Config.LOGD && Email.DEBUG) { 198 Log.d(Email.LOG_TAG, "*** MailService: checkMailFinished"); 199 } 200 NotificationManager notifMgr = (NotificationManager)context 201 .getSystemService(Context.NOTIFICATION_SERVICE); 202 203 if (accountsWithNewMail.size() > 0) { 204 Notification notif = new Notification(R.drawable.stat_notify_email_generic, 205 getString(R.string.notification_new_title), System.currentTimeMillis()); 206 boolean vibrate = false; 207 String ringtone = null; 208 if (accountsWithNewMail.size() > 1) { 209 for (Account account1 : accountsWithNewMail.keySet()) { 210 if (account1.isVibrate()) vibrate = true; 211 ringtone = account1.getRingtone(); 212 } 213 Intent i = new Intent(context, Accounts.class); 214 PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0); 215 notif.setLatestEventInfo(context, getString(R.string.notification_new_title), 216 getString(R.string.notification_new_multi_account_fmt, 217 accountsWithNewMail.size()), pi); 218 } else { 219 Account account1 = accountsWithNewMail.keySet().iterator().next(); 220 int totalNewMails = accountsWithNewMail.get(account1); 221 Intent i = FolderMessageList.actionHandleAccountIntent(context, account1, Email.INBOX); 222 PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0); 223 notif.setLatestEventInfo(context, getString(R.string.notification_new_title), 224 getString(R.string.notification_new_one_account_fmt, totalNewMails, 225 account1.getDescription()), pi); 226 vibrate = account1.isVibrate(); 227 ringtone = account1.getRingtone(); 228 } 229 notif.defaults = Notification.DEFAULT_LIGHTS; 230 notif.sound = TextUtils.isEmpty(ringtone) ? null : Uri.parse(ringtone); 231 if (vibrate) { 232 notif.defaults |= Notification.DEFAULT_VIBRATE; 233 } 234 notifMgr.notify(1, notif); 235 } 236 237 reschedule(); 238 stopSelf(mStartId); 239 } 240 } 241} 242