Implement API to have new broadcasts replace existing broadcasts.

Use this in various places where it should serve no purpose to deliver
both broadcasts.  This is intended to reduce somewhat the flurry of
broadcasts that we churn through during boot.
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 8d86219..18a5615 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -127,8 +127,9 @@
         mTimeTickSender = PendingIntent.getBroadcast(context, 0,
                 new Intent(Intent.ACTION_TIME_TICK).addFlags(
                         Intent.FLAG_RECEIVER_REGISTERED_ONLY), 0);
-        mDateChangeSender = PendingIntent.getBroadcast(context, 0,
-                new Intent(Intent.ACTION_DATE_CHANGED), 0);
+        Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+        mDateChangeSender = PendingIntent.getBroadcast(context, 0, intent, 0);
         
         // now that we have initied the driver schedule the alarm
         mClockReceiver= new ClockReceiver();
@@ -272,6 +273,7 @@
         
         if (timeZoneWasChanged) {
             Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
             intent.putExtra("time-zone", zone.getID());
             mContext.sendBroadcast(intent);
         }
@@ -609,7 +611,9 @@
                 if ((result & TIME_CHANGED_MASK) != 0) {
                     remove(mTimeTickSender);
                     mClockReceiver.scheduleTimeTickEvent();
-                    mContext.sendBroadcast(new Intent(Intent.ACTION_TIME_CHANGED));
+                    Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
+                    intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+                    mContext.sendBroadcast(intent);
                 }
                 
                 synchronized (mLock) {
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index e98fa99..bdebc8d 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -327,7 +327,8 @@
     private final void sendIntent() {
         //  Pack up the values and broadcast them to everyone
         Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
         try {
             mBatteryStats.setOnBattery(mPlugType == BATTERY_PLUGGED_NONE, mBatteryLevel);
         } catch (RemoteException e) {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 27b631e..77884a4 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -98,7 +98,7 @@
     private List mFeatureUsers;
 
     private boolean mSystemReady;
-    private ArrayList<Intent> mDeferredBroadcasts;
+    private Intent mInitialBroadcast;
 
     private static class NetworkAttributes {
         /**
@@ -786,6 +786,7 @@
         }
 
         Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
         if (info.isFailover()) {
             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
@@ -885,6 +886,7 @@
 
     private void sendConnectedBroadcast(NetworkInfo info) {
         Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
         if (info.isFailover()) {
             intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
@@ -922,6 +924,7 @@
         }
 
         Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
         intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
         if (getActiveNetworkInfo() == null) {
             intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
@@ -941,26 +944,20 @@
 
     private void sendStickyBroadcast(Intent intent) {
         synchronized(this) {
-            if (mSystemReady) {
-                mContext.sendStickyBroadcast(intent);
-            } else {
-                if (mDeferredBroadcasts == null) {
-                    mDeferredBroadcasts = new ArrayList<Intent>();
-                }
-                mDeferredBroadcasts.add(intent);
+            if (!mSystemReady) {
+                mInitialBroadcast = new Intent(intent);
             }
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+            mContext.sendStickyBroadcast(intent);
         }
     }
 
     void systemReady() {
         synchronized(this) {
             mSystemReady = true;
-            if (mDeferredBroadcasts != null) {
-                int count = mDeferredBroadcasts.size();
-                for (int i = 0; i < count; i++) {
-                    mContext.sendStickyBroadcast(mDeferredBroadcasts.get(i));
-                }
-                mDeferredBroadcasts = null;
+            if (mInitialBroadcast != null) {
+                mContext.sendStickyBroadcast(mInitialBroadcast);
+                mInitialBroadcast = null;
             }
         }
     }
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 2fff54c..6ea50c7 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -179,6 +179,7 @@
                 }
                 // Pack up the values and broadcast them to everyone
                 Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
+                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
                 intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
 
                 // Check if this is Bluetooth Dock
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index a64cb1a..405dc2e 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -949,6 +949,7 @@
 
             if (ActivityManagerNative.isSystemReady()) {
                 Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
+                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
                 intent.putExtra("input_method_id", id);
                 mContext.sendBroadcast(intent);
             }
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 47cb6ad..3bee40c 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -485,6 +485,7 @@
         }
 
         Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
         Bundle data = new Bundle();
         state.fillInNotifierBundle(data);
         intent.putExtras(data);
@@ -502,6 +503,7 @@
         }
 
         Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
         Bundle data = new Bundle();
         signalStrength.fillInNotifierBundle(data);
         intent.putExtras(data);
@@ -523,6 +525,7 @@
         }
 
         Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
         intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertCallState(state).toString());
         if (!TextUtils.isEmpty(incomingNumber)) {
             intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
@@ -537,6 +540,7 @@
         // status bar takes care of that after taking into account all of the
         // required info.
         Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
         intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertDataState(state).toString());
         if (!isDataConnectivityPossible) {
             intent.putExtra(Phone.NETWORK_UNAVAILABLE_KEY, true);
@@ -559,6 +563,7 @@
 
     private void broadcastDataConnectionFailed(String reason) {
         Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
         intent.putExtra(Phone.FAILURE_REASON_KEY, reason);
         mContext.sendStickyBroadcast(intent);
     }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index fc47f93..1eeb49f 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -11844,6 +11844,12 @@
             // pm is in same process, this will never happen.
         }
 
+        final boolean replacePending =
+                (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
+        
+        if (DEBUG_BROADCAST) Log.v(TAG, "Enqueing broadcast: " + intent.getAction()
+                + " replacePending=" + replacePending);
+        
         int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
         if (!ordered && NR > 0) {
             // If we are not serializing this broadcast, then send the
@@ -11856,8 +11862,22 @@
             if (DEBUG_BROADCAST) Log.v(
                     TAG, "Enqueueing parallel broadcast " + r
                     + ": prev had " + mParallelBroadcasts.size());
-            mParallelBroadcasts.add(r);
-            scheduleBroadcastsLocked();
+            boolean replaced = false;
+            if (replacePending) {
+                for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
+                    if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
+                        if (DEBUG_BROADCAST) Log.v(TAG,
+                                "***** DROPPING PARALLEL: " + intent);
+                        mParallelBroadcasts.set(i, r);
+                        replaced = true;
+                        break;
+                    }
+                }
+            }
+            if (!replaced) {
+                mParallelBroadcasts.add(r);
+                scheduleBroadcastsLocked();
+            }
             registeredReceivers = null;
             NR = 0;
         }
@@ -11940,8 +11960,22 @@
                 int seq = r.intent.getIntExtra("seq", -1);
                 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
             }
-            mOrderedBroadcasts.add(r);
-            scheduleBroadcastsLocked();
+            boolean replaced = false;
+            if (replacePending) {
+                for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
+                    if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
+                        if (DEBUG_BROADCAST) Log.v(TAG,
+                                "***** DROPPING ORDERED: " + intent);
+                        mOrderedBroadcasts.set(i, r);
+                        replaced = true;
+                        break;
+                    }
+                }
+            }
+            if (!replaced) {
+                mOrderedBroadcasts.add(r);
+                scheduleBroadcastsLocked();
+            }
         }
 
         return BROADCAST_SUCCESS;
@@ -12837,7 +12871,8 @@
                     }
                 }
                 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
-                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                        | Intent.FLAG_RECEIVER_REPLACE_PENDING);
                 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
                         null, false, false, MY_PID, Process.SYSTEM_UID);
                 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {