OSDN Git Service

Bug 2457183
[android-x86/packages-apps-Calendar.git] / src / com / android / calendar / AlertService.java
index 29170a9..73c1831 100644 (file)
@@ -21,11 +21,13 @@ import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.Service;
 import android.content.ContentResolver;
+import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.database.Cursor;
+import android.media.AudioManager;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -35,21 +37,18 @@ import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
 import android.preference.PreferenceManager;
-import android.provider.Calendar;
 import android.provider.Calendar.Attendees;
 import android.provider.Calendar.CalendarAlerts;
-import android.provider.Calendar.Instances;
-import android.provider.Calendar.Reminders;
 import android.text.TextUtils;
-import android.text.format.DateUtils;
 import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
+
+import java.util.HashMap;
 
 /**
  * This service is used to handle calendar event reminders.
  */
 public class AlertService extends Service {
+    static final boolean DEBUG = true;
     private static final String TAG = "AlertService";
 
     private volatile Looper mServiceLooper;
@@ -66,11 +65,7 @@ public class AlertService extends Service {
         CalendarAlerts.ALARM_TIME,              // 7
         CalendarAlerts.MINUTES,                 // 8
         CalendarAlerts.BEGIN,                   // 9
-    };
-
-    // We just need a simple projection that returns any column
-    private static final String[] ALERT_PROJECTION_SMALL = new String[] {
-        CalendarAlerts._ID,                     // 0
+        CalendarAlerts.END,                     // 10
     };
 
     private static final int ALERT_INDEX_ID = 0;
@@ -83,31 +78,16 @@ public class AlertService extends Service {
     private static final int ALERT_INDEX_ALARM_TIME = 7;
     private static final int ALERT_INDEX_MINUTES = 8;
     private static final int ALERT_INDEX_BEGIN = 9;
+    private static final int ALERT_INDEX_END = 10;
 
-    private String[] INSTANCE_PROJECTION = { Instances.BEGIN, Instances.END };
-    private static final int INSTANCES_INDEX_BEGIN = 0;
-    private static final int INSTANCES_INDEX_END = 1;
+    private static final String ACTIVE_ALERTS_SELECTION = "(" + CalendarAlerts.STATE + "=? OR "
+            + CalendarAlerts.STATE + "=?) AND " + CalendarAlerts.ALARM_TIME + "<=";
 
-    // We just need a simple projection that returns any column
-    private static final String[] REMINDER_PROJECTION_SMALL = new String[] {
-        Reminders._ID,                     // 0
+    private static final String[] ACTIVE_ALERTS_SELECTION_ARGS = new String[] {
+            Integer.toString(CalendarAlerts.FIRED), Integer.toString(CalendarAlerts.SCHEDULED)
     };
 
-    private final boolean alarmsFiredRecently(ContentResolver cr) {
-        String selection = CalendarAlerts.RECEIVED_TIME + ">="
-                + (System.currentTimeMillis() - 10000);
-        String[] projection = new String[] { CalendarAlerts.ALARM_TIME };
-        Cursor cursor = cr.query(CalendarAlerts.CONTENT_URI, projection, selection, null, null);
-
-        boolean recentAlarms = false;
-        if (cursor != null) {
-            if (cursor.moveToFirst() && cursor.getCount() > 0) {
-                recentAlarms = true;
-            }
-            cursor.close();
-        }
-        return recentAlarms;
-    }
+    private static final String ACTIVE_ALERTS_SORT = "begin DESC, end DESC";
 
     @SuppressWarnings("deprecation")
     void processMessage(Message msg) {
@@ -116,316 +96,253 @@ public class AlertService extends Service {
         // On reboot, update the notification bar with the contents of the
         // CalendarAlerts table.
         String action = bundle.getString("action");
+        if (DEBUG) {
+            Log.d(TAG, "" + bundle.getLong(android.provider.Calendar.CalendarAlerts.ALARM_TIME)
+                    + " Action = " + action);
+        }
+
         if (action.equals(Intent.ACTION_BOOT_COMPLETED)
                 || action.equals(Intent.ACTION_TIME_CHANGED)) {
             doTimeChanged();
             return;
         }
 
-        // The Uri specifies an entry in the CalendarAlerts table
-        Uri alertUri = Uri.parse(bundle.getString("uri"));
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "uri: " + alertUri);
+        if (!action.equals(android.provider.Calendar.EVENT_REMINDER_ACTION)
+                && !action.equals(Intent.ACTION_LOCALE_CHANGED)) {
+            Log.w(TAG, "Invalid action: " + action);
+            return;
         }
 
-        ContentResolver cr = getContentResolver();
-        boolean alarmsFiredRecently = alarmsFiredRecently(cr);
-
-        if (alertUri != null) {
-            if (!Calendar.AUTHORITY.equals(alertUri.getAuthority())) {
-                Log.w(TAG, "Invalid AUTHORITY uri: " + alertUri);
-                return;
-            }
+        updateAlertNotification(this);
+    }
 
-            // Record the received time in the CalendarAlerts table.
-            // This is useful for finding bugs that cause alarms to be
-            // missed or delayed.
-            ContentValues values = new ContentValues();
-            values.put(CalendarAlerts.RECEIVED_TIME, System.currentTimeMillis());
-            cr.update(alertUri, values, null /* where */, null /* args */);
-        }
+    static boolean updateAlertNotification(Context context) {
+        ContentResolver cr = context.getContentResolver();
+        final long currentTime = System.currentTimeMillis();
 
-        Cursor alertCursor = cr.query(alertUri, ALERT_PROJECTION,
-                null /* selection */, null, null /* sort order */);
+        Cursor alertCursor = CalendarAlerts.query(cr, ALERT_PROJECTION, ACTIVE_ALERTS_SELECTION
+                + currentTime, ACTIVE_ALERTS_SELECTION_ARGS, ACTIVE_ALERTS_SORT);
 
-        long alertId, eventId, alarmTime;
-        int minutes;
-        String eventName;
-        String location;
-        boolean allDay;
-        boolean declined = false;
-        try {
-            if (alertCursor == null || !alertCursor.moveToFirst()) {
-                // This can happen if the event was deleted.
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "alert not found");
-                }
-                return;
-            }
-            alertId = alertCursor.getLong(ALERT_INDEX_ID);
-            eventId = alertCursor.getLong(ALERT_INDEX_EVENT_ID);
-            minutes = alertCursor.getInt(ALERT_INDEX_MINUTES);
-            eventName = alertCursor.getString(ALERT_INDEX_TITLE);
-            location = alertCursor.getString(ALERT_INDEX_EVENT_LOCATION);
-            allDay = alertCursor.getInt(ALERT_INDEX_ALL_DAY) != 0;
-            alarmTime = alertCursor.getLong(ALERT_INDEX_ALARM_TIME);
-            declined = alertCursor.getInt(ALERT_INDEX_SELF_ATTENDEE_STATUS) ==
-                    Attendees.ATTENDEE_STATUS_DECLINED;
-
-            // If the event was declined, then mark the alarm DISMISSED,
-            // otherwise, mark the alarm FIRED.
-            int newState = CalendarAlerts.FIRED;
-            if (declined) {
-                newState = CalendarAlerts.DISMISSED;
-            }
-            alertCursor.updateInt(ALERT_INDEX_STATE, newState);
-            alertCursor.commitUpdates();
-        } finally {
+        if (alertCursor == null || alertCursor.getCount() == 0) {
             if (alertCursor != null) {
                 alertCursor.close();
             }
+
+            if (DEBUG) Log.d(TAG, "No fired or scheduled alerts");
+            NotificationManager nm =
+                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+            nm.cancel(0);
+            return false;
         }
 
-        // Do not show an alert if the event was declined
-        if (declined) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "event declined, alert cancelled");
-            }
-            return;
+        if (DEBUG) {
+            Log.d(TAG, "alert count:" + alertCursor.getCount());
         }
 
-        long beginTime = bundle.getLong(Calendar.EVENT_BEGIN_TIME, 0);
-        long endTime = bundle.getLong(Calendar.EVENT_END_TIME, 0);
-
-        // Check if this alarm is still valid.  The time of the event may
-        // have been changed, or the reminder may have been changed since
-        // this alarm was set. First, search for an instance in the Instances
-        // that has the same event id and the same begin and end time.
-        // Then check for a reminder in the Reminders table to ensure that
-        // the reminder minutes is consistent with this alarm.
-        String selection = Instances.EVENT_ID + "=" + eventId;
-        Cursor instanceCursor = Instances.query(cr, INSTANCE_PROJECTION,
-                beginTime, endTime, selection, Instances.DEFAULT_SORT_ORDER);
-        long instanceBegin = 0, instanceEnd = 0;
+        String notificationEventName = null;
+        String notificationEventLocation = null;
+        long notificationEventBegin = 0;
+        int notificationEventStatus = 0;
+        HashMap<Long, Long> eventIds = new HashMap<Long, Long>();
+        int numReminders = 0;
+        int numFired = 0;
         try {
-            if (instanceCursor == null || !instanceCursor.moveToFirst()) {
-                // Delete this alarm from the CalendarAlerts table
-                cr.delete(alertUri, null /* selection */, null /* selection args */);
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "instance not found, alert cancelled");
+            while (alertCursor.moveToNext()) {
+                final long alertId = alertCursor.getLong(ALERT_INDEX_ID);
+                final long eventId = alertCursor.getLong(ALERT_INDEX_EVENT_ID);
+                final int minutes = alertCursor.getInt(ALERT_INDEX_MINUTES);
+                final String eventName = alertCursor.getString(ALERT_INDEX_TITLE);
+                final String location = alertCursor.getString(ALERT_INDEX_EVENT_LOCATION);
+                final boolean allDay = alertCursor.getInt(ALERT_INDEX_ALL_DAY) != 0;
+                final int status = alertCursor.getInt(ALERT_INDEX_SELF_ATTENDEE_STATUS);
+                final boolean declined = status == Attendees.ATTENDEE_STATUS_DECLINED;
+                final long beginTime = alertCursor.getLong(ALERT_INDEX_BEGIN);
+                final long endTime = alertCursor.getLong(ALERT_INDEX_END);
+                final Uri alertUri = ContentUris
+                        .withAppendedId(CalendarAlerts.CONTENT_URI, alertId);
+                final long alarmTime = alertCursor.getLong(ALERT_INDEX_ALARM_TIME);
+                int state = alertCursor.getInt(ALERT_INDEX_STATE);
+
+                if (DEBUG) {
+                    Log.d(TAG, "alarmTime:" + alarmTime + " alertId:" + alertId
+                            + " eventId:" + eventId + " state: " + state + " minutes:" + minutes
+                            + " declined:" + declined + " beginTime:" + beginTime
+                            + " endTime:" + endTime);
                 }
-                return;
-            }
-            instanceBegin = instanceCursor.getLong(INSTANCES_INDEX_BEGIN);
-            instanceEnd = instanceCursor.getLong(INSTANCES_INDEX_END);
-        } finally {
-            if (instanceCursor != null) {
-                instanceCursor.close();
-            }
-        }
 
-        // Check that a reminder for this event exists with the same number
-        // of minutes.  But snoozed alarms have minutes = 0, so don't do this
-        // check for snoozed alarms.
-        if (minutes > 0) {
-            selection = Reminders.EVENT_ID + "=" + eventId
-                + " AND " + Reminders.MINUTES + "=" + minutes;
-            Cursor reminderCursor = cr.query(Reminders.CONTENT_URI, REMINDER_PROJECTION_SMALL,
-                    selection, null /* selection args */, null /* sort order */);
-            try {
-                if (reminderCursor == null || reminderCursor.getCount() == 0) {
-                    // Delete this alarm from the CalendarAlerts table
-                    cr.delete(alertUri, null /* selection */, null /* selection args */);
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "reminder not found, alert cancelled");
+                ContentValues values = new ContentValues();
+                int newState = -1;
+
+                // Uncomment for the behavior of clearing out alerts after the
+                // events ended. b/1880369
+                //
+                // if (endTime < currentTime) {
+                //     newState = CalendarAlerts.DISMISSED;
+                // } else
+
+                // Remove declined events and duplicate alerts for the same event
+                if (!declined && eventIds.put(eventId, beginTime) == null) {
+                    numReminders++;
+                    if (state == CalendarAlerts.SCHEDULED) {
+                        newState = CalendarAlerts.FIRED;
+                        numFired++;
+
+                        // Record the received time in the CalendarAlerts table.
+                        // This is useful for finding bugs that cause alarms to be
+                        // missed or delayed.
+                        values.put(CalendarAlerts.RECEIVED_TIME, currentTime);
+                    }
+                } else {
+                    newState = CalendarAlerts.DISMISSED;
+                    if (DEBUG) {
+                        if (!declined) Log.d(TAG, "dropping dup alert for event " + eventId);
                     }
-                    return;
-                }
-            } finally {
-                if (reminderCursor != null) {
-                    reminderCursor.close();
                 }
-            }
-        }
-
-        // If the event time was changed and the event has already ended,
-        // then don't sound the alarm.
-        if (alarmTime > instanceEnd) {
-            // Delete this alarm from the CalendarAlerts table
-            cr.delete(alertUri, null /* selection */, null /* selection args */);
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "event ended, alert cancelled");
-            }
-            return;
-        }
 
-        // If minutes > 0, then this is a normal alarm (not a snoozed alarm)
-        // so check for duplicate alarms.  A duplicate alarm can occur when
-        // the start time of an event is changed to an earlier time.  The
-        // later alarm (that was first scheduled for the later event time)
-        // should be discarded.
-        long computedAlarmTime = instanceBegin - minutes * DateUtils.MINUTE_IN_MILLIS;
-        if (minutes > 0 && computedAlarmTime != alarmTime) {
-            // If the event time was changed to a later time, then the computed
-            // alarm time is in the future and we shouldn't sound this alarm.
-            if (computedAlarmTime > alarmTime) {
-                // Delete this alarm from the CalendarAlerts table
-                cr.delete(alertUri, null /* selection */, null /* selection args */);
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "event postponed, alert cancelled");
+                // Update row if state changed
+                if (newState != -1) {
+                    values.put(CalendarAlerts.STATE, newState);
+                    state = newState;
                 }
-                return;
-            }
 
-            // Check for another alarm in the CalendarAlerts table that has the
-            // same event id and the same "minutes".  This can occur
-            // if the event start time was changed to an earlier time and the
-            // alarm for the later time goes off.  To avoid discarding alarms
-            // for repeating events (that have the same event id), we check
-            // that the other alarm fired recently (within an hour of this one).
-            long recently = alarmTime - 60 * DateUtils.MINUTE_IN_MILLIS;
-            selection = CalendarAlerts.EVENT_ID + "=" + eventId
-                    + " AND " + CalendarAlerts.TABLE_NAME + "." + CalendarAlerts._ID
-                    + "!=" + alertId
-                    + " AND " + CalendarAlerts.MINUTES + "=" + minutes
-                    + " AND " + CalendarAlerts.ALARM_TIME + ">" + recently
-                    + " AND " + CalendarAlerts.ALARM_TIME + "<=" + alarmTime;
-            alertCursor = CalendarAlerts.query(cr, ALERT_PROJECTION_SMALL, selection, null);
-            if (alertCursor != null) {
-                try {
-                    if (alertCursor.getCount() > 0) {
-                        // Delete this alarm from the CalendarAlerts table
-                        cr.delete(alertUri, null /* selection */, null /* selection args */);
-                        if (Log.isLoggable(TAG, Log.DEBUG)) {
-                            Log.d(TAG, "duplicate alarm, alert cancelled");
-                        }
-                        return;
-                    }
-                } finally {
-                    alertCursor.close();
+                if (state == CalendarAlerts.FIRED) {
+                    // Record the time posting to notification manager.
+                    // This is used for debugging missed alarms.
+                    values.put(CalendarAlerts.NOTIFY_TIME, currentTime);
                 }
-            }
-        }
 
-        // Find all the alerts that have fired but have not been dismissed
-        selection = CalendarAlerts.STATE + "=" + CalendarAlerts.FIRED;
-        alertCursor = CalendarAlerts.query(cr, ALERT_PROJECTION, selection, null);
+                // Write row to if anything changed
+                if (values.size() > 0) cr.update(alertUri, values, null, null);
 
-        if (alertCursor == null || alertCursor.getCount() == 0) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "no fired alarms found");
-            }
-            return;
-        }
+                if (state != CalendarAlerts.FIRED) {
+                    continue;
+                }
 
-        int numReminders = alertCursor.getCount();
-        try {
-            while (alertCursor.moveToNext()) {
-                long otherEventId = alertCursor.getLong(ALERT_INDEX_EVENT_ID);
-                long otherAlertId = alertCursor.getLong(ALERT_INDEX_ID);
-                int otherAlarmState = alertCursor.getInt(ALERT_INDEX_STATE);
-                long otherBeginTime = alertCursor.getLong(ALERT_INDEX_BEGIN);
-                if (otherEventId == eventId && otherAlertId != alertId
-                        && otherAlarmState == CalendarAlerts.FIRED
-                        && otherBeginTime == beginTime) {
-                    // This event already has an alert that fired and has not
-                    // been dismissed.  This can happen if an event has
-                    // multiple reminders.  Do not count this as a separate
-                    // reminder.  But we do want to sound the alarm and vibrate
-                    // the phone, if necessary.
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "multiple alarms for this event");
-                    }
-                    numReminders -= 1;
+                // Pick an Event title for the notification panel by the latest
+                // alertTime and give prefer accepted events in case of ties.
+                int newStatus;
+                switch (status) {
+                    case Attendees.ATTENDEE_STATUS_ACCEPTED:
+                        newStatus = 2;
+                        break;
+                    case Attendees.ATTENDEE_STATUS_TENTATIVE:
+                        newStatus = 1;
+                        break;
+                    default:
+                        newStatus = 0;
+                }
+
+                // TODO Prioritize by "primary" calendar
+                // Assumes alerts are sorted by begin time in reverse
+                if (notificationEventName == null
+                        || (notificationEventBegin <= beginTime &&
+                                notificationEventStatus < newStatus)) {
+                    notificationEventName = eventName;
+                    notificationEventLocation = location;
+                    notificationEventBegin = beginTime;
+                    notificationEventStatus = newStatus;
                 }
             }
         } finally {
-            alertCursor.close();
-        }
-
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "creating new alarm notification, numReminders: " + numReminders);
+            if (alertCursor != null) {
+                alertCursor.close();
+            }
         }
-        Notification notification = AlertReceiver.makeNewAlertNotification(this, eventName,
-                location, numReminders);
 
-        // Generate either a pop-up dialog, status bar notification, or
-        // neither. Pop-up dialog and status bar notification may include a
-        // sound, an alert, or both. A status bar notification also includes
-        // a toast.
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
         String reminderType = prefs.getString(CalendarPreferenceActivity.KEY_ALERTS_TYPE,
                 CalendarPreferenceActivity.ALERT_TYPE_STATUS_BAR);
 
+        // TODO check for this before adding stuff to the alerts table.
         if (reminderType.equals(CalendarPreferenceActivity.ALERT_TYPE_OFF)) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 Log.d(TAG, "alert preference is OFF");
             }
-            return;
+            return true;
+        }
+
+        postNotification(context, prefs, notificationEventName, notificationEventLocation,
+                numReminders, numFired == 0 /* quiet update */);
+
+        if (numFired > 0 && reminderType.equals(CalendarPreferenceActivity.ALERT_TYPE_ALERTS)) {
+            Intent alertIntent = new Intent();
+            alertIntent.setClass(context, AlertActivity.class);
+            alertIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            context.startActivity(alertIntent);
+        }
+
+        return true;
+    }
+
+    private static void postNotification(Context context, SharedPreferences prefs,
+            String eventName, String location, int numReminders, boolean quietUpdate) {
+        if (DEBUG) {
+            Log.d(TAG, "###### creating new alarm notification, numReminders: " + numReminders
+                    + (quietUpdate ? " QUIET" : " loud"));
         }
 
         NotificationManager nm =
-            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-        boolean reminderVibrate =
-                prefs.getBoolean(CalendarPreferenceActivity.KEY_ALERTS_VIBRATE, false);
+                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
 
-        // Possibly generate a vibration
-        if (reminderVibrate) {
-            notification.defaults |= Notification.DEFAULT_VIBRATE;
+        if (numReminders == 0) {
+            nm.cancel(0);
+            return;
         }
 
-        // Temp fix. If we sounded an notification recently, be quiet so the
-        // audio won't overlap.
+        Notification notification = AlertReceiver.makeNewAlertNotification(context, eventName,
+                location, numReminders);
+        notification.defaults |= Notification.DEFAULT_LIGHTS;
+
+        // Quietly update notification bar. Nothing new. Maybe something just got deleted.
+        if (!quietUpdate) {
+            // Flash ticker in status bar
+            notification.tickerText = eventName;
+            if (!TextUtils.isEmpty(location)) {
+                notification.tickerText = eventName + " - " + location;
+            }
+
+            // Generate either a pop-up dialog, status bar notification, or
+            // neither. Pop-up dialog and status bar notification may include a
+            // sound, an alert, or both. A status bar notification also includes
+            // a toast.
+
+            // Find out the circumstances under which to vibrate.
+            // Migrate from pre-Froyo boolean setting if necessary.
+            String vibrateWhen; // "always" or "silent" or "never"
+            if(prefs.contains(CalendarPreferenceActivity.KEY_ALERTS_VIBRATE_WHEN))
+            {
+                // Look up Froyo setting
+                vibrateWhen =
+                    prefs.getString(CalendarPreferenceActivity.KEY_ALERTS_VIBRATE_WHEN, null);
+            } else if(prefs.contains(CalendarPreferenceActivity.KEY_ALERTS_VIBRATE)) {
+                // No Froyo setting. Migrate pre-Froyo setting to new Froyo-defined value.
+                boolean vibrate =
+                    prefs.getBoolean(CalendarPreferenceActivity.KEY_ALERTS_VIBRATE, false);
+                vibrateWhen = vibrate ?
+                    context.getString(R.string.prefDefault_alerts_vibrate_true) :
+                    context.getString(R.string.prefDefault_alerts_vibrate_false);
+            } else {
+                // No setting. Use Froyo-defined default.
+                vibrateWhen = context.getString(R.string.prefDefault_alerts_vibrateWhen);
+            }
+            boolean vibrateAlways = vibrateWhen.equals("always");
+            boolean vibrateSilent = vibrateWhen.equals("silent");
+            AudioManager audioManager =
+                (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
+            boolean nowSilent =
+                audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
+
+            // Possibly generate a vibration
+            if (vibrateAlways || (vibrateSilent && nowSilent)) {
+                notification.defaults |= Notification.DEFAULT_VIBRATE;
+            }
 
-        // TODO Long term fix: CalendarProvider currently setup an alarm with
-        // AlarmManager for each event notification. So AlertService can post
-        // multiple notifications back to back if there are multiple alarms that
-        // fire at the same time. Instead of doing that, CalendarProvider should
-        // setup one alarm for each wake up time. AlertService can query for
-        // alerts table and update notification manager only once.
-        if (!alarmsFiredRecently) {
             // Possibly generate a sound. If 'Silent' is chosen, the ringtone
             // string will be empty.
             String reminderRingtone = prefs.getString(
                     CalendarPreferenceActivity.KEY_ALERTS_RINGTONE, null);
             notification.sound = TextUtils.isEmpty(reminderRingtone) ? null : Uri
                     .parse(reminderRingtone);
-        } else {
-            notification.sound = null;
-        }
-
-        if (reminderType.equals(CalendarPreferenceActivity.ALERT_TYPE_ALERTS)) {
-            Intent alertIntent = new Intent();
-            alertIntent.setClass(this, AlertActivity.class);
-            alertIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            startActivity(alertIntent);
-        } else {
-            LayoutInflater inflater;
-            inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-            View view = inflater.inflate(R.layout.alert_toast, null);
-
-            AlertAdapter.updateView(this, view, eventName, location, beginTime, endTime, allDay);
-        }
-
-        // Record the notify time in the CalendarAlerts table.
-        // This is used for debugging missed alarms.
-        ContentValues values = new ContentValues();
-        long currentTime = System.currentTimeMillis();
-        values.put(CalendarAlerts.NOTIFY_TIME, currentTime);
-        cr.update(alertUri, values, null /* where */, null /* args */);
-
-        // The notification time should be pretty close to the reminder time
-        // that the user set for this event.  If the notification is late, then
-        // that's a bug and we should log an error.
-        if (currentTime > alarmTime + DateUtils.MINUTE_IN_MILLIS) {
-            long minutesLate = (currentTime - alarmTime) / DateUtils.MINUTE_IN_MILLIS;
-            int flags = DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_TIME;
-            String alarmTimeStr = DateUtils.formatDateTime(this, alarmTime, flags);
-            String currentTimeStr = DateUtils.formatDateTime(this, currentTime, flags);
-            Log.w(TAG, "Calendar reminder alarm for event id " + eventId
-                    + " is " + minutesLate + " minute(s) late;"
-                    + " expected alarm at: " + alarmTimeStr
-                    + " but got it at: " + currentTimeStr);
         }
 
         nm.notify(0, notification);
@@ -436,7 +353,7 @@ public class AlertService extends Service {
         Object service = getSystemService(Context.ALARM_SERVICE);
         AlarmManager manager = (AlarmManager) service;
         CalendarAlerts.rescheduleMissedAlarms(cr, this, manager);
-        AlertReceiver.updateAlertNotification(this);
+        updateAlertNotification(this);
     }
 
     private final class ServiceHandler extends Handler {
@@ -451,7 +368,7 @@ public class AlertService extends Service {
             // make sure the wake lock acquired by AlertReceiver is released.
             AlertReceiver.finishStartingService(AlertService.this, msg.arg1);
         }
-    };
+    }
 
     @Override
     public void onCreate() {