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

Commit c4316c09 authored by Yuri Lin's avatar Yuri Lin Committed by Android (Google) Code Review
Browse files

Merge "Add "allow channels" to ZenPolicy, NM.Policy, ZenModeConfig" into main

parents 6e0d99ab 97a25379
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -40757,6 +40757,7 @@ package android.service.notification {
  public final class ZenPolicy implements android.os.Parcelable {
    method public int describeContents();
    method @FlaggedApi("android.app.modes_api") public int getAllowedChannels();
    method public int getPriorityCallSenders();
    method public int getPriorityCategoryAlarms();
    method public int getPriorityCategoryCalls();
@@ -40777,6 +40778,9 @@ package android.service.notification {
    method public int getVisualEffectPeek();
    method public int getVisualEffectStatusBar();
    method public void writeToParcel(android.os.Parcel, int);
    field @FlaggedApi("android.app.modes_api") public static final int CHANNEL_TYPE_NONE = 2; // 0x2
    field @FlaggedApi("android.app.modes_api") public static final int CHANNEL_TYPE_PRIORITY = 1; // 0x1
    field @FlaggedApi("android.app.modes_api") public static final int CHANNEL_TYPE_UNSET = 0; // 0x0
    field public static final int CONVERSATION_SENDERS_ANYONE = 1; // 0x1
    field public static final int CONVERSATION_SENDERS_IMPORTANT = 2; // 0x2
    field public static final int CONVERSATION_SENDERS_NONE = 3; // 0x3
@@ -40797,6 +40801,7 @@ package android.service.notification {
    method @NonNull public android.service.notification.ZenPolicy.Builder allowAlarms(boolean);
    method @NonNull public android.service.notification.ZenPolicy.Builder allowAllSounds();
    method @NonNull public android.service.notification.ZenPolicy.Builder allowCalls(int);
    method @FlaggedApi("android.app.modes_api") @NonNull public android.service.notification.ZenPolicy.Builder allowChannels(int);
    method @NonNull public android.service.notification.ZenPolicy.Builder allowConversations(int);
    method @NonNull public android.service.notification.ZenPolicy.Builder allowEvents(boolean);
    method @NonNull public android.service.notification.ZenPolicy.Builder allowMedia(boolean);
+4 −0
Original line number Diff line number Diff line
@@ -373,6 +373,10 @@ package android.app {
    method public void updateNotificationChannel(@NonNull String, int, @NonNull android.app.NotificationChannel);
  }

  public static class NotificationManager.Policy implements android.os.Parcelable {
    method @FlaggedApi("android.app.modes_api") public boolean allowPriorityChannels();
  }

  public final class PendingIntent implements android.os.Parcelable {
    method public boolean addCancelListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.PendingIntent.CancelListener);
    method @RequiresPermission("android.permission.GET_INTENT_SENDER_INTENT") public boolean intentFilterEquals(@Nullable android.app.PendingIntent);
+65 −14
Original line number Diff line number Diff line
@@ -2057,6 +2057,14 @@ public class NotificationManager {
         */
        public static final int STATE_CHANNELS_BYPASSING_DND = 1 << 0;

        /**
         * Whether the policy indicates that even priority channels are NOT permitted to bypass DND.
         * Note that this state explicitly marks the "disallow" state because the default behavior
         * is to allow priority channels to break through.
         * @hide
         */
        public static final int STATE_PRIORITY_CHANNELS_BLOCKED = 1 << 1;

        /**
         * @hide
         */
@@ -2272,20 +2280,34 @@ public class NotificationManager {

        @Override
        public String toString() {
            return "NotificationManager.Policy["
                    + "priorityCategories=" + priorityCategoriesToString(priorityCategories)
                    + ",priorityCallSenders=" + prioritySendersToString(priorityCallSenders)
                    + ",priorityMessageSenders=" + prioritySendersToString(priorityMessageSenders)
                    + ",priorityConvSenders="
                    + conversationSendersToString(priorityConversationSenders)
                    + ",suppressedVisualEffects="
                    + suppressedEffectsToString(suppressedVisualEffects)
                    + ",areChannelsBypassingDnd=" + (state == STATE_UNSET
            StringBuilder sb = new StringBuilder().append("NotificationManager.Policy[")
                    .append("priorityCategories=")
                    .append(priorityCategoriesToString(priorityCategories))
                    .append(",priorityCallSenders=")
                    .append(prioritySendersToString(priorityCallSenders))
                    .append(",priorityMessageSenders=")
                    .append(prioritySendersToString(priorityMessageSenders))
                    .append(",priorityConvSenders=")
                    .append(conversationSendersToString(priorityConversationSenders))
                    .append(",suppressedVisualEffects=")
                    .append(suppressedEffectsToString(suppressedVisualEffects));
            if (Flags.modesApi()) {
                sb.append(",hasPriorityChannels=");
            } else {
                sb.append(",areChannelsBypassingDnd=");
            }
            sb.append((state == STATE_UNSET
                    ? "unset"
                    : ((state & STATE_CHANNELS_BYPASSING_DND) != 0)
                            ? "true"
                                : "false")
                    + "]";
                            : "false"));
            if (Flags.modesApi()) {
                sb.append(",allowPriorityChannels=")
                        .append((state == STATE_UNSET
                                ? "unset"
                                : (allowPriorityChannels() ? "true" : "false")));
            }
            return sb.append("]").toString();
        }

        /** @hide */
@@ -2556,6 +2578,35 @@ public class NotificationManager {
            return (suppressedVisualEffects & SUPPRESSED_EFFECT_NOTIFICATION_LIST) == 0;
        }

        /** @hide **/
        @FlaggedApi(Flags.FLAG_MODES_API)
        @TestApi // so CTS tests can read this state without having to use implementation detail
        public boolean allowPriorityChannels() {
            if (state == STATE_UNSET) {
                return true; // default
            }
            return (state & STATE_PRIORITY_CHANNELS_BLOCKED) == 0;
        }

        /** @hide */
        @FlaggedApi(Flags.FLAG_MODES_API)
        public boolean hasPriorityChannels() {
            return (state & STATE_CHANNELS_BYPASSING_DND) != 0;
        }

        /** @hide **/
        @FlaggedApi(Flags.FLAG_MODES_API)
        public static int policyState(boolean hasPriorityChannels, boolean allowPriorityChannels) {
            int state = 0;
            if (hasPriorityChannels) {
                state |= STATE_CHANNELS_BYPASSING_DND;
            }
            if (!allowPriorityChannels) {
                state |= STATE_PRIORITY_CHANNELS_BLOCKED;
            }
            return state;
        }

        /**
         * returns a deep copy of this policy
         * @hide
+110 −12
Original line number Diff line number Diff line
@@ -115,6 +115,7 @@ public class ZenModeConfig implements Parcelable {
    private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = true;
    private static final boolean DEFAULT_ALLOW_CONV = true;
    private static final int DEFAULT_ALLOW_CONV_FROM = ZenPolicy.CONVERSATION_SENDERS_IMPORTANT;
    private static final boolean DEFAULT_ALLOW_PRIORITY_CHANNELS = true;
    private static final boolean DEFAULT_CHANNELS_BYPASSING_DND = false;
    // Default setting here is 010011101 = 157
    private static final int DEFAULT_SUPPRESSED_VISUAL_EFFECTS =
@@ -141,6 +142,7 @@ public class ZenModeConfig implements Parcelable {
    private static final String ALLOW_ATT_SCREEN_ON = "visualScreenOn";
    private static final String ALLOW_ATT_CONV = "convos";
    private static final String ALLOW_ATT_CONV_FROM = "convosFrom";
    private static final String ALLOW_ATT_CHANNELS = "channels";
    private static final String DISALLOW_TAG = "disallow";
    private static final String DISALLOW_ATT_VISUAL_EFFECTS = "visualEffects";
    private static final String STATE_TAG = "state";
@@ -213,7 +215,12 @@ public class ZenModeConfig implements Parcelable {
    public int allowConversationsFrom = DEFAULT_ALLOW_CONV_FROM;
    public int user = UserHandle.USER_SYSTEM;
    public int suppressedVisualEffects = DEFAULT_SUPPRESSED_VISUAL_EFFECTS;
    // Note that when the modes_api flag is true, the areChannelsBypassingDnd boolean only tracks
    // whether the current user has any priority channels. These channels may bypass DND when
    // allowPriorityChannels is true.
    // TODO: b/310620812 - Rename to be more accurate when modes_api flag is inlined.
    public boolean areChannelsBypassingDnd = DEFAULT_CHANNELS_BYPASSING_DND;
    public boolean allowPriorityChannels = DEFAULT_ALLOW_PRIORITY_CHANNELS;
    public int version;

    public ZenRule manualRule;
@@ -221,7 +228,8 @@ public class ZenModeConfig implements Parcelable {
    public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();

    @UnsupportedAppUsage
    public ZenModeConfig() { }
    public ZenModeConfig() {
    }

    public ZenModeConfig(Parcel source) {
        allowCalls = source.readInt() == 1;
@@ -250,6 +258,9 @@ public class ZenModeConfig implements Parcelable {
        areChannelsBypassingDnd = source.readInt() == 1;
        allowConversations = source.readBoolean();
        allowConversationsFrom = source.readInt();
        if (Flags.modesApi()) {
            allowPriorityChannels = source.readBoolean();
        }
    }

    @Override
@@ -284,11 +295,14 @@ public class ZenModeConfig implements Parcelable {
        dest.writeInt(areChannelsBypassingDnd ? 1 : 0);
        dest.writeBoolean(allowConversations);
        dest.writeInt(allowConversationsFrom);
        if (Flags.modesApi()) {
            dest.writeBoolean(allowPriorityChannels);
        }
    }

    @Override
    public String toString() {
        return new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[')
        StringBuilder sb = new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[')
                .append("user=").append(user)
                .append(",allowAlarms=").append(allowAlarms)
                .append(",allowMedia=").append(allowMedia)
@@ -303,9 +317,14 @@ public class ZenModeConfig implements Parcelable {
                .append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom))
                .append(",allowConvFrom=").append(ZenPolicy.conversationTypeToString
                        (allowConversationsFrom))
                .append(",suppressedVisualEffects=").append(suppressedVisualEffects)
                .append(",areChannelsBypassingDnd=").append(areChannelsBypassingDnd)
                .append(",\nautomaticRules=").append(rulesToString())
                .append(",suppressedVisualEffects=").append(suppressedVisualEffects);
        if (Flags.modesApi()) {
            sb.append(",hasPriorityChannels=").append(areChannelsBypassingDnd);
            sb.append(",allowPriorityChannels=").append(allowPriorityChannels);
        } else {
            sb.append(",areChannelsBypassingDnd=").append(areChannelsBypassingDnd);
        }
        return sb.append(",\nautomaticRules=").append(rulesToString())
                .append(",\nmanualRule=").append(manualRule)
                .append(']').toString();
    }
@@ -385,7 +404,7 @@ public class ZenModeConfig implements Parcelable {
        if (!(o instanceof ZenModeConfig)) return false;
        if (o == this) return true;
        final ZenModeConfig other = (ZenModeConfig) o;
        return other.allowAlarms == allowAlarms
        boolean eq = other.allowAlarms == allowAlarms
                && other.allowMedia == allowMedia
                && other.allowSystem == allowSystem
                && other.allowCalls == allowCalls
@@ -402,10 +421,22 @@ public class ZenModeConfig implements Parcelable {
                && other.areChannelsBypassingDnd == areChannelsBypassingDnd
                && other.allowConversations == allowConversations
                && other.allowConversationsFrom == allowConversationsFrom;
        if (Flags.modesApi()) {
            return eq && other.allowPriorityChannels == allowPriorityChannels;
        }
        return eq;
    }

    @Override
    public int hashCode() {
        if (Flags.modesApi()) {
            return Objects.hash(allowAlarms, allowMedia, allowSystem, allowCalls,
                    allowRepeatCallers, allowMessages,
                    allowCallsFrom, allowMessagesFrom, allowReminders, allowEvents,
                    user, automaticRules, manualRule,
                    suppressedVisualEffects, areChannelsBypassingDnd, allowConversations,
                    allowConversationsFrom, allowPriorityChannels);
        }
        return Objects.hash(allowAlarms, allowMedia, allowSystem, allowCalls,
                allowRepeatCallers, allowMessages,
                allowCallsFrom, allowMessagesFrom, allowReminders, allowEvents,
@@ -511,6 +542,10 @@ public class ZenModeConfig implements Parcelable {
                    rt.allowMedia = safeBoolean(parser, ALLOW_ATT_MEDIA,
                            DEFAULT_ALLOW_MEDIA);
                    rt.allowSystem = safeBoolean(parser, ALLOW_ATT_SYSTEM, DEFAULT_ALLOW_SYSTEM);
                    if (Flags.modesApi()) {
                        rt.allowPriorityChannels = safeBoolean(parser, ALLOW_ATT_CHANNELS,
                                DEFAULT_ALLOW_PRIORITY_CHANNELS);
                    }

                    // migrate old suppressed visual effects fields, if they still exist in the xml
                    Boolean allowWhenScreenOff = unsafeBoolean(parser, ALLOW_ATT_SCREEN_OFF);
@@ -584,6 +619,9 @@ public class ZenModeConfig implements Parcelable {
        out.attributeBoolean(null, ALLOW_ATT_SYSTEM, allowSystem);
        out.attributeBoolean(null, ALLOW_ATT_CONV, allowConversations);
        out.attributeInt(null, ALLOW_ATT_CONV_FROM, allowConversationsFrom);
        if (Flags.modesApi()) {
            out.attributeBoolean(null, ALLOW_ATT_CHANNELS, allowPriorityChannels);
        }
        out.endTag(null, ALLOW_TAG);

        out.startTag(null, DISALLOW_TAG);
@@ -748,6 +786,13 @@ public class ZenModeConfig implements Parcelable {
        final int system = safeInt(parser, ALLOW_ATT_SYSTEM, ZenPolicy.STATE_UNSET);
        final int events = safeInt(parser, ALLOW_ATT_EVENTS, ZenPolicy.STATE_UNSET);
        final int reminders = safeInt(parser, ALLOW_ATT_REMINDERS, ZenPolicy.STATE_UNSET);
        if (Flags.modesApi()) {
            final int channels = safeInt(parser, ALLOW_ATT_CHANNELS, ZenPolicy.CHANNEL_TYPE_UNSET);
            if (channels != ZenPolicy.CHANNEL_TYPE_UNSET) {
                builder.allowChannels(channels);
                policySet = true;
            }
        }

        if (calls != ZenPolicy.PEOPLE_TYPE_UNSET) {
            builder.allowCalls(calls);
@@ -856,6 +901,10 @@ public class ZenModeConfig implements Parcelable {
        writeZenPolicyState(SHOW_ATT_AMBIENT, policy.getVisualEffectAmbient(), out);
        writeZenPolicyState(SHOW_ATT_NOTIFICATION_LIST, policy.getVisualEffectNotificationList(),
                out);

        if (Flags.modesApi()) {
            writeZenPolicyState(ALLOW_ATT_CHANNELS, policy.getAllowedChannels(), out);
        }
    }

    private static void writeZenPolicyState(String attr, int val, TypedXmlSerializer out)
@@ -869,6 +918,10 @@ public class ZenModeConfig implements Parcelable {
            if (val != ZenPolicy.CONVERSATION_SENDERS_UNSET) {
                out.attributeInt(null, attr, val);
            }
        } else if (Flags.modesApi() && Objects.equals(attr, ALLOW_ATT_CHANNELS)) {
            if (val != ZenPolicy.CHANNEL_TYPE_UNSET) {
                out.attributeInt(null, attr, val);
            }
        } else {
            if (val != ZenPolicy.STATE_UNSET) {
                out.attributeInt(null, attr, val);
@@ -1044,6 +1097,11 @@ public class ZenModeConfig implements Parcelable {
            builder.showInNotificationList(
                    (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST) == 0);
        }

        if (Flags.modesApi()) {
            builder.allowChannels(allowPriorityChannels ? ZenPolicy.CHANNEL_TYPE_PRIORITY
                    : ZenPolicy.CHANNEL_TYPE_NONE);
        }
        return builder.build();
    }

@@ -1169,8 +1227,15 @@ public class ZenModeConfig implements Parcelable {
            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
        }

        int state = defaultPolicy.state;
        if (Flags.modesApi()) {
            state = Policy.policyState(defaultPolicy.hasPriorityChannels(),
                    getAllowPriorityChannelsWithDefault(zenPolicy.getAllowedChannels(),
                            DEFAULT_ALLOW_PRIORITY_CHANNELS));
        }

        return new NotificationManager.Policy(priorityCategories, callSenders,
                messageSenders, suppressedVisualEffects, defaultPolicy.state, conversationSenders);
                messageSenders, suppressedVisualEffects, state, conversationSenders);
    }

    private boolean isPriorityCategoryEnabled(int categoryType, Policy policy) {
@@ -1207,6 +1272,24 @@ public class ZenModeConfig implements Parcelable {
        }
    }

    /**
     * Gets whether priority channels are permitted by this channel type, with the specified
     * default if the value is unset. This effectively converts the channel enum to a boolean,
     * where "true" indicates priority channels are allowed to break through and "false" means
     * they are not.
     */
    public static boolean getAllowPriorityChannelsWithDefault(
            @ZenPolicy.ChannelType int channelType, boolean defaultAllowChannels) {
        switch (channelType) {
            case ZenPolicy.CHANNEL_TYPE_PRIORITY:
                return true;
            case ZenPolicy.CHANNEL_TYPE_NONE:
                return false;
            default:
                return defaultAllowChannels;
        }
    }

    /**
     * Maps NotificationManager.Policy senders type to ZenPolicy.PeopleType
     */
@@ -1259,10 +1342,13 @@ public class ZenModeConfig implements Parcelable {
        priorityConversationSenders = getConversationSendersWithDefault(
                allowConversationsFrom, priorityConversationSenders);

        int state = areChannelsBypassingDnd ? Policy.STATE_CHANNELS_BYPASSING_DND : 0;
        if (Flags.modesApi()) {
            state = Policy.policyState(areChannelsBypassingDnd, allowPriorityChannels);
        }

        return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders,
                suppressedVisualEffects, areChannelsBypassingDnd
                ? Policy.STATE_CHANNELS_BYPASSING_DND : 0,
                priorityConversationSenders);
                suppressedVisualEffects, state, priorityConversationSenders);
    }

    /**
@@ -1342,6 +1428,9 @@ public class ZenModeConfig implements Parcelable {
                allowConversationsFrom);
        if (policy.state != Policy.STATE_UNSET) {
            areChannelsBypassingDnd = (policy.state & Policy.STATE_CHANNELS_BYPASSING_DND) != 0;
            if (Flags.modesApi()) {
                allowPriorityChannels = policy.allowPriorityChannels();
            }
        }
    }

@@ -2067,6 +2156,10 @@ public class ZenModeConfig implements Parcelable {
        boolean allowConversations = (policy.priorityConversationSenders
                & Policy.PRIORITY_CATEGORY_CONVERSATIONS) != 0;
        boolean areChannelsBypassingDnd = (policy.state & Policy.STATE_CHANNELS_BYPASSING_DND) != 0;
        if (Flags.modesApi()) {
            areChannelsBypassingDnd = policy.hasPriorityChannels()
                    && policy.allowPriorityChannels();
        }
        boolean allowSystem = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_SYSTEM) != 0;
        return !allowReminders && !allowCalls && !allowMessages && !allowEvents
                && !allowRepeatCallers && !areChannelsBypassingDnd && !allowSystem
@@ -2098,9 +2191,14 @@ public class ZenModeConfig implements Parcelable {
     * This includes notification, ringer and system sounds
     */
    public static boolean areAllPriorityOnlyRingerSoundsMuted(ZenModeConfig config) {
        boolean areChannelsBypassingDnd = config.areChannelsBypassingDnd;
        if (Flags.modesApi()) {
            areChannelsBypassingDnd = config.areChannelsBypassingDnd
                    && config.allowPriorityChannels;
        }
        return !config.allowReminders && !config.allowCalls && !config.allowMessages
                && !config.allowEvents && !config.allowRepeatCallers
                && !config.areChannelsBypassingDnd && !config.allowSystem;
                && !areChannelsBypassingDnd && !config.allowSystem;
    }

    /**
+8 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.service.notification;

import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.Flags;
import android.util.ArrayMap;
import android.util.ArraySet;

@@ -221,6 +222,7 @@ public class ZenModeDiff {
        public static final String FIELD_ALLOW_CONVERSATIONS_FROM = "allowConversationsFrom";
        public static final String FIELD_SUPPRESSED_VISUAL_EFFECTS = "suppressedVisualEffects";
        public static final String FIELD_ARE_CHANNELS_BYPASSING_DND = "areChannelsBypassingDnd";
        public static final String FIELD_ALLOW_PRIORITY_CHANNELS = "allowPriorityChannels";
        private static final Set<String> PEOPLE_TYPE_FIELDS =
                Set.of(FIELD_ALLOW_CALLS_FROM, FIELD_ALLOW_MESSAGES_FROM);

@@ -297,6 +299,12 @@ public class ZenModeDiff {
                addField(FIELD_ARE_CHANNELS_BYPASSING_DND,
                        new FieldDiff<>(from.areChannelsBypassingDnd, to.areChannelsBypassingDnd));
            }
            if (Flags.modesApi()) {
                if (from.allowPriorityChannels != to.allowPriorityChannels) {
                    addField(FIELD_ALLOW_PRIORITY_CHANNELS,
                            new FieldDiff<>(from.allowPriorityChannels, to.allowPriorityChannels));
                }
            }

            // Compare automatic and manual rules
            final ArraySet<String> allRules = new ArraySet<>();
Loading