From c6b371b65935763d0d00711ed71db4a9d3620ae0 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Tue, 14 Jun 2016 08:31:03 -0400 Subject: [PATCH] Prevent notifications from erroroneously bypassing 'repeat callers' filter 1. Dialer uses a hidden api to check 'is repeat caller' that has side effects. Update to use a method without side effects 2. Delay the storage of person information until the notification is canceled, so ranking updates and notification updates don't bypass the filter. Note, this means that someone calling twice at overlapping times (?!) wouldn't get through the filter. Fixes: 29184211 Change-Id: I53ce402a0ed6f5df6f8265d571d401778dacebd3 --- .../NotificationManagerService.java | 10 +++++ .../server/notification/ZenModeFiltering.java | 43 ++++++++++++++----- .../server/notification/ZenModeHelper.java | 7 ++- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index cbd0769fdf687..e368af2fda5cb 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 @@ public class NotificationManagerService extends SystemService { } } + 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 @@ public class NotificationManagerService extends SystemService { } 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 80dc52349c343..cbaad460b8883 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 @@ public class ZenModeFiltering { 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 @@ public class ZenModeFiltering { ? 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 @@ public class ZenModeFiltering { } private static class RepeatCallers { + // Person : time private final ArrayMap 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 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 8c9dc3ba60f2c..c22bfb321a5ca 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { 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);