Zen: New option to allow repeat callers.
Bug: 20064962
Change-Id: I11a5519c02bf8fa8e332559092c865c5e612fbd2
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
index 32fd01a..2aaeb9d 100644
--- a/services/core/java/com/android/server/notification/ZenModeFiltering.java
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -27,14 +27,19 @@
import android.provider.Settings.Secure;
import android.service.notification.ZenModeConfig;
import android.telecom.TelecomManager;
+import android.util.ArrayMap;
import android.util.Slog;
+import java.io.PrintWriter;
+import java.util.Date;
import java.util.Objects;
public class ZenModeFiltering {
private static final String TAG = ZenModeHelper.TAG;
private static final boolean DEBUG = ZenModeHelper.DEBUG;
+ static final RepeatCallers REPEAT_CALLERS = new RepeatCallers();
+
private final Context mContext;
private ComponentName mDefaultPhoneApp;
@@ -43,8 +48,25 @@
mContext = context;
}
- public ComponentName getDefaultPhoneApp() {
- return mDefaultPhoneApp;
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("mDefaultPhoneApp="); pw.println(mDefaultPhoneApp);
+ pw.print(prefix); pw.print("RepeatCallers.mThresholdMinutes=");
+ pw.println(REPEAT_CALLERS.mThresholdMinutes);
+ synchronized (REPEAT_CALLERS) {
+ if (!REPEAT_CALLERS.mCalls.isEmpty()) {
+ pw.print(prefix); pw.println("RepeatCallers.mCalls=");
+ for (int i = 0; i < REPEAT_CALLERS.mCalls.size(); i++) {
+ pw.print(prefix); pw.print(" ");
+ pw.print(REPEAT_CALLERS.mCalls.keyAt(i));
+ pw.print(" at ");
+ pw.println(ts(REPEAT_CALLERS.mCalls.valueAt(i)));
+ }
+ }
+ }
+ }
+
+ private static String ts(long time) {
+ return new Date(time) + " (" + time + ")";
}
/**
@@ -53,13 +75,14 @@
* @param timeoutAffinity affinity to return when the timeout specified via
* <code>contactsTimeoutMs</code> is hit
*/
- public static boolean matchesCallFilter(int zen, ZenModeConfig config, UserHandle userHandle,
- Bundle extras, ValidateNotificationPeople validator, int contactsTimeoutMs,
- float timeoutAffinity) {
+ public static boolean matchesCallFilter(Context context, int zen, ZenModeConfig config,
+ UserHandle userHandle, Bundle extras, ValidateNotificationPeople validator,
+ int contactsTimeoutMs, float timeoutAffinity) {
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.allowCalls) return false; // no calls get through
+ 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,
contactsTimeoutMs, timeoutAffinity);
@@ -69,6 +92,11 @@
return true;
}
+ private static Bundle extras(NotificationRecord record) {
+ return record != null && record.sbn != null && record.sbn.getNotification() != null
+ ? record.sbn.getNotification().extras : null;
+ }
+
public boolean shouldIntercept(int zen, ZenModeConfig config, NotificationRecord record) {
if (isSystem(record)) {
return false;
@@ -96,6 +124,11 @@
return false;
}
if (isCall(record)) {
+ if (config.allowRepeatCallers
+ && REPEAT_CALLERS.isRepeat(mContext, extras(record))) {
+ ZenLog.traceNotIntercepted(record, "repeatCaller");
+ return false;
+ }
if (!config.allowCalls) {
ZenLog.traceIntercepted(record, "!allowCalls");
return true;
@@ -199,4 +232,48 @@
return true;
}
}
+
+ private static class RepeatCallers {
+ private final ArrayMap<String, Long> mCalls = new ArrayMap<>();
+ private int mThresholdMinutes;
+
+ 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);
+ }
+ 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();
+ 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);
+ }
+ }
+ final boolean isRepeat = mCalls.containsKey(peopleString);
+ mCalls.put(peopleString, now);
+ return isRepeat;
+ }
+
+ private static String peopleString(Bundle extras) {
+ final String[] extraPeople = ValidateNotificationPeople.getExtraPeople(extras);
+ if (extraPeople == null || extraPeople.length == 0) return null;
+ final StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < extraPeople.length; i++) {
+ String extraPerson = extraPeople[i];
+ if (extraPerson == null) continue;
+ extraPerson = extraPerson.trim();
+ if (extraPerson.isEmpty()) continue;
+ if (sb.length() > 0) {
+ sb.append('|');
+ }
+ sb.append(extraPerson);
+ }
+ return sb.length() == 0 ? null : sb.toString();
+ }
+ }
+
}