Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1d7d2248 authored by John Spurlock's avatar John Spurlock
Browse files

Zen: New option to allow repeat callers.

Bug: 20064962
Change-Id: I11a5519c02bf8fa8e332559092c865c5e612fbd2
parent 4c42bc04
Loading
Loading
Loading
Loading
+12 −2
Original line number Original line Diff line number Diff line
@@ -68,12 +68,14 @@ public class ZenModeConfig implements Parcelable {


    private static final boolean DEFAULT_ALLOW_REMINDERS = true;
    private static final boolean DEFAULT_ALLOW_REMINDERS = true;
    private static final boolean DEFAULT_ALLOW_EVENTS = true;
    private static final boolean DEFAULT_ALLOW_EVENTS = true;
    private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false;


    private static final int XML_VERSION = 2;
    private static final int XML_VERSION = 2;
    private static final String ZEN_TAG = "zen";
    private static final String ZEN_TAG = "zen";
    private static final String ZEN_ATT_VERSION = "version";
    private static final String ZEN_ATT_VERSION = "version";
    private static final String ALLOW_TAG = "allow";
    private static final String ALLOW_TAG = "allow";
    private static final String ALLOW_ATT_CALLS = "calls";
    private static final String ALLOW_ATT_CALLS = "calls";
    private static final String ALLOW_ATT_REPEAT_CALLERS = "repeatCallers";
    private static final String ALLOW_ATT_MESSAGES = "messages";
    private static final String ALLOW_ATT_MESSAGES = "messages";
    private static final String ALLOW_ATT_FROM = "from";
    private static final String ALLOW_ATT_FROM = "from";
    private static final String ALLOW_ATT_REMINDERS = "reminders";
    private static final String ALLOW_ATT_REMINDERS = "reminders";
@@ -101,6 +103,7 @@ public class ZenModeConfig implements Parcelable {
    private static final String RULE_ATT_CONDITION_ID = "conditionId";
    private static final String RULE_ATT_CONDITION_ID = "conditionId";


    public boolean allowCalls;
    public boolean allowCalls;
    public boolean allowRepeatCallers = DEFAULT_ALLOW_REPEAT_CALLERS;
    public boolean allowMessages;
    public boolean allowMessages;
    public boolean allowReminders = DEFAULT_ALLOW_REMINDERS;
    public boolean allowReminders = DEFAULT_ALLOW_REMINDERS;
    public boolean allowEvents = DEFAULT_ALLOW_EVENTS;
    public boolean allowEvents = DEFAULT_ALLOW_EVENTS;
@@ -113,6 +116,7 @@ public class ZenModeConfig implements Parcelable {


    public ZenModeConfig(Parcel source) {
    public ZenModeConfig(Parcel source) {
        allowCalls = source.readInt() == 1;
        allowCalls = source.readInt() == 1;
        allowRepeatCallers = source.readInt() == 1;
        allowMessages = source.readInt() == 1;
        allowMessages = source.readInt() == 1;
        allowReminders = source.readInt() == 1;
        allowReminders = source.readInt() == 1;
        allowEvents = source.readInt() == 1;
        allowEvents = source.readInt() == 1;
@@ -133,6 +137,7 @@ public class ZenModeConfig implements Parcelable {
    @Override
    @Override
    public void writeToParcel(Parcel dest, int flags) {
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(allowCalls ? 1 : 0);
        dest.writeInt(allowCalls ? 1 : 0);
        dest.writeInt(allowRepeatCallers ? 1 : 0);
        dest.writeInt(allowMessages ? 1 : 0);
        dest.writeInt(allowMessages ? 1 : 0);
        dest.writeInt(allowReminders ? 1 : 0);
        dest.writeInt(allowReminders ? 1 : 0);
        dest.writeInt(allowEvents ? 1 : 0);
        dest.writeInt(allowEvents ? 1 : 0);
@@ -158,6 +163,7 @@ public class ZenModeConfig implements Parcelable {
    public String toString() {
    public String toString() {
        return new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[')
        return new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[')
            .append("allowCalls=").append(allowCalls)
            .append("allowCalls=").append(allowCalls)
            .append(",allowRepeatCallers=").append(allowRepeatCallers)
            .append(",allowMessages=").append(allowMessages)
            .append(",allowMessages=").append(allowMessages)
            .append(",allowFrom=").append(sourceToString(allowFrom))
            .append(",allowFrom=").append(sourceToString(allowFrom))
            .append(",allowReminders=").append(allowReminders)
            .append(",allowReminders=").append(allowReminders)
@@ -213,6 +219,7 @@ public class ZenModeConfig implements Parcelable {
        if (o == this) return true;
        if (o == this) return true;
        final ZenModeConfig other = (ZenModeConfig) o;
        final ZenModeConfig other = (ZenModeConfig) o;
        return other.allowCalls == allowCalls
        return other.allowCalls == allowCalls
                && other.allowRepeatCallers == allowRepeatCallers
                && other.allowMessages == allowMessages
                && other.allowMessages == allowMessages
                && other.allowFrom == allowFrom
                && other.allowFrom == allowFrom
                && other.allowReminders == allowReminders
                && other.allowReminders == allowReminders
@@ -223,8 +230,8 @@ public class ZenModeConfig implements Parcelable {


    @Override
    @Override
    public int hashCode() {
    public int hashCode() {
        return Objects.hash(allowCalls, allowMessages, allowFrom, allowReminders, allowEvents,
        return Objects.hash(allowCalls, allowRepeatCallers, allowMessages, allowFrom,
                automaticRules, manualRule);
                allowReminders, allowEvents, automaticRules, manualRule);
    }
    }


    private static String toDayList(int[] days) {
    private static String toDayList(int[] days) {
@@ -279,6 +286,8 @@ public class ZenModeConfig implements Parcelable {
            if (type == XmlPullParser.START_TAG) {
            if (type == XmlPullParser.START_TAG) {
                if (ALLOW_TAG.equals(tag)) {
                if (ALLOW_TAG.equals(tag)) {
                    rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, false);
                    rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, false);
                    rt.allowRepeatCallers = safeBoolean(parser, ALLOW_ATT_REPEAT_CALLERS,
                            DEFAULT_ALLOW_REPEAT_CALLERS);
                    rt.allowMessages = safeBoolean(parser, ALLOW_ATT_MESSAGES, false);
                    rt.allowMessages = safeBoolean(parser, ALLOW_ATT_MESSAGES, false);
                    rt.allowReminders = safeBoolean(parser, ALLOW_ATT_REMINDERS,
                    rt.allowReminders = safeBoolean(parser, ALLOW_ATT_REMINDERS,
                            DEFAULT_ALLOW_REMINDERS);
                            DEFAULT_ALLOW_REMINDERS);
@@ -307,6 +316,7 @@ public class ZenModeConfig implements Parcelable {


        out.startTag(null, ALLOW_TAG);
        out.startTag(null, ALLOW_TAG);
        out.attribute(null, ALLOW_ATT_CALLS, Boolean.toString(allowCalls));
        out.attribute(null, ALLOW_ATT_CALLS, Boolean.toString(allowCalls));
        out.attribute(null, ALLOW_ATT_REPEAT_CALLERS, Boolean.toString(allowRepeatCallers));
        out.attribute(null, ALLOW_ATT_MESSAGES, Boolean.toString(allowMessages));
        out.attribute(null, ALLOW_ATT_MESSAGES, Boolean.toString(allowMessages));
        out.attribute(null, ALLOW_ATT_REMINDERS, Boolean.toString(allowReminders));
        out.attribute(null, ALLOW_ATT_REMINDERS, Boolean.toString(allowReminders));
        out.attribute(null, ALLOW_ATT_EVENTS, Boolean.toString(allowEvents));
        out.attribute(null, ALLOW_ATT_EVENTS, Boolean.toString(allowEvents));
+3 −0
Original line number Original line Diff line number Diff line
@@ -2047,6 +2047,9 @@
        <item>schedule</item>
        <item>schedule</item>
    </string-array>
    </string-array>


    <!-- Priority repeat caller threshold, in minutes -->
    <integer name="config_zen_repeat_callers_threshold">15</integer>

    <!-- Flags enabling default window features. See Window.java -->
    <!-- Flags enabling default window features. See Window.java -->
    <bool name="config_defaultWindowFeatureOptionsPanel">true</bool>
    <bool name="config_defaultWindowFeatureOptionsPanel">true</bool>
    <bool name="config_defaultWindowFeatureContextMenu">true</bool>
    <bool name="config_defaultWindowFeatureContextMenu">true</bool>
+1 −0
Original line number Original line Diff line number Diff line
@@ -2230,4 +2230,5 @@
  <java-symbol type="string" name="date_picker_next_month_button" />
  <java-symbol type="string" name="date_picker_next_month_button" />
  <java-symbol type="layout" name="date_picker_month_item_material" />
  <java-symbol type="layout" name="date_picker_month_item_material" />
  <java-symbol type="id" name="month_view" />
  <java-symbol type="id" name="month_view" />
  <java-symbol type="integer" name="config_zen_repeat_callers_threshold" />
</resources>
</resources>
+83 −6
Original line number Original line Diff line number Diff line
@@ -27,14 +27,19 @@ import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.provider.Settings.Secure;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig;
import android.telecom.TelecomManager;
import android.telecom.TelecomManager;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.Slog;


import java.io.PrintWriter;
import java.util.Date;
import java.util.Objects;
import java.util.Objects;


public class ZenModeFiltering {
public class ZenModeFiltering {
    private static final String TAG = ZenModeHelper.TAG;
    private static final String TAG = ZenModeHelper.TAG;
    private static final boolean DEBUG = ZenModeHelper.DEBUG;
    private static final boolean DEBUG = ZenModeHelper.DEBUG;


    static final RepeatCallers REPEAT_CALLERS = new RepeatCallers();

    private final Context mContext;
    private final Context mContext;


    private ComponentName mDefaultPhoneApp;
    private ComponentName mDefaultPhoneApp;
@@ -43,8 +48,25 @@ public class ZenModeFiltering {
        mContext = context;
        mContext = context;
    }
    }


    public ComponentName getDefaultPhoneApp() {
    public void dump(PrintWriter pw, String prefix) {
        return mDefaultPhoneApp;
        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 @@ public class ZenModeFiltering {
     * @param timeoutAffinity affinity to return when the timeout specified via
     * @param timeoutAffinity affinity to return when the timeout specified via
     *                        <code>contactsTimeoutMs</code> is hit
     *                        <code>contactsTimeoutMs</code> is hit
     */
     */
    public static boolean matchesCallFilter(int zen, ZenModeConfig config, UserHandle userHandle,
    public static boolean matchesCallFilter(Context context, int zen, ZenModeConfig config,
            Bundle extras, ValidateNotificationPeople validator, int contactsTimeoutMs,
            UserHandle userHandle, Bundle extras, ValidateNotificationPeople validator,
            float timeoutAffinity) {
            int contactsTimeoutMs, float timeoutAffinity) {
        if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) return false; // nothing gets through
        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_ALARMS) return false; // not an alarm
        if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
        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) {
            if (validator != null) {
                final float contactAffinity = validator.getContactAffinity(userHandle, extras,
                final float contactAffinity = validator.getContactAffinity(userHandle, extras,
                        contactsTimeoutMs, timeoutAffinity);
                        contactsTimeoutMs, timeoutAffinity);
@@ -69,6 +92,11 @@ public class ZenModeFiltering {
        return true;
        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) {
    public boolean shouldIntercept(int zen, ZenModeConfig config, NotificationRecord record) {
        if (isSystem(record)) {
        if (isSystem(record)) {
            return false;
            return false;
@@ -96,6 +124,11 @@ public class ZenModeFiltering {
                    return false;
                    return false;
                }
                }
                if (isCall(record)) {
                if (isCall(record)) {
                    if (config.allowRepeatCallers
                            && REPEAT_CALLERS.isRepeat(mContext, extras(record))) {
                        ZenLog.traceNotIntercepted(record, "repeatCaller");
                        return false;
                    }
                    if (!config.allowCalls) {
                    if (!config.allowCalls) {
                        ZenLog.traceIntercepted(record, "!allowCalls");
                        ZenLog.traceIntercepted(record, "!allowCalls");
                        return true;
                        return true;
@@ -199,4 +232,48 @@ public class ZenModeFiltering {
                return true;
                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();
        }
    }

}
}
+8 −7
Original line number Original line Diff line number Diff line
@@ -101,8 +101,8 @@ public class ZenModeHelper {


    public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,
    public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,
            ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
            ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
        return ZenModeFiltering.matchesCallFilter(mZenMode, mConfig, userHandle, extras, validator,
        return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig, userHandle, extras,
                contactsTimeoutMs, timeoutAffinity);
                validator, contactsTimeoutMs, timeoutAffinity);
    }
    }


    public boolean isCall(NotificationRecord record) {
    public boolean isCall(NotificationRecord record) {
@@ -195,8 +195,8 @@ public class ZenModeHelper {
        dump(pw, prefix, "mConfig", mConfig);
        dump(pw, prefix, "mConfig", mConfig);
        dump(pw, prefix, "mDefaultConfig", mDefaultConfig);
        dump(pw, prefix, "mDefaultConfig", mDefaultConfig);
        pw.print(prefix); pw.print("mPreviousRingerMode="); pw.println(mPreviousRingerMode);
        pw.print(prefix); pw.print("mPreviousRingerMode="); pw.println(mPreviousRingerMode);
        pw.print(prefix); pw.print("DefaultPhoneApp="); pw.println(mFiltering.getDefaultPhoneApp());
        pw.print(prefix); pw.print("mEffectsSuppressed="); pw.println(mEffectsSuppressed);
        pw.print(prefix); pw.print("mEffectsSuppressed="); pw.println(mEffectsSuppressed);
        mFiltering.dump(pw, prefix);
        mConditions.dump(pw, prefix);
        mConditions.dump(pw, prefix);
    }
    }


@@ -206,9 +206,9 @@ public class ZenModeHelper {
            pw.println(config);
            pw.println(config);
            return;
            return;
        }
        }
        pw.printf("allow(calls=%s,events=%s,from=%s,messages=%s,reminders=%s)\n",
        pw.printf("allow(calls=%s,repeatCallers=%s,events=%s,from=%s,messages=%s,reminders=%s)\n",
                config.allowCalls, config.allowEvents, config.allowFrom, config.allowMessages,
                config.allowCalls, config.allowRepeatCallers, config.allowEvents, config.allowFrom,
                config.allowReminders);
                config.allowMessages, config.allowReminders);
        pw.print(prefix); pw.print("  manualRule="); pw.println(config.manualRule);
        pw.print(prefix); pw.print("  manualRule="); pw.println(config.manualRule);
        if (config.automaticRules.isEmpty()) return;
        if (config.automaticRules.isEmpty()) return;
        final int N = config.automaticRules.size();
        final int N = config.automaticRules.size();
@@ -304,7 +304,8 @@ public class ZenModeHelper {
        applyRestrictions(muteNotifications, USAGE_NOTIFICATION);
        applyRestrictions(muteNotifications, USAGE_NOTIFICATION);


        // call restrictions
        // call restrictions
        final boolean muteCalls = zen && !mConfig.allowCalls || mEffectsSuppressed;
        final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers
                || mEffectsSuppressed;
        applyRestrictions(muteCalls, USAGE_NOTIFICATION_RINGTONE);
        applyRestrictions(muteCalls, USAGE_NOTIFICATION_RINGTONE);


        // alarm restrictions
        // alarm restrictions