diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 7b749569c..86ca3bca8 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -89,6 +89,14 @@ + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index f9672fa07..81e790c28 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -82,6 +82,7 @@ New email New email from %s %d Unread (%s) + %d New Email(s) (%s) in %d accounts Message not sent diff --git a/src/com/android/email/Email.java b/src/com/android/email/Email.java index ea66cd5fc..0155ead38 100644 --- a/src/com/android/email/Email.java +++ b/src/com/android/email/Email.java @@ -151,6 +151,10 @@ public class Email extends Application { public static final int FLAGGED_COLOR = 0xffff4444; + public static final String INTENT_DATA_URI_SCHEMA = "content"; + public static final String INTENT_DATA_UR_PATH_PREFIX = "email"; + public static final String INTENT_DATA_URI_PREFIX = INTENT_DATA_URI_SCHEMA + "://" + INTENT_DATA_UR_PATH_PREFIX; + /** * Called throughout the application when the number of accounts has changed. This method * enables or disables the Compose activity, the boot receiver and the service based on diff --git a/src/com/android/email/activity/FolderMessageList.java b/src/com/android/email/activity/FolderMessageList.java index 1b4ef2653..75f2d85f1 100644 --- a/src/com/android/email/activity/FolderMessageList.java +++ b/src/com/android/email/activity/FolderMessageList.java @@ -16,6 +16,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.Typeface; import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Process; @@ -80,6 +81,8 @@ import com.android.email.mail.store.LocalStore; */ public class FolderMessageList extends ExpandableListActivity { + private static final String INTENT_DATA_PATH_SUFFIX = "/accounts"; + private static final String EXTRA_ACCOUNT = "account"; private static final String EXTRA_CLEAR_NOTIFICATION = "clearNotification"; @@ -453,7 +456,8 @@ public class FolderMessageList extends ExpandableListActivity public static Intent actionHandleAccountIntent(Context context, Account account, String initialFolder) { - Intent intent = new Intent(context, FolderMessageList.class); + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(Email.INTENT_DATA_URI_PREFIX + INTENT_DATA_PATH_SUFFIX + "/" + account.getAccountNumber()), context, FolderMessageList.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(EXTRA_ACCOUNT, account); intent.putExtra(EXTRA_CLEAR_NOTIFICATION, true); if (initialFolder != null) diff --git a/src/com/android/email/service/MailService.java b/src/com/android/email/service/MailService.java index ba7cd91b2..fb4a37d0d 100644 --- a/src/com/android/email/service/MailService.java +++ b/src/com/android/email/service/MailService.java @@ -1,328 +1,309 @@ - -package com.android.email.service; - -import java.util.Date; -import java.util.HashMap; - -import android.app.AlarmManager; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.IBinder; -import android.os.PowerManager; -import android.os.PowerManager.WakeLock; -import android.os.SystemClock; -import android.util.Config; -import android.util.Log; -import android.text.TextUtils; -import android.net.Uri; - -import com.android.email.Account; -import com.android.email.Email; -import com.android.email.MessagingController; -import com.android.email.MessagingListener; -import com.android.email.Preferences; -import com.android.email.R; -import com.android.email.activity.Accounts; -import com.android.email.activity.FolderMessageList; -import com.android.email.mail.Folder; -import com.android.email.mail.MessagingException; -import com.android.email.mail.Store; - -/** - */ -public class MailService extends Service { - private static final String ACTION_CHECK_MAIL = "com.android.email.intent.action.MAIL_SERVICE_WAKEUP"; - private static final String ACTION_RESCHEDULE = "com.android.email.intent.action.MAIL_SERVICE_RESCHEDULE"; - private static final String ACTION_CANCEL = "com.android.email.intent.action.MAIL_SERVICE_CANCEL"; - - private Listener mListener = new Listener(); - - private int mStartId; - - public static void actionReschedule(Context context) { - Intent i = new Intent(); - i.setClass(context, MailService.class); - i.setAction(MailService.ACTION_RESCHEDULE); - context.startService(i); - } - - public static void actionCancel(Context context) { - Intent i = new Intent(); - i.setClass(context, MailService.class); - i.setAction(MailService.ACTION_CANCEL); - context.startService(i); - } - - @Override - public void onCreate() { - super.onCreate(); - Log.v(Email.LOG_TAG, "***** MailService *****: onCreate"); - } - - @Override - public void onStart(Intent intent, int startId) { - setForeground(true); // if it gets killed once, it'll never restart - Log.v(Email.LOG_TAG, "***** MailService *****: onStart(" + intent + ", " + startId + ")"); - super.onStart(intent, startId); - this.mStartId = startId; - - // MessagingController.getInstance(getApplication()).addListener(mListener); - if (ACTION_CHECK_MAIL.equals(intent.getAction())) { - //if (Config.LOGV) { - MessagingController.getInstance(getApplication()).log("***** MailService *****: checking mail"); - Log.v(Email.LOG_TAG, "***** MailService *****: checking mail"); - //} - - MessagingController controller = MessagingController.getInstance(getApplication()); - Listener listener = (Listener)controller.getCheckMailListener(); - if (listener == null) - { - MessagingController.getInstance(getApplication()).log("***** MailService *****: starting new check"); - - mListener.wakeLockAcquire(); - controller.setCheckMailListener(mListener); - controller.checkMail(this, null, mListener); - } - else - { - MessagingController.getInstance(getApplication()).log("***** MailService *****: renewing WakeLock"); - - listener.wakeLockAcquire(); - } - - reschedule(); - stopSelf(startId); - } - else if (ACTION_CANCEL.equals(intent.getAction())) { - if (Config.LOGV) { - Log.v(Email.LOG_TAG, "***** MailService *****: cancel"); - } - MessagingController.getInstance(getApplication()).log("***** MailService *****: cancel"); - - cancel(); - stopSelf(startId); - } - else if (ACTION_RESCHEDULE.equals(intent.getAction())) { - if (Config.LOGV) { - Log.v(Email.LOG_TAG, "***** MailService *****: reschedule"); - } - MessagingController.getInstance(getApplication()).log("***** MailService *****: reschedule"); - reschedule(); - stopSelf(startId); - } - } - - @Override - public void onDestroy() { - Log.v(Email.LOG_TAG, "***** MailService *****: onDestroy()"); - super.onDestroy(); - // MessagingController.getInstance(getApplication()).removeListener(mListener); - } - - private void cancel() { - AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE); - Intent i = new Intent(); - i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService"); - i.setAction(ACTION_CHECK_MAIL); - PendingIntent pi = PendingIntent.getService(this, 0, i, 0); - alarmMgr.cancel(pi); - } - - private void reschedule() { - AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE); - Intent i = new Intent(); - i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService"); - i.setAction(ACTION_CHECK_MAIL); - PendingIntent pi = PendingIntent.getService(this, 0, i, 0); - - int shortestInterval = -1; - - for (Account account : Preferences.getPreferences(this).getAccounts()) { - if (account.getAutomaticCheckIntervalMinutes() != -1 - && (account.getAutomaticCheckIntervalMinutes() < shortestInterval || shortestInterval == -1)) { - shortestInterval = account.getAutomaticCheckIntervalMinutes(); - } - } - - if (shortestInterval == -1) { - Log.v(Email.LOG_TAG, "No next check scheduled for package " + getApplication().getPackageName()); - alarmMgr.cancel(pi); - } - else - { - long delay = (shortestInterval * (60 * 1000)); - - long nextTime = System.currentTimeMillis() + delay; - String checkString = "Next check for package " + getApplication().getPackageName() + " scheduled for " + new Date(nextTime); - Log.v(Email.LOG_TAG, checkString); - MessagingController.getInstance(getApplication()).log(checkString); - alarmMgr.set(AlarmManager.RTC_WAKEUP, nextTime, pi); - } - - } - - public IBinder onBind(Intent intent) { - return null; - } - - class Listener extends MessagingListener { - HashMap accountsWithNewMail = new HashMap(); - private WakeLock wakeLock = null; - - // wakelock strategy is to be very conservative. If there is any reason to release, then release - // don't want to take the chance of running wild - public synchronized void wakeLockAcquire() - { - WakeLock oldWakeLock = wakeLock; - - PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email"); - wakeLock.setReferenceCounted(false); - wakeLock.acquire(Email.WAKE_LOCK_TIMEOUT); - - if (oldWakeLock != null) - { - oldWakeLock.release(); - } - - } - public synchronized void wakeLockRelease() - { - if (wakeLock != null) - { - wakeLock.release(); - wakeLock = null; - } - } - @Override - public void checkMailStarted(Context context, Account account) { - accountsWithNewMail.clear(); - } - - @Override - public void checkMailFailed(Context context, Account account, String reason) { - release(); - } - - @Override - public void synchronizeMailboxFinished( - Account account, - String folder, - int totalMessagesInMailbox, - int numNewMessages) { - if (account.isNotifyNewMail() && numNewMessages > 0) { - accountsWithNewMail.put(account.getUuid(), numNewMessages); - } - } - - private void checkMailDone(Context context, Account doNotUseaccount) - { - if (accountsWithNewMail.isEmpty()) - { - return; - } - StringBuffer notice = new StringBuffer(); - int accountNumber = Email.FETCHING_EMAIL_NOTIFICATION_NO_ACCOUNT; - - boolean vibrate = false; - String ringtone = null; - for (Account thisAccount : Preferences.getPreferences(context).getAccounts()) { - if (thisAccount.isNotifyNewMail()) - { - int unreadMessageCount = 0; - try - { - unreadMessageCount = thisAccount.getUnreadMessageCount(context, getApplication()); - if (unreadMessageCount > 0) - { - notice.append(getString(R.string.notification_new_one_account_fmt, unreadMessageCount, - thisAccount.getDescription()) + "\n"); - if (accountNumber != Email.FETCHING_EMAIL_NOTIFICATION_MULTI_ACCOUNT_ID) // if already set to Multi, nothing to do - { - if (accountNumber == Email.FETCHING_EMAIL_NOTIFICATION_NO_ACCOUNT) // Haven't set to anything, yet, set to this account number - { - accountNumber = thisAccount.getAccountNumber(); - } - else // Another account was already set, so there is more than one with new mail - { - accountNumber = Email.FETCHING_EMAIL_NOTIFICATION_MULTI_ACCOUNT_ID; - } - } - } - } - catch (MessagingException me) - { - Log.e(Email.LOG_TAG, "***** MailService *****: couldn't get unread count for account " + - thisAccount.getDescription(), me); - } - if (accountsWithNewMail.containsKey(thisAccount.getUuid())) - { - if (ringtone == null) - { - ringtone = thisAccount.getRingtone(); - } - vibrate |= thisAccount.isVibrate(); - } - } - } - if (notice.length() > 0) - { - NotificationManager notifMgr = - (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); - - Notification notif = new Notification(R.drawable.stat_notify_email_generic, - getString(R.string.notification_new_title), System.currentTimeMillis()); - - // If only one account has mail, maybe go back to the old way of targetting the account. - Intent i = new Intent(context, Accounts.class); - PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0); - - notif.setLatestEventInfo(context, getString(R.string.notification_new_title), - notice, pi); - - Log.v(Email.LOG_TAG, "Using ringtone " + ringtone + " and vibrate = " + vibrate); - - // notif.defaults = Notification.DEFAULT_LIGHTS; - notif.sound = TextUtils.isEmpty(ringtone) ? null : Uri.parse(ringtone); - if (vibrate) { - notif.defaults |= Notification.DEFAULT_VIBRATE; - } - - notif.flags |= Notification.FLAG_SHOW_LIGHTS; - notif.ledARGB = Email.NOTIFICATION_LED_COLOR; - notif.ledOnMS = Email.NOTIFICATION_LED_ON_TIME; - notif.ledOffMS = Email.NOTIFICATION_LED_OFF_TIME; - - notifMgr.notify(accountNumber, notif); - } - - } - - private void release() - { - MessagingController controller = MessagingController.getInstance(getApplication()); - controller.setCheckMailListener(null); - reschedule(); - wakeLockRelease(); - stopSelf(mStartId); - } - - @Override - public void checkMailFinished(Context context, Account account) { - - Log.v(Email.LOG_TAG, "***** MailService *****: checkMailFinished"); - try - { - checkMailDone(context, account); - } - finally - { - release(); - } - } - } -} + +package com.android.email.service; + +import java.util.Date; +import java.util.HashMap; + +import android.app.AlarmManager; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; +import android.os.SystemClock; +import android.util.Config; +import android.util.Log; +import android.text.TextUtils; +import android.net.Uri; + +import com.android.email.Account; +import com.android.email.Email; +import com.android.email.MessagingController; +import com.android.email.MessagingListener; +import com.android.email.Preferences; +import com.android.email.R; +import com.android.email.activity.Accounts; +import com.android.email.activity.FolderMessageList; +import com.android.email.mail.Folder; +import com.android.email.mail.MessagingException; +import com.android.email.mail.Store; + +/** + */ +public class MailService extends Service { + private static final String ACTION_CHECK_MAIL = "com.android.email.intent.action.MAIL_SERVICE_WAKEUP"; + private static final String ACTION_RESCHEDULE = "com.android.email.intent.action.MAIL_SERVICE_RESCHEDULE"; + private static final String ACTION_CANCEL = "com.android.email.intent.action.MAIL_SERVICE_CANCEL"; + + private Listener mListener = new Listener(); + + private int mStartId; + + public static void actionReschedule(Context context) { + Intent i = new Intent(); + i.setClass(context, MailService.class); + i.setAction(MailService.ACTION_RESCHEDULE); + context.startService(i); + } + + public static void actionCancel(Context context) { + Intent i = new Intent(); + i.setClass(context, MailService.class); + i.setAction(MailService.ACTION_CANCEL); + context.startService(i); + } + + @Override + public void onCreate() { + super.onCreate(); + Log.v(Email.LOG_TAG, "***** MailService *****: onCreate"); + } + + @Override + public void onStart(Intent intent, int startId) { + setForeground(true); // if it gets killed once, it'll never restart + Log.v(Email.LOG_TAG, "***** MailService *****: onStart(" + intent + ", " + startId + ")"); + super.onStart(intent, startId); + this.mStartId = startId; + + // MessagingController.getInstance(getApplication()).addListener(mListener); + if (ACTION_CHECK_MAIL.equals(intent.getAction())) { + //if (Config.LOGV) { + MessagingController.getInstance(getApplication()).log("***** MailService *****: checking mail"); + Log.v(Email.LOG_TAG, "***** MailService *****: checking mail"); + //} + + MessagingController controller = MessagingController.getInstance(getApplication()); + Listener listener = (Listener)controller.getCheckMailListener(); + if (listener == null) + { + MessagingController.getInstance(getApplication()).log("***** MailService *****: starting new check"); + + mListener.wakeLockAcquire(); + controller.setCheckMailListener(mListener); + controller.checkMail(this, null, mListener); + } + else + { + MessagingController.getInstance(getApplication()).log("***** MailService *****: renewing WakeLock"); + + listener.wakeLockAcquire(); + } + + reschedule(); + stopSelf(startId); + } + else if (ACTION_CANCEL.equals(intent.getAction())) { + if (Config.LOGV) { + Log.v(Email.LOG_TAG, "***** MailService *****: cancel"); + } + MessagingController.getInstance(getApplication()).log("***** MailService *****: cancel"); + + cancel(); + stopSelf(startId); + } + else if (ACTION_RESCHEDULE.equals(intent.getAction())) { + if (Config.LOGV) { + Log.v(Email.LOG_TAG, "***** MailService *****: reschedule"); + } + MessagingController.getInstance(getApplication()).log("***** MailService *****: reschedule"); + reschedule(); + stopSelf(startId); + } + } + + @Override + public void onDestroy() { + Log.v(Email.LOG_TAG, "***** MailService *****: onDestroy()"); + super.onDestroy(); + // MessagingController.getInstance(getApplication()).removeListener(mListener); + } + + private void cancel() { + AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE); + Intent i = new Intent(); + i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService"); + i.setAction(ACTION_CHECK_MAIL); + PendingIntent pi = PendingIntent.getService(this, 0, i, 0); + alarmMgr.cancel(pi); + } + + private void reschedule() { + AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE); + Intent i = new Intent(); + i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService"); + i.setAction(ACTION_CHECK_MAIL); + PendingIntent pi = PendingIntent.getService(this, 0, i, 0); + + int shortestInterval = -1; + + for (Account account : Preferences.getPreferences(this).getAccounts()) { + if (account.getAutomaticCheckIntervalMinutes() != -1 + && (account.getAutomaticCheckIntervalMinutes() < shortestInterval || shortestInterval == -1)) { + shortestInterval = account.getAutomaticCheckIntervalMinutes(); + } + } + + if (shortestInterval == -1) { + Log.v(Email.LOG_TAG, "No next check scheduled for package " + getApplication().getPackageName()); + alarmMgr.cancel(pi); + } + else + { + long delay = (shortestInterval * (60 * 1000)); + + long nextTime = System.currentTimeMillis() + delay; + String checkString = "Next check for package " + getApplication().getPackageName() + " scheduled for " + new Date(nextTime); + Log.v(Email.LOG_TAG, checkString); + MessagingController.getInstance(getApplication()).log(checkString); + alarmMgr.set(AlarmManager.RTC_WAKEUP, nextTime, pi); + } + + } + + public IBinder onBind(Intent intent) { + return null; + } + + class Listener extends MessagingListener { + HashMap accountsWithNewMail = new HashMap(); + private WakeLock wakeLock = null; + + // wakelock strategy is to be very conservative. If there is any reason to release, then release + // don't want to take the chance of running wild + public synchronized void wakeLockAcquire() + { + WakeLock oldWakeLock = wakeLock; + + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email"); + wakeLock.setReferenceCounted(false); + wakeLock.acquire(Email.WAKE_LOCK_TIMEOUT); + + if (oldWakeLock != null) + { + oldWakeLock.release(); + } + + } + public synchronized void wakeLockRelease() + { + if (wakeLock != null) + { + wakeLock.release(); + wakeLock = null; + } + } + @Override + public void checkMailStarted(Context context, Account account) { + accountsWithNewMail.clear(); + } + + @Override + public void checkMailFailed(Context context, Account account, String reason) { + release(); + } + + @Override + public void synchronizeMailboxFinished( + Account account, + String folder, + int totalMessagesInMailbox, + int numNewMessages) { + if (account.isNotifyNewMail() && numNewMessages > 0) { + accountsWithNewMail.put(account.getUuid(), numNewMessages); + } + } + + private void checkMailDone(Context context, Account doNotUseaccount) + { + if (accountsWithNewMail.isEmpty()) + { + return; + } + + NotificationManager notifMgr = + (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); + + int index = 0; + for (Account thisAccount : Preferences.getPreferences(context).getAccounts()) { + //No need to filter out accounts that do not require notification + //since only the one that require so are in this map + if (accountsWithNewMail.containsKey(thisAccount.getUuid())) + { + String notice = null; + try + { + int unreadMessageCount = thisAccount.getUnreadMessageCount(context, getApplication()); + if (unreadMessageCount > 0) + { + notice = getString(R.string.notification_new_one_account_fmt, unreadMessageCount, + thisAccount.getDescription()); + } + //Can this ever happen? + else + { + notice = getString(R.string.notification_new_one_account_unknown_unread_count_fmt, (int)accountsWithNewMail.get(thisAccount.getUuid()), thisAccount.getDescription()); + } + } + catch (MessagingException me) + { + Log.e(Email.LOG_TAG, "***** MailService *****: couldn't get unread count for account " + + thisAccount.getDescription(), me); + notice = getString(R.string.notification_new_one_account_unknown_unread_count_fmt, (int)accountsWithNewMail.get(thisAccount.getUuid()), thisAccount.getDescription()); + } + + Notification notif = new Notification(R.drawable.stat_notify_email_generic, + getString(R.string.notification_new_title), System.currentTimeMillis() + (index*1000)); + + Intent i = FolderMessageList.actionHandleAccountIntent(context, thisAccount, Email.INBOX); + + PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0); + + notif.setLatestEventInfo(context, getString(R.string.notification_new_title), notice, pi); + + String ringtone = thisAccount.getRingtone(); + notif.sound = TextUtils.isEmpty(ringtone) ? null : Uri.parse(ringtone); + + if (thisAccount.isVibrate()) { + notif.defaults |= Notification.DEFAULT_VIBRATE; + } + + notif.flags |= Notification.FLAG_SHOW_LIGHTS; + notif.ledARGB = Email.NOTIFICATION_LED_COLOR; + notif.ledOnMS = Email.NOTIFICATION_LED_ON_TIME; + notif.ledOffMS = Email.NOTIFICATION_LED_OFF_TIME; + + notifMgr.notify(thisAccount.getAccountNumber(), notif); + } + }//for accounts + }//checkMailDone + + private void release() + { + MessagingController controller = MessagingController.getInstance(getApplication()); + controller.setCheckMailListener(null); + reschedule(); + wakeLockRelease(); + stopSelf(mStartId); + } + + @Override + public void checkMailFinished(Context context, Account account) { + + Log.v(Email.LOG_TAG, "***** MailService *****: checkMailFinished"); + try + { + checkMailDone(context, account); + } + finally + { + release(); + } + } + } +}