OSDN Git Service

b/2194249 Prevent Calendar from playing multiple notification tones around the same...
authorMichael Chan <mchan@android.com>
Thu, 29 Oct 2009 07:17:21 +0000 (00:17 -0700)
committerMichael Chan <mchan@android.com>
Thu, 29 Oct 2009 17:09:36 +0000 (10:09 -0700)
This is a safe but temp fix for overlapping ringtones playing at the same time.

Change-Id: I8d8bc976837c0ef036626fd991bfcd2c91772c64

src/com/android/calendar/AlertService.java

index 3719f6b..29170a9 100644 (file)
@@ -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);
     }