From: Michael Chan Date: Thu, 29 Oct 2009 07:17:21 +0000 (-0700) Subject: b/2194249 Prevent Calendar from playing multiple notification tones around the same... X-Git-Tag: android-x86-2.2~83^2~4^2~2 X-Git-Url: http://git.osdn.net/view?p=android-x86%2Fpackages-apps-Calendar.git;a=commitdiff_plain;h=0e7235b00fdf47c773592a324c4a62ef95d1dcf4 b/2194249 Prevent Calendar from playing multiple notification tones around the same time. This is a safe but temp fix for overlapping ringtones playing at the same time. Change-Id: I8d8bc976837c0ef036626fd991bfcd2c91772c64 --- diff --git a/src/com/android/calendar/AlertService.java b/src/com/android/calendar/AlertService.java index 3719f6b..29170a9 100644 --- a/src/com/android/calendar/AlertService.java +++ b/src/com/android/calendar/AlertService.java @@ -51,11 +51,11 @@ import android.view.View; */ public class AlertService extends Service { private static final String TAG = "AlertService"; - + private volatile Looper mServiceLooper; private volatile ServiceHandler mServiceHandler; - - private static final String[] ALERT_PROJECTION = new String[] { + + private static final String[] ALERT_PROJECTION = new String[] { CalendarAlerts._ID, // 0 CalendarAlerts.EVENT_ID, // 1 CalendarAlerts.STATE, // 2 @@ -69,10 +69,10 @@ public class AlertService extends Service { }; // We just need a simple projection that returns any column - private static final String[] ALERT_PROJECTION_SMALL = new String[] { + private static final String[] ALERT_PROJECTION_SMALL = new String[] { CalendarAlerts._ID, // 0 }; - + private static final int ALERT_INDEX_ID = 0; private static final int ALERT_INDEX_EVENT_ID = 1; private static final int ALERT_INDEX_STATE = 2; @@ -89,14 +89,30 @@ public class AlertService extends Service { private static final int INSTANCES_INDEX_END = 1; // We just need a simple projection that returns any column - private static final String[] REMINDER_PROJECTION_SMALL = new String[] { + private static final String[] REMINDER_PROJECTION_SMALL = new String[] { Reminders._ID, // 0 }; - + + 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; + } + @SuppressWarnings("deprecation") void processMessage(Message msg) { Bundle bundle = (Bundle) msg.obj; - + // On reboot, update the notification bar with the contents of the // CalendarAlerts table. String action = bundle.getString("action"); @@ -112,6 +128,9 @@ public class AlertService extends Service { Log.d(TAG, "uri: " + alertUri); } + ContentResolver cr = getContentResolver(); + boolean alarmsFiredRecently = alarmsFiredRecently(cr); + if (alertUri != null) { if (!Calendar.AUTHORITY.equals(alertUri.getAuthority())) { Log.w(TAG, "Invalid AUTHORITY uri: " + alertUri); @@ -123,13 +142,12 @@ public class AlertService extends Service { // missed or delayed. ContentValues values = new ContentValues(); values.put(CalendarAlerts.RECEIVED_TIME, System.currentTimeMillis()); - getContentResolver().update(alertUri, values, null /* where */, null /* args */); + cr.update(alertUri, values, null /* where */, null /* args */); } - - ContentResolver cr = getContentResolver(); + Cursor alertCursor = cr.query(alertUri, ALERT_PROJECTION, null /* selection */, null, null /* sort order */); - + long alertId, eventId, alarmTime; int minutes; String eventName; @@ -151,9 +169,9 @@ public class AlertService extends Service { 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) == + 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; @@ -167,7 +185,7 @@ public class AlertService extends Service { alertCursor.close(); } } - + // Do not show an alert if the event was declined if (declined) { if (Log.isLoggable(TAG, Log.DEBUG)) { @@ -175,10 +193,10 @@ public class AlertService extends Service { } return; } - + 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 @@ -205,7 +223,7 @@ public class AlertService extends Service { 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. @@ -229,7 +247,7 @@ public class AlertService extends Service { } } } - + // If the event time was changed and the event has already ended, // then don't sound the alarm. if (alarmTime > instanceEnd) { @@ -258,7 +276,7 @@ public class AlertService extends Service { } 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 @@ -288,11 +306,11 @@ public class AlertService extends Service { } } } - + // 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); - + if (alertCursor == null || alertCursor.getCount() == 0) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "no fired alarms found"); @@ -324,13 +342,13 @@ public class AlertService extends Service { } finally { alertCursor.close(); } - + if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "creating new alarm notification, numReminders: " + numReminders); } 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 @@ -338,30 +356,44 @@ public class AlertService extends Service { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); String reminderType = prefs.getString(CalendarPreferenceActivity.KEY_ALERTS_TYPE, CalendarPreferenceActivity.ALERT_TYPE_STATUS_BAR); - + if (reminderType.equals(CalendarPreferenceActivity.ALERT_TYPE_OFF)) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "alert preference is OFF"); } return; } - - NotificationManager nm = + + NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - boolean reminderVibrate = + boolean reminderVibrate = prefs.getBoolean(CalendarPreferenceActivity.KEY_ALERTS_VIBRATE, false); - String reminderRingtone = - prefs.getString(CalendarPreferenceActivity.KEY_ALERTS_RINGTONE, null); // Possibly generate a vibration if (reminderVibrate) { notification.defaults |= Notification.DEFAULT_VIBRATE; } - - // Possibly generate a sound. If 'Silent' is chosen, the ringtone string will be empty. - notification.sound = TextUtils.isEmpty(reminderRingtone) ? null : Uri - .parse(reminderRingtone); - + + // Temp fix. If we sounded an notification recently, be quiet so the + // audio won't overlap. + + // 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); @@ -371,17 +403,17 @@ public class AlertService extends Service { 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. @@ -398,7 +430,7 @@ public class AlertService extends Service { nm.notify(0, notification); } - + private void doTimeChanged() { ContentResolver cr = getContentResolver(); Object service = getSystemService(Context.ALARM_SERVICE); @@ -406,19 +438,19 @@ public class AlertService extends Service { CalendarAlerts.rescheduleMissedAlarms(cr, this, manager); AlertReceiver.updateAlertNotification(this); } - + private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } - + @Override public void handleMessage(Message msg) { processMessage(msg); // NOTE: We MUST not call stopSelf() directly, since we need to // make sure the wake lock acquired by AlertReceiver is released. AlertReceiver.finishStartingService(AlertService.this, msg.arg1); - } + } }; @Override @@ -426,7 +458,7 @@ public class AlertService extends Service { HandlerThread thread = new HandlerThread("AlertService", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); - + mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); }