Now display a new email notification per account. Each notification now opens the account (does not go to the Accounts screen anymore)

Note: Notifications are displayed after all accounts are sync'ed but are delayed to be 1sec. apart
TODO: Display notifications at the end of each individual sync
This commit is contained in:
Bao-Long Nguyen-Trong 2009-02-01 07:19:08 +00:00
parent 3dfabbbd0c
commit 41dc1ca8d8
5 changed files with 327 additions and 329 deletions

View file

@ -89,6 +89,14 @@
</activity> </activity>
<activity <activity
android:name="com.android.email.activity.FolderMessageList"> android:name="com.android.email.activity.FolderMessageList">
<intent-filter>
<action android:name="android.intent.action.view" />
<data
android:scheme="content"
android:path="/email/accounts/*"
/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity> </activity>
<activity <activity
android:name="com.android.email.activity.MessageView"> android:name="com.android.email.activity.MessageView">

View file

@ -82,6 +82,7 @@
<string name="notification_new_title">New email</string> <string name="notification_new_title">New email</string>
<string name="notification_new_scrolling">New email from <xliff:g id="sender">%s</xliff:g></string> <string name="notification_new_scrolling">New email from <xliff:g id="sender">%s</xliff:g></string>
<string name="notification_new_one_account_fmt"><xliff:g id="unread_message_count">%d</xliff:g> Unread (<xliff:g id="account">%s</xliff:g>)</string> <!-- 279 Unread (someone@google.com) --> <string name="notification_new_one_account_fmt"><xliff:g id="unread_message_count">%d</xliff:g> Unread (<xliff:g id="account">%s</xliff:g>)</string> <!-- 279 Unread (someone@google.com) -->
<string name="notification_new_one_account_unknown_unread_count_fmt"><xliff:g id="new_message_count">%d</xliff:g> New Email(s) (<xliff:g id="account">%s</xliff:g>)</string> <!-- 2 New Email(s) (someone@google.com) -->
<string name="notification_new_multi_account_fmt">in <xliff:g id="number_accounts">%d</xliff:g> accounts</string> <string name="notification_new_multi_account_fmt">in <xliff:g id="number_accounts">%d</xliff:g> accounts</string>
<string name="notification_unsent_title">Message not sent</string> <string name="notification_unsent_title">Message not sent</string>

View file

@ -151,6 +151,10 @@ public class Email extends Application {
public static final int FLAGGED_COLOR = 0xffff4444; 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 * 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 * enables or disables the Compose activity, the boot receiver and the service based on

View file

@ -16,6 +16,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Process; import android.os.Process;
@ -80,6 +81,8 @@ import com.android.email.mail.store.LocalStore;
*/ */
public class FolderMessageList extends ExpandableListActivity 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_ACCOUNT = "account";
private static final String EXTRA_CLEAR_NOTIFICATION = "clearNotification"; private static final String EXTRA_CLEAR_NOTIFICATION = "clearNotification";
@ -453,7 +456,8 @@ public class FolderMessageList extends ExpandableListActivity
public static Intent actionHandleAccountIntent(Context context, public static Intent actionHandleAccountIntent(Context context,
Account account, String initialFolder) 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_ACCOUNT, account);
intent.putExtra(EXTRA_CLEAR_NOTIFICATION, true); intent.putExtra(EXTRA_CLEAR_NOTIFICATION, true);
if (initialFolder != null) if (initialFolder != null)

View file

@ -1,328 +1,309 @@
package com.android.email.service; package com.android.email.service;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.IBinder; import android.os.IBinder;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.PowerManager.WakeLock; import android.os.PowerManager.WakeLock;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.Config; import android.util.Config;
import android.util.Log; import android.util.Log;
import android.text.TextUtils; import android.text.TextUtils;
import android.net.Uri; import android.net.Uri;
import com.android.email.Account; import com.android.email.Account;
import com.android.email.Email; import com.android.email.Email;
import com.android.email.MessagingController; import com.android.email.MessagingController;
import com.android.email.MessagingListener; import com.android.email.MessagingListener;
import com.android.email.Preferences; import com.android.email.Preferences;
import com.android.email.R; import com.android.email.R;
import com.android.email.activity.Accounts; import com.android.email.activity.Accounts;
import com.android.email.activity.FolderMessageList; import com.android.email.activity.FolderMessageList;
import com.android.email.mail.Folder; import com.android.email.mail.Folder;
import com.android.email.mail.MessagingException; import com.android.email.mail.MessagingException;
import com.android.email.mail.Store; import com.android.email.mail.Store;
/** /**
*/ */
public class MailService extends Service { 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_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_RESCHEDULE = "com.android.email.intent.action.MAIL_SERVICE_RESCHEDULE";
private static final String ACTION_CANCEL = "com.android.email.intent.action.MAIL_SERVICE_CANCEL"; private static final String ACTION_CANCEL = "com.android.email.intent.action.MAIL_SERVICE_CANCEL";
private Listener mListener = new Listener(); private Listener mListener = new Listener();
private int mStartId; private int mStartId;
public static void actionReschedule(Context context) { public static void actionReschedule(Context context) {
Intent i = new Intent(); Intent i = new Intent();
i.setClass(context, MailService.class); i.setClass(context, MailService.class);
i.setAction(MailService.ACTION_RESCHEDULE); i.setAction(MailService.ACTION_RESCHEDULE);
context.startService(i); context.startService(i);
} }
public static void actionCancel(Context context) { public static void actionCancel(Context context) {
Intent i = new Intent(); Intent i = new Intent();
i.setClass(context, MailService.class); i.setClass(context, MailService.class);
i.setAction(MailService.ACTION_CANCEL); i.setAction(MailService.ACTION_CANCEL);
context.startService(i); context.startService(i);
} }
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
Log.v(Email.LOG_TAG, "***** MailService *****: onCreate"); Log.v(Email.LOG_TAG, "***** MailService *****: onCreate");
} }
@Override @Override
public void onStart(Intent intent, int startId) { public void onStart(Intent intent, int startId) {
setForeground(true); // if it gets killed once, it'll never restart setForeground(true); // if it gets killed once, it'll never restart
Log.v(Email.LOG_TAG, "***** MailService *****: onStart(" + intent + ", " + startId + ")"); Log.v(Email.LOG_TAG, "***** MailService *****: onStart(" + intent + ", " + startId + ")");
super.onStart(intent, startId); super.onStart(intent, startId);
this.mStartId = startId; this.mStartId = startId;
// MessagingController.getInstance(getApplication()).addListener(mListener); // MessagingController.getInstance(getApplication()).addListener(mListener);
if (ACTION_CHECK_MAIL.equals(intent.getAction())) { if (ACTION_CHECK_MAIL.equals(intent.getAction())) {
//if (Config.LOGV) { //if (Config.LOGV) {
MessagingController.getInstance(getApplication()).log("***** MailService *****: checking mail"); MessagingController.getInstance(getApplication()).log("***** MailService *****: checking mail");
Log.v(Email.LOG_TAG, "***** MailService *****: checking mail"); Log.v(Email.LOG_TAG, "***** MailService *****: checking mail");
//} //}
MessagingController controller = MessagingController.getInstance(getApplication()); MessagingController controller = MessagingController.getInstance(getApplication());
Listener listener = (Listener)controller.getCheckMailListener(); Listener listener = (Listener)controller.getCheckMailListener();
if (listener == null) if (listener == null)
{ {
MessagingController.getInstance(getApplication()).log("***** MailService *****: starting new check"); MessagingController.getInstance(getApplication()).log("***** MailService *****: starting new check");
mListener.wakeLockAcquire(); mListener.wakeLockAcquire();
controller.setCheckMailListener(mListener); controller.setCheckMailListener(mListener);
controller.checkMail(this, null, mListener); controller.checkMail(this, null, mListener);
} }
else else
{ {
MessagingController.getInstance(getApplication()).log("***** MailService *****: renewing WakeLock"); MessagingController.getInstance(getApplication()).log("***** MailService *****: renewing WakeLock");
listener.wakeLockAcquire(); listener.wakeLockAcquire();
} }
reschedule(); reschedule();
stopSelf(startId); stopSelf(startId);
} }
else if (ACTION_CANCEL.equals(intent.getAction())) { else if (ACTION_CANCEL.equals(intent.getAction())) {
if (Config.LOGV) { if (Config.LOGV) {
Log.v(Email.LOG_TAG, "***** MailService *****: cancel"); Log.v(Email.LOG_TAG, "***** MailService *****: cancel");
} }
MessagingController.getInstance(getApplication()).log("***** MailService *****: cancel"); MessagingController.getInstance(getApplication()).log("***** MailService *****: cancel");
cancel(); cancel();
stopSelf(startId); stopSelf(startId);
} }
else if (ACTION_RESCHEDULE.equals(intent.getAction())) { else if (ACTION_RESCHEDULE.equals(intent.getAction())) {
if (Config.LOGV) { if (Config.LOGV) {
Log.v(Email.LOG_TAG, "***** MailService *****: reschedule"); Log.v(Email.LOG_TAG, "***** MailService *****: reschedule");
} }
MessagingController.getInstance(getApplication()).log("***** MailService *****: reschedule"); MessagingController.getInstance(getApplication()).log("***** MailService *****: reschedule");
reschedule(); reschedule();
stopSelf(startId); stopSelf(startId);
} }
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
Log.v(Email.LOG_TAG, "***** MailService *****: onDestroy()"); Log.v(Email.LOG_TAG, "***** MailService *****: onDestroy()");
super.onDestroy(); super.onDestroy();
// MessagingController.getInstance(getApplication()).removeListener(mListener); // MessagingController.getInstance(getApplication()).removeListener(mListener);
} }
private void cancel() { private void cancel() {
AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE); AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(); Intent i = new Intent();
i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService"); i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService");
i.setAction(ACTION_CHECK_MAIL); i.setAction(ACTION_CHECK_MAIL);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0); PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
alarmMgr.cancel(pi); alarmMgr.cancel(pi);
} }
private void reschedule() { private void reschedule() {
AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE); AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(); Intent i = new Intent();
i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService"); i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService");
i.setAction(ACTION_CHECK_MAIL); i.setAction(ACTION_CHECK_MAIL);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0); PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
int shortestInterval = -1; int shortestInterval = -1;
for (Account account : Preferences.getPreferences(this).getAccounts()) { for (Account account : Preferences.getPreferences(this).getAccounts()) {
if (account.getAutomaticCheckIntervalMinutes() != -1 if (account.getAutomaticCheckIntervalMinutes() != -1
&& (account.getAutomaticCheckIntervalMinutes() < shortestInterval || shortestInterval == -1)) { && (account.getAutomaticCheckIntervalMinutes() < shortestInterval || shortestInterval == -1)) {
shortestInterval = account.getAutomaticCheckIntervalMinutes(); shortestInterval = account.getAutomaticCheckIntervalMinutes();
} }
} }
if (shortestInterval == -1) { if (shortestInterval == -1) {
Log.v(Email.LOG_TAG, "No next check scheduled for package " + getApplication().getPackageName()); Log.v(Email.LOG_TAG, "No next check scheduled for package " + getApplication().getPackageName());
alarmMgr.cancel(pi); alarmMgr.cancel(pi);
} }
else else
{ {
long delay = (shortestInterval * (60 * 1000)); long delay = (shortestInterval * (60 * 1000));
long nextTime = System.currentTimeMillis() + delay; long nextTime = System.currentTimeMillis() + delay;
String checkString = "Next check for package " + getApplication().getPackageName() + " scheduled for " + new Date(nextTime); String checkString = "Next check for package " + getApplication().getPackageName() + " scheduled for " + new Date(nextTime);
Log.v(Email.LOG_TAG, checkString); Log.v(Email.LOG_TAG, checkString);
MessagingController.getInstance(getApplication()).log(checkString); MessagingController.getInstance(getApplication()).log(checkString);
alarmMgr.set(AlarmManager.RTC_WAKEUP, nextTime, pi); alarmMgr.set(AlarmManager.RTC_WAKEUP, nextTime, pi);
} }
} }
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
return null; return null;
} }
class Listener extends MessagingListener { class Listener extends MessagingListener {
HashMap<String, Integer> accountsWithNewMail = new HashMap<String, Integer>(); HashMap<String, Integer> accountsWithNewMail = new HashMap<String, Integer>();
private WakeLock wakeLock = null; private WakeLock wakeLock = null;
// wakelock strategy is to be very conservative. If there is any reason to release, then release // 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 // don't want to take the chance of running wild
public synchronized void wakeLockAcquire() public synchronized void wakeLockAcquire()
{ {
WakeLock oldWakeLock = wakeLock; WakeLock oldWakeLock = wakeLock;
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email"); wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email");
wakeLock.setReferenceCounted(false); wakeLock.setReferenceCounted(false);
wakeLock.acquire(Email.WAKE_LOCK_TIMEOUT); wakeLock.acquire(Email.WAKE_LOCK_TIMEOUT);
if (oldWakeLock != null) if (oldWakeLock != null)
{ {
oldWakeLock.release(); oldWakeLock.release();
} }
} }
public synchronized void wakeLockRelease() public synchronized void wakeLockRelease()
{ {
if (wakeLock != null) if (wakeLock != null)
{ {
wakeLock.release(); wakeLock.release();
wakeLock = null; wakeLock = null;
} }
} }
@Override @Override
public void checkMailStarted(Context context, Account account) { public void checkMailStarted(Context context, Account account) {
accountsWithNewMail.clear(); accountsWithNewMail.clear();
} }
@Override @Override
public void checkMailFailed(Context context, Account account, String reason) { public void checkMailFailed(Context context, Account account, String reason) {
release(); release();
} }
@Override @Override
public void synchronizeMailboxFinished( public void synchronizeMailboxFinished(
Account account, Account account,
String folder, String folder,
int totalMessagesInMailbox, int totalMessagesInMailbox,
int numNewMessages) { int numNewMessages) {
if (account.isNotifyNewMail() && numNewMessages > 0) { if (account.isNotifyNewMail() && numNewMessages > 0) {
accountsWithNewMail.put(account.getUuid(), numNewMessages); accountsWithNewMail.put(account.getUuid(), numNewMessages);
} }
} }
private void checkMailDone(Context context, Account doNotUseaccount) private void checkMailDone(Context context, Account doNotUseaccount)
{ {
if (accountsWithNewMail.isEmpty()) if (accountsWithNewMail.isEmpty())
{ {
return; return;
} }
StringBuffer notice = new StringBuffer();
int accountNumber = Email.FETCHING_EMAIL_NOTIFICATION_NO_ACCOUNT; NotificationManager notifMgr =
(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
boolean vibrate = false;
String ringtone = null; int index = 0;
for (Account thisAccount : Preferences.getPreferences(context).getAccounts()) { for (Account thisAccount : Preferences.getPreferences(context).getAccounts()) {
if (thisAccount.isNotifyNewMail()) //No need to filter out accounts that do not require notification
{ //since only the one that require so are in this map
int unreadMessageCount = 0; if (accountsWithNewMail.containsKey(thisAccount.getUuid()))
try {
{ String notice = null;
unreadMessageCount = thisAccount.getUnreadMessageCount(context, getApplication()); try
if (unreadMessageCount > 0) {
{ int unreadMessageCount = thisAccount.getUnreadMessageCount(context, getApplication());
notice.append(getString(R.string.notification_new_one_account_fmt, unreadMessageCount, if (unreadMessageCount > 0)
thisAccount.getDescription()) + "\n"); {
if (accountNumber != Email.FETCHING_EMAIL_NOTIFICATION_MULTI_ACCOUNT_ID) // if already set to Multi, nothing to do notice = getString(R.string.notification_new_one_account_fmt, unreadMessageCount,
{ thisAccount.getDescription());
if (accountNumber == Email.FETCHING_EMAIL_NOTIFICATION_NO_ACCOUNT) // Haven't set to anything, yet, set to this account number }
{ //Can this ever happen?
accountNumber = thisAccount.getAccountNumber(); else
} {
else // Another account was already set, so there is more than one with new mail notice = getString(R.string.notification_new_one_account_unknown_unread_count_fmt, (int)accountsWithNewMail.get(thisAccount.getUuid()), thisAccount.getDescription());
{ }
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);
catch (MessagingException me) notice = getString(R.string.notification_new_one_account_unknown_unread_count_fmt, (int)accountsWithNewMail.get(thisAccount.getUuid()), thisAccount.getDescription());
{ }
Log.e(Email.LOG_TAG, "***** MailService *****: couldn't get unread count for account " +
thisAccount.getDescription(), me); Notification notif = new Notification(R.drawable.stat_notify_email_generic,
} getString(R.string.notification_new_title), System.currentTimeMillis() + (index*1000));
if (accountsWithNewMail.containsKey(thisAccount.getUuid()))
{ Intent i = FolderMessageList.actionHandleAccountIntent(context, thisAccount, Email.INBOX);
if (ringtone == null)
{ PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0);
ringtone = thisAccount.getRingtone();
} notif.setLatestEventInfo(context, getString(R.string.notification_new_title), notice, pi);
vibrate |= thisAccount.isVibrate();
} String ringtone = thisAccount.getRingtone();
} notif.sound = TextUtils.isEmpty(ringtone) ? null : Uri.parse(ringtone);
}
if (notice.length() > 0) if (thisAccount.isVibrate()) {
{ notif.defaults |= Notification.DEFAULT_VIBRATE;
NotificationManager notifMgr = }
(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
notif.flags |= Notification.FLAG_SHOW_LIGHTS;
Notification notif = new Notification(R.drawable.stat_notify_email_generic, notif.ledARGB = Email.NOTIFICATION_LED_COLOR;
getString(R.string.notification_new_title), System.currentTimeMillis()); notif.ledOnMS = Email.NOTIFICATION_LED_ON_TIME;
notif.ledOffMS = Email.NOTIFICATION_LED_OFF_TIME;
// If only one account has mail, maybe go back to the old way of targetting the account.
Intent i = new Intent(context, Accounts.class); notifMgr.notify(thisAccount.getAccountNumber(), notif);
PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0); }
}//for accounts
notif.setLatestEventInfo(context, getString(R.string.notification_new_title), }//checkMailDone
notice, pi);
private void release()
Log.v(Email.LOG_TAG, "Using ringtone " + ringtone + " and vibrate = " + vibrate); {
MessagingController controller = MessagingController.getInstance(getApplication());
// notif.defaults = Notification.DEFAULT_LIGHTS; controller.setCheckMailListener(null);
notif.sound = TextUtils.isEmpty(ringtone) ? null : Uri.parse(ringtone); reschedule();
if (vibrate) { wakeLockRelease();
notif.defaults |= Notification.DEFAULT_VIBRATE; stopSelf(mStartId);
} }
notif.flags |= Notification.FLAG_SHOW_LIGHTS; @Override
notif.ledARGB = Email.NOTIFICATION_LED_COLOR; public void checkMailFinished(Context context, Account account) {
notif.ledOnMS = Email.NOTIFICATION_LED_ON_TIME;
notif.ledOffMS = Email.NOTIFICATION_LED_OFF_TIME; Log.v(Email.LOG_TAG, "***** MailService *****: checkMailFinished");
try
notifMgr.notify(accountNumber, notif); {
} checkMailDone(context, account);
}
} finally
{
private void release() 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();
}
}
}
}