Merge "Prevent notifications from erroroneously bypassing 'repeat callers' filter" into nyc-mr1-dev
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index cbd0769..e368af2 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3150,6 +3150,12 @@
         }
     }
 
+    private void recordCallerLocked(NotificationRecord record) {
+        if (mZenModeHelper.isCall(record)) {
+            mZenModeHelper.recordCaller(record);
+        }
+    }
+
     // let zen mode evaluate this record
     private void applyZenModeLocked(NotificationRecord record) {
         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
@@ -3289,6 +3295,10 @@
     }
 
     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
+
+        // Record caller.
+        recordCallerLocked(r);
+
         // tell the app
         if (sendDelete) {
             if (r.getNotification().deleteIntent != null) {
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
index 80dc523..cbaad46 100644
--- a/services/core/java/com/android/server/notification/ZenModeFiltering.java
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -81,7 +81,9 @@
         if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) return false; // nothing gets through
         if (zen == Global.ZEN_MODE_ALARMS) return false; // not an alarm
         if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
-            if (config.allowRepeatCallers && REPEAT_CALLERS.isRepeat(context, extras)) return true;
+            if (config.allowRepeatCallers && REPEAT_CALLERS.isRepeat(context, extras)) {
+                return true;
+            }
             if (!config.allowCalls) return false; // no other calls get through
             if (validator != null) {
                 final float contactAffinity = validator.getContactAffinity(userHandle, extras,
@@ -97,6 +99,10 @@
                 ? record.sbn.getNotification().extras : null;
     }
 
+    protected void recordCall(NotificationRecord record) {
+        REPEAT_CALLERS.recordCall(mContext, extras(record));
+    }
+
     public boolean shouldIntercept(int zen, ZenModeConfig config, NotificationRecord record) {
         if (isSystem(record)) {
             return false;
@@ -233,28 +239,45 @@
     }
 
     private static class RepeatCallers {
+        // Person : time
         private final ArrayMap<String, Long> mCalls = new ArrayMap<>();
         private int mThresholdMinutes;
 
+        private synchronized void recordCall(Context context, Bundle extras) {
+            setThresholdMinutes(context);
+            if (mThresholdMinutes <= 0 || extras == null) return;
+            final String peopleString = peopleString(extras);
+            if (peopleString == null) return;
+            final long now = System.currentTimeMillis();
+            cleanUp(mCalls, now);
+            mCalls.put(peopleString, now);
+        }
+
         private synchronized boolean isRepeat(Context context, Bundle extras) {
-            if (mThresholdMinutes <= 0) {
-                mThresholdMinutes = context.getResources().getInteger(com.android.internal.R.integer
-                        .config_zen_repeat_callers_threshold);
-            }
+            setThresholdMinutes(context);
             if (mThresholdMinutes <= 0 || extras == null) return false;
             final String peopleString = peopleString(extras);
             if (peopleString == null) return false;
             final long now = System.currentTimeMillis();
-            final int N = mCalls.size();
+            cleanUp(mCalls, now);
+            return mCalls.containsKey(peopleString);
+        }
+
+        private synchronized void cleanUp(ArrayMap<String, Long> calls, long now) {
+            final int N = calls.size();
             for (int i = N - 1; i >= 0; i--) {
                 final long time = mCalls.valueAt(i);
                 if (time > now || (now - time) > mThresholdMinutes * 1000 * 60) {
-                    mCalls.removeAt(i);
+                    calls.removeAt(i);
                 }
             }
-            final boolean isRepeat = mCalls.containsKey(peopleString);
-            mCalls.put(peopleString, now);
-            return isRepeat;
+        }
+
+        private void setThresholdMinutes(Context context) {
+            if (mThresholdMinutes <= 0) {
+                mThresholdMinutes = context.getResources().getInteger(com.android.internal.R.integer
+                        .config_zen_repeat_callers_threshold);
+            }
         }
 
         private static String peopleString(Bundle extras) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 8c9dc3b..c22bfb3 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -139,8 +139,7 @@
             ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
         synchronized (mConfig) {
             return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig, userHandle,
-                    extras,
-                    validator, contactsTimeoutMs, timeoutAffinity);
+                    extras, validator, contactsTimeoutMs, timeoutAffinity);
         }
     }
 
@@ -148,6 +147,10 @@
         return mFiltering.isCall(record);
     }
 
+    public void recordCaller(NotificationRecord record) {
+        mFiltering.recordCall(record);
+    }
+
     public boolean shouldIntercept(NotificationRecord record) {
         synchronized (mConfig) {
             return mFiltering.shouldIntercept(mZenMode, mConfig, record);