Add message ID cache to detect duplicate broadcasts.

Ignore received broadcasts with message ID and geo scope matching
an already received cell broadcast. This prevents the display of
duplicate alerts when the user has deleted the original broadcast.

Bug: 6853691
Change-Id: I879be8fbdd092e4b6d26ecc074034ce79a4e284c
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java
index 5161dbb..dc1021f 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java
@@ -31,9 +31,12 @@
 import android.provider.Telephony;
 import android.telephony.CellBroadcastMessage;
 import android.telephony.SmsCbCmasInfo;
+import android.telephony.SmsCbLocation;
 import android.telephony.SmsCbMessage;
 import android.util.Log;
 
+import java.util.HashSet;
+
 /**
  * This service manages the display and animation of broadcast messages.
  * Emergency messages display with a flashing animated exclamation mark icon,
@@ -62,6 +65,42 @@
     /** Hold the wake lock for 5 seconds, which should be enough time to display the alert. */
     private static final int WAKE_LOCK_TIMEOUT = 5000;
 
+    /** Container for message ID and geographical scope, for duplicate message detection. */
+    private static final class MessageIdAndScope {
+        private final int mMessageId;
+        private final SmsCbLocation mLocation;
+
+        MessageIdAndScope(int messageId, SmsCbLocation location) {
+            mMessageId = messageId;
+            mLocation = location;
+        }
+
+        @Override
+        public int hashCode() {
+            return mMessageId * 31 + mLocation.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+            if (o instanceof MessageIdAndScope) {
+                MessageIdAndScope other = (MessageIdAndScope) o;
+                return (mMessageId == other.mMessageId && mLocation.equals(other.mLocation));
+            }
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return "{messageId: " + mMessageId + " location: " + mLocation.toString() + '}';
+        }
+    }
+
+    /** Cache of received message IDs, for duplicate message detection. */
+    private static final HashSet<MessageIdAndScope> sCmasIdList = new HashSet<MessageIdAndScope>(8);
+
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         String action = intent.getAction();
@@ -97,6 +136,14 @@
             return;
         }
 
+        // Set.add() returns false if message ID has already been added
+        MessageIdAndScope messageIdAndScope = new MessageIdAndScope(message.getSerialNumber(),
+                message.getLocation());
+        if (!sCmasIdList.add(messageIdAndScope)) {
+            Log.d(TAG, "ignoring duplicate alert with " + messageIdAndScope);
+            return;
+        }
+
         final Intent alertIntent = new Intent(SHOW_NEW_ALERT_ACTION);
         alertIntent.setClass(this, CellBroadcastAlertService.class);
         alertIntent.putExtra("message", cbm);