diff options
| author | Julia Reynolds <juliacr@google.com> | 2020-02-05 12:21:25 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-02-05 12:21:25 +0000 |
| commit | e79019393ace0111999f1a52174ba9540f9630a8 (patch) | |
| tree | 5a3857a04923f0ea39cb63db54392ccf5b92ec46 /core/java/android | |
| parent | b85646d57be10ed2b7c9eb7f71050091cbbd906c (diff) | |
| parent | 24edc003044ca39b9c49f98d878069d7af846646 (diff) | |
Merge "Separate concept of VIC from DND"
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/app/NotificationChannel.java | 37 | ||||
| -rw-r--r-- | core/java/android/app/NotificationManager.java | 173 | ||||
| -rw-r--r-- | core/java/android/service/notification/ZenModeConfig.java | 83 | ||||
| -rw-r--r-- | core/java/android/service/notification/ZenPolicy.java | 124 |
4 files changed, 363 insertions, 54 deletions
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 4b24e098b3c6..7212be82d1a9 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -31,7 +31,6 @@ import android.os.Parcelable; import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.text.TextUtils; -import android.util.Log; import android.util.proto.ProtoOutputStream; import com.android.internal.util.Preconditions; @@ -105,6 +104,7 @@ public final class NotificationChannel implements Parcelable { private static final String ATT_ORIG_IMP = "orig_imp"; private static final String ATT_PARENT_CHANNEL = "parent"; private static final String ATT_CONVERSATION_ID = "conv_id"; + private static final String ATT_IMP_CONVERSATION = "imp_conv"; private static final String ATT_DEMOTE = "dem"; private static final String DELIMITER = ","; @@ -196,6 +196,7 @@ public final class NotificationChannel implements Parcelable { private String mParentId = null; private String mConversationId = null; private boolean mDemoted = false; + private boolean mImportantConvo = false; /** * Creates a notification channel. @@ -263,6 +264,7 @@ public final class NotificationChannel implements Parcelable { mParentId = in.readString(); mConversationId = in.readString(); mDemoted = in.readBoolean(); + mImportantConvo = in.readBoolean(); } @Override @@ -321,6 +323,7 @@ public final class NotificationChannel implements Parcelable { dest.writeString(mParentId); dest.writeString(mConversationId); dest.writeBoolean(mDemoted); + dest.writeBoolean(mImportantConvo); } /** @@ -354,6 +357,14 @@ public final class NotificationChannel implements Parcelable { } /** + * @hide + */ + @TestApi + public void setImportantConversation(boolean importantConvo) { + mImportantConvo = importantConvo; + } + + /** * Allows users to block notifications sent through this channel, if this channel belongs to * a package that is signed with the system signature. If the channel does not belong to a * package that is signed with the system signature, this method does nothing. @@ -601,6 +612,18 @@ public final class NotificationChannel implements Parcelable { } /** + * Whether or not notifications in this conversation are considered important. + * + * <p>Important conversations may get special visual treatment, and might be able to bypass DND. + * + * <p>This is only valid for channels that represent conversations, that is, those with a valid + * {@link #getConversationId() conversation id}. + */ + public boolean isImportantConversation() { + return mImportantConvo; + } + + /** * Returns the notification sound for this channel. */ public Uri getSound() { @@ -852,6 +875,7 @@ public final class NotificationChannel implements Parcelable { setConversationId(parser.getAttributeValue(null, ATT_PARENT_CHANNEL), parser.getAttributeValue(null, ATT_CONVERSATION_ID)); setDemoted(safeBool(parser, ATT_DEMOTE, false)); + setImportantConversation(safeBool(parser, ATT_IMP_CONVERSATION, false)); } @Nullable @@ -985,6 +1009,9 @@ public final class NotificationChannel implements Parcelable { if (isDemoted()) { out.attribute(null, ATT_DEMOTE, Boolean.toString(isDemoted())); } + if (isImportantConversation()) { + out.attribute(null, ATT_IMP_CONVERSATION, Boolean.toString(isImportantConversation())); + } // mImportanceLockedDefaultApp and mImportanceLockedByOEM have a different source of // truth and so aren't written to this xml file @@ -1145,7 +1172,8 @@ public final class NotificationChannel implements Parcelable { && mOriginalImportance == that.mOriginalImportance && Objects.equals(getParentChannelId(), that.getParentChannelId()) && Objects.equals(getConversationId(), that.getConversationId()) - && isDemoted() == that.isDemoted(); + && isDemoted() == that.isDemoted() + && isImportantConversation() == that.isImportantConversation(); } @Override @@ -1156,7 +1184,7 @@ public final class NotificationChannel implements Parcelable { isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(), getAudioAttributes(), isBlockableSystem(), mAllowBubbles, mImportanceLockedByOEM, mImportanceLockedDefaultApp, mOriginalImportance, - mParentId, mConversationId, mDemoted); + mParentId, mConversationId, mDemoted, mImportantConvo); result = 31 * result + Arrays.hashCode(mVibration); return result; } @@ -1204,7 +1232,8 @@ public final class NotificationChannel implements Parcelable { + ", mOriginalImp=" + mOriginalImportance + ", mParent=" + mParentId + ", mConversationId=" + mConversationId - + ", mDemoted=" + mDemoted; + + ", mDemoted=" + mDemoted + + ", mImportantConvo=" + mImportantConvo; } /** @hide */ diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 1a8e15c0a23e..528b508cecb1 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -46,6 +46,7 @@ import android.service.notification.Adjustment; import android.service.notification.Condition; import android.service.notification.StatusBarNotification; import android.service.notification.ZenModeConfig; +import android.service.notification.ZenPolicy; import android.util.Log; import android.util.proto.ProtoOutputStream; @@ -1555,19 +1556,24 @@ public class NotificationManager { public static final int PRIORITY_CATEGORY_MEDIA = 1 << 6; /**System (catch-all for non-never suppressible sounds) are prioritized */ public static final int PRIORITY_CATEGORY_SYSTEM = 1 << 7; + /** + * Conversations are allowed through DND. + */ + public static final int PRIORITY_CATEGORY_CONVERSATIONS = 1 << 8; /** * @hide */ public static final int[] ALL_PRIORITY_CATEGORIES = { - PRIORITY_CATEGORY_ALARMS, - PRIORITY_CATEGORY_MEDIA, - PRIORITY_CATEGORY_SYSTEM, - PRIORITY_CATEGORY_REMINDERS, - PRIORITY_CATEGORY_EVENTS, - PRIORITY_CATEGORY_MESSAGES, - PRIORITY_CATEGORY_CALLS, - PRIORITY_CATEGORY_REPEAT_CALLERS, + PRIORITY_CATEGORY_ALARMS, + PRIORITY_CATEGORY_MEDIA, + PRIORITY_CATEGORY_SYSTEM, + PRIORITY_CATEGORY_REMINDERS, + PRIORITY_CATEGORY_EVENTS, + PRIORITY_CATEGORY_MESSAGES, + PRIORITY_CATEGORY_CALLS, + PRIORITY_CATEGORY_REPEAT_CALLERS, + PRIORITY_CATEGORY_CONVERSATIONS, }; /** Any sender is prioritized. */ @@ -1577,6 +1583,31 @@ public class NotificationManager { /** Only starred contacts are prioritized. */ public static final int PRIORITY_SENDERS_STARRED = 2; + + /** @hide */ + @IntDef(prefix = { "CONVERSATION_SENDERS_" }, value = { + CONVERSATION_SENDERS_ANYONE, + CONVERSATION_SENDERS_IMPORTANT, + CONVERSATION_SENDERS_NONE, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ConversationSenders {} + /** + * Used to indicate all conversations can bypass dnd. + */ + public static final int CONVERSATION_SENDERS_ANYONE = ZenPolicy.CONVERSATION_SENDERS_ANYONE; + + /** + * Used to indicate important conversations can bypass dnd. + */ + public static final int CONVERSATION_SENDERS_IMPORTANT = + ZenPolicy.CONVERSATION_SENDERS_IMPORTANT; + + /** + * Used to indicate no conversations can bypass dnd. + */ + public static final int CONVERSATION_SENDERS_NONE = ZenPolicy.CONVERSATION_SENDERS_NONE; + /** Notification categories to prioritize. Bitmask of PRIORITY_CATEGORY_* constants. */ public final int priorityCategories; @@ -1589,6 +1620,18 @@ public class NotificationManager { public final int priorityMessageSenders; /** + * Notification senders to prioritize for conversations. One of: + * {@link #CONVERSATION_SENDERS_NONE}, {@link #CONVERSATION_SENDERS_IMPORTANT}, + * {@link #CONVERSATION_SENDERS_ANYONE}. + */ + public final int priorityConversationSenders; + + /** + * @hide + */ + public static final int CONVERSATION_SENDERS_UNSET = -1; + + /** * @hide */ public static final int SUPPRESSED_EFFECTS_UNSET = -1; @@ -1665,21 +1708,6 @@ public class NotificationManager { SUPPRESSED_EFFECT_NOTIFICATION_LIST }; - private static final int[] SCREEN_OFF_SUPPRESSED_EFFECTS = { - SUPPRESSED_EFFECT_SCREEN_OFF, - SUPPRESSED_EFFECT_FULL_SCREEN_INTENT, - SUPPRESSED_EFFECT_LIGHTS, - SUPPRESSED_EFFECT_AMBIENT, - }; - - private static final int[] SCREEN_ON_SUPPRESSED_EFFECTS = { - SUPPRESSED_EFFECT_SCREEN_ON, - SUPPRESSED_EFFECT_PEEK, - SUPPRESSED_EFFECT_STATUS_BAR, - SUPPRESSED_EFFECT_BADGE, - SUPPRESSED_EFFECT_NOTIFICATION_LIST - }; - /** * Visual effects to suppress for a notification that is filtered by Do Not Disturb mode. * Bitmask of SUPPRESSED_EFFECT_* constants. @@ -1718,7 +1746,41 @@ public class NotificationManager { */ public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders) { this(priorityCategories, priorityCallSenders, priorityMessageSenders, - SUPPRESSED_EFFECTS_UNSET, STATE_UNSET); + SUPPRESSED_EFFECTS_UNSET, STATE_UNSET, CONVERSATION_SENDERS_UNSET); + } + + /** + * Constructs a policy for Do Not Disturb priority mode behavior. + * + * <p> + * Apps that target API levels below {@link Build.VERSION_CODES#R} cannot + * change user-designated values to allow or disallow + * {@link Policy#PRIORITY_CATEGORY_CONVERSATIONS}, from bypassing dnd. + * <p> + * Additionally, apps that target API levels below {@link Build.VERSION_CODES#P} can + * only modify the {@link #SUPPRESSED_EFFECT_SCREEN_ON} and + * {@link #SUPPRESSED_EFFECT_SCREEN_OFF} bits of the suppressed visual effects field. + * All other suppressed effects will be ignored and reconstituted from the screen on + * and screen off values. + * <p> + * Apps that target {@link Build.VERSION_CODES#P} or above can set any + * suppressed visual effects. However, if any suppressed effects > + * {@link #SUPPRESSED_EFFECT_SCREEN_ON} are set, {@link #SUPPRESSED_EFFECT_SCREEN_ON} + * and {@link #SUPPRESSED_EFFECT_SCREEN_OFF} will be ignored and reconstituted from + * the more specific suppressed visual effect bits. Apps should migrate to targeting + * specific effects instead of the deprecated {@link #SUPPRESSED_EFFECT_SCREEN_ON} and + * {@link #SUPPRESSED_EFFECT_SCREEN_OFF} effects. + * + * @param priorityCategories bitmask of categories of notifications that can bypass DND. + * @param priorityCallSenders which callers can bypass DND. + * @param priorityMessageSenders which message senders can bypass DND. + * @param suppressedVisualEffects which visual interruptions should be suppressed from + * notifications that are filtered by DND. + */ + public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders, + int suppressedVisualEffects) { + this(priorityCategories, priorityCallSenders, priorityMessageSenders, + suppressedVisualEffects, STATE_UNSET, CONVERSATION_SENDERS_UNSET); } /** @@ -1727,7 +1789,14 @@ public class NotificationManager { * <p> * Apps that target API levels below {@link Build.VERSION_CODES#P} cannot * change user-designated values to allow or disallow - * {@link Policy#PRIORITY_CATEGORY_ALARMS}, {@link Policy#PRIORITY_CATEGORY_SYSTEM}, and + * {@link Policy#PRIORITY_CATEGORY_CONVERSATIONS} from bypassing dnd. If you do need + * to change them, use a {@link ZenPolicy} associated with an {@link AutomaticZenRule} + * instead of changing the global setting. + * <p> + * Apps that target API levels below {@link Build.VERSION_CODES#P} cannot + * change user-designated values to allow or disallow + * {@link Policy#PRIORITY_CATEGORY_ALARMS}, + * {@link Policy#PRIORITY_CATEGORY_SYSTEM}, and * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd. * <p> * Additionally, apps that target API levels below {@link Build.VERSION_CODES#P} can @@ -1751,28 +1820,27 @@ public class NotificationManager { * notifications that are filtered by DND. */ public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders, - int suppressedVisualEffects) { - this.priorityCategories = priorityCategories; - this.priorityCallSenders = priorityCallSenders; - this.priorityMessageSenders = priorityMessageSenders; - this.suppressedVisualEffects = suppressedVisualEffects; - this.state = STATE_UNSET; + int suppressedVisualEffects, int priorityConversationSenders) { + this(priorityCategories, priorityCallSenders, priorityMessageSenders, + suppressedVisualEffects, STATE_UNSET, priorityConversationSenders); } /** @hide */ public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders, - int suppressedVisualEffects, int state) { + int suppressedVisualEffects, int state, int priorityConversationSenders) { this.priorityCategories = priorityCategories; this.priorityCallSenders = priorityCallSenders; this.priorityMessageSenders = priorityMessageSenders; this.suppressedVisualEffects = suppressedVisualEffects; this.state = state; + this.priorityConversationSenders = priorityConversationSenders; } + /** @hide */ public Policy(Parcel source) { this(source.readInt(), source.readInt(), source.readInt(), source.readInt(), - source.readInt()); + source.readInt(), source.readInt()); } @Override @@ -1782,6 +1850,7 @@ public class NotificationManager { dest.writeInt(priorityMessageSenders); dest.writeInt(suppressedVisualEffects); dest.writeInt(state); + dest.writeInt(priorityConversationSenders); } @Override @@ -1792,7 +1861,7 @@ public class NotificationManager { @Override public int hashCode() { return Objects.hash(priorityCategories, priorityCallSenders, priorityMessageSenders, - suppressedVisualEffects, state); + suppressedVisualEffects, state, priorityConversationSenders); } @Override @@ -1805,7 +1874,8 @@ public class NotificationManager { && other.priorityMessageSenders == priorityMessageSenders && suppressedVisualEffectsEqual(suppressedVisualEffects, other.suppressedVisualEffects) - && other.state == this.state; + && other.state == this.state + && other.priorityConversationSenders == this.priorityConversationSenders; } private boolean suppressedVisualEffectsEqual(int suppressedEffects, @@ -1867,6 +1937,8 @@ public class NotificationManager { + "priorityCategories=" + priorityCategoriesToString(priorityCategories) + ",priorityCallSenders=" + prioritySendersToString(priorityCallSenders) + ",priorityMessageSenders=" + prioritySendersToString(priorityMessageSenders) + + ",priorityConvSenders=" + + conversationSendersToString(priorityConversationSenders) + ",suppressedVisualEffects=" + suppressedEffectsToString(suppressedVisualEffects) + ",areChannelsBypassingDnd=" + (((state & STATE_CHANNELS_BYPASSING_DND) != 0) @@ -2003,6 +2075,7 @@ public class NotificationManager { case PRIORITY_CATEGORY_ALARMS: return "PRIORITY_CATEGORY_ALARMS"; case PRIORITY_CATEGORY_MEDIA: return "PRIORITY_CATEGORY_MEDIA"; case PRIORITY_CATEGORY_SYSTEM: return "PRIORITY_CATEGORY_SYSTEM"; + case PRIORITY_CATEGORY_CONVERSATIONS: return "PRIORITY_CATEGORY_CONVERSATIONS"; default: return "PRIORITY_CATEGORY_UNKNOWN_" + priorityCategory; } } @@ -2016,7 +2089,25 @@ public class NotificationManager { } } - public static final @android.annotation.NonNull Parcelable.Creator<Policy> CREATOR = new Parcelable.Creator<Policy>() { + /** + * @hide + */ + public static @NonNull String conversationSendersToString(int priorityConversationSenders) { + switch (priorityConversationSenders) { + case CONVERSATION_SENDERS_ANYONE: + return "anyone"; + case CONVERSATION_SENDERS_IMPORTANT: + return "important"; + case CONVERSATION_SENDERS_NONE: + return "none"; + case CONVERSATION_SENDERS_UNSET: + return "unset"; + } + return "invalidConversationType{" + priorityConversationSenders + "}"; + } + + public static final @android.annotation.NonNull Parcelable.Creator<Policy> CREATOR + = new Parcelable.Creator<Policy>() { @Override public Policy createFromParcel(Parcel in) { return new Policy(in); @@ -2054,6 +2145,11 @@ public class NotificationManager { } /** @hide **/ + public boolean allowConversations() { + return (priorityCategories & PRIORITY_CATEGORY_CONVERSATIONS) != 0; + } + + /** @hide **/ public boolean allowMessages() { return (priorityCategories & PRIORITY_CATEGORY_MESSAGES) != 0; } @@ -2079,6 +2175,11 @@ public class NotificationManager { } /** @hide **/ + public int allowConversationsFrom() { + return priorityConversationSenders; + } + + /** @hide **/ public boolean showFullScreenIntents() { return (suppressedVisualEffects & SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) == 0; } diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 3f9462cb971b..af915966e7eb 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -16,6 +16,9 @@ package android.service.notification; +import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE; +import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT; +import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_NONE; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; @@ -99,6 +102,8 @@ public class ZenModeConfig implements Parcelable { private static final boolean DEFAULT_ALLOW_REMINDERS = false; private static final boolean DEFAULT_ALLOW_EVENTS = false; 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_CHANNELS_BYPASSING_DND = false; private static final int DEFAULT_SUPPRESSED_VISUAL_EFFECTS = 0; @@ -120,6 +125,8 @@ public class ZenModeConfig implements Parcelable { private static final String ALLOW_ATT_EVENTS = "events"; private static final String ALLOW_ATT_SCREEN_OFF = "visualScreenOff"; private static final String ALLOW_ATT_SCREEN_ON = "visualScreenOn"; + private static final String ALLOW_ATT_CONV = "conv"; + private static final String ALLOW_ATT_CONV_FROM = "convFrom"; private static final String DISALLOW_TAG = "disallow"; private static final String DISALLOW_ATT_VISUAL_EFFECTS = "visualEffects"; private static final String STATE_TAG = "state"; @@ -170,6 +177,8 @@ public class ZenModeConfig implements Parcelable { public boolean allowEvents = DEFAULT_ALLOW_EVENTS; public int allowCallsFrom = DEFAULT_CALLS_SOURCE; public int allowMessagesFrom = DEFAULT_SOURCE; + public boolean allowConversations = DEFAULT_ALLOW_CONV; + public int allowConversationsFrom = DEFAULT_ALLOW_CONV_FROM; public int user = UserHandle.USER_SYSTEM; public int suppressedVisualEffects = DEFAULT_SUPPRESSED_VISUAL_EFFECTS; public boolean areChannelsBypassingDnd = DEFAULT_CHANNELS_BYPASSING_DND; @@ -207,6 +216,8 @@ public class ZenModeConfig implements Parcelable { allowSystem = source.readInt() == 1; suppressedVisualEffects = source.readInt(); areChannelsBypassingDnd = source.readInt() == 1; + allowConversations = source.readBoolean(); + allowConversationsFrom = source.readInt(); } @Override @@ -239,6 +250,8 @@ public class ZenModeConfig implements Parcelable { dest.writeInt(allowSystem ? 1 : 0); dest.writeInt(suppressedVisualEffects); dest.writeInt(areChannelsBypassingDnd ? 1 : 0); + dest.writeBoolean(allowConversations); + dest.writeInt(allowConversationsFrom); } @Override @@ -253,8 +266,11 @@ public class ZenModeConfig implements Parcelable { .append(",allowCalls=").append(allowCalls) .append(",allowRepeatCallers=").append(allowRepeatCallers) .append(",allowMessages=").append(allowMessages) + .append(",allowConversations=").append(allowConversations) .append(",allowCallsFrom=").append(sourceToString(allowCallsFrom)) .append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom)) + .append(",allowConvFrom=").append(ZenPolicy.conversationTypeToString + (allowConversationsFrom)) .append(",suppressedVisualEffects=").append(suppressedVisualEffects) .append(",areChannelsBypassingDnd=").append(areChannelsBypassingDnd) .append(",\nautomaticRules=").append(rulesToString()) @@ -431,7 +447,9 @@ public class ZenModeConfig implements Parcelable { && Objects.equals(other.automaticRules, automaticRules) && Objects.equals(other.manualRule, manualRule) && other.suppressedVisualEffects == suppressedVisualEffects - && other.areChannelsBypassingDnd == areChannelsBypassingDnd; + && other.areChannelsBypassingDnd == areChannelsBypassingDnd + && other.allowConversations == allowConversations + && other.allowConversationsFrom == allowConversationsFrom; } @Override @@ -440,7 +458,8 @@ public class ZenModeConfig implements Parcelable { allowRepeatCallers, allowMessages, allowCallsFrom, allowMessagesFrom, allowReminders, allowEvents, user, automaticRules, manualRule, - suppressedVisualEffects, areChannelsBypassingDnd); + suppressedVisualEffects, areChannelsBypassingDnd, allowConversations, + allowConversationsFrom); } private static String toDayList(int[] days) { @@ -518,10 +537,13 @@ public class ZenModeConfig implements Parcelable { DEFAULT_ALLOW_MESSAGES); rt.allowReminders = safeBoolean(parser, ALLOW_ATT_REMINDERS, DEFAULT_ALLOW_REMINDERS); + rt.allowConversations = safeBoolean(parser, ALLOW_ATT_CONV, DEFAULT_ALLOW_CONV); rt.allowEvents = safeBoolean(parser, ALLOW_ATT_EVENTS, DEFAULT_ALLOW_EVENTS); final int from = safeInt(parser, ALLOW_ATT_FROM, -1); final int callsFrom = safeInt(parser, ALLOW_ATT_CALLS_FROM, -1); final int messagesFrom = safeInt(parser, ALLOW_ATT_MESSAGES_FROM, -1); + rt.allowConversationsFrom = safeInt(parser, ALLOW_ATT_CONV_FROM, + DEFAULT_ALLOW_CONV_FROM); if (isValidSource(callsFrom) && isValidSource(messagesFrom)) { rt.allowCallsFrom = callsFrom; rt.allowMessagesFrom = messagesFrom; @@ -602,6 +624,8 @@ public class ZenModeConfig implements Parcelable { out.attribute(null, ALLOW_ATT_ALARMS, Boolean.toString(allowAlarms)); out.attribute(null, ALLOW_ATT_MEDIA, Boolean.toString(allowMedia)); out.attribute(null, ALLOW_ATT_SYSTEM, Boolean.toString(allowSystem)); + out.attribute(null, ALLOW_ATT_CONV, Boolean.toString(allowConversations)); + out.attribute(null, ALLOW_ATT_CONV_FROM, Integer.toString(allowConversationsFrom)); out.endTag(null, ALLOW_TAG); out.startTag(null, DISALLOW_TAG); @@ -944,6 +968,7 @@ public class ZenModeConfig implements Parcelable { int suppressedVisualEffects = 0; int callSenders = defaultPolicy.priorityCallSenders; int messageSenders = defaultPolicy.priorityMessageSenders; + int conversationSenders = defaultPolicy.priorityConversationSenders; if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_REMINDERS, isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_REMINDERS, defaultPolicy))) { @@ -962,6 +987,14 @@ public class ZenModeConfig implements Parcelable { messageSenders); } + if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_CONVERSATIONS, + isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_CONVERSATIONS, defaultPolicy))) { + priorityCategories |= Policy.PRIORITY_CATEGORY_CONVERSATIONS; + conversationSenders = getNotificationPolicySenders( + zenPolicy.getPriorityConversationSenders(), + conversationSenders); + } + if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_CALLS, isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_CALLS, defaultPolicy))) { priorityCategories |= Policy.PRIORITY_CATEGORY_CALLS; @@ -1047,7 +1080,7 @@ public class ZenModeConfig implements Parcelable { } return new NotificationManager.Policy(priorityCategories, callSenders, - messageSenders, suppressedVisualEffects, defaultPolicy.state); + messageSenders, suppressedVisualEffects, defaultPolicy.state, conversationSenders); } private boolean isPriorityCategoryEnabled(int categoryType, Policy policy) { @@ -1088,11 +1121,14 @@ public class ZenModeConfig implements Parcelable { } } - public Policy toNotificationPolicy() { int priorityCategories = 0; int priorityCallSenders = Policy.PRIORITY_SENDERS_CONTACTS; int priorityMessageSenders = Policy.PRIORITY_SENDERS_CONTACTS; + int priorityConversationSenders = Policy.CONVERSATION_SENDERS_IMPORTANT; + if (allowConversations) { + priorityCategories |= Policy.PRIORITY_CATEGORY_CONVERSATIONS; + } if (allowCalls) { priorityCategories |= Policy.PRIORITY_CATEGORY_CALLS; } @@ -1119,10 +1155,12 @@ public class ZenModeConfig implements Parcelable { } priorityCallSenders = sourceToPrioritySenders(allowCallsFrom, priorityCallSenders); priorityMessageSenders = sourceToPrioritySenders(allowMessagesFrom, priorityMessageSenders); + priorityConversationSenders = allowConversationsFrom; return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders, suppressedVisualEffects, areChannelsBypassingDnd - ? Policy.STATE_CHANNELS_BYPASSING_DND : 0); + ? Policy.STATE_CHANNELS_BYPASSING_DND : 0, + priorityConversationSenders); } /** @@ -1157,6 +1195,27 @@ public class ZenModeConfig implements Parcelable { } } + private static int normalizePrioritySenders(int prioritySenders, int def) { + if (!(prioritySenders == Policy.PRIORITY_SENDERS_CONTACTS + || prioritySenders == Policy.PRIORITY_SENDERS_STARRED + || prioritySenders == Policy.PRIORITY_SENDERS_ANY)) { + return def; + } + return prioritySenders; + } + + private static int normalizeConversationSenders(boolean allowed, int senders, int def) { + if (!allowed) { + return CONVERSATION_SENDERS_NONE; + } + if (!(senders == CONVERSATION_SENDERS_ANYONE + || senders == CONVERSATION_SENDERS_IMPORTANT + || senders == CONVERSATION_SENDERS_NONE)) { + return def; + } + return senders; + } + public void applyNotificationPolicy(Policy policy) { if (policy == null) return; allowAlarms = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_ALARMS) != 0; @@ -1168,12 +1227,17 @@ public class ZenModeConfig implements Parcelable { allowMessages = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_MESSAGES) != 0; allowRepeatCallers = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_REPEAT_CALLERS) != 0; - allowCallsFrom = prioritySendersToSource(policy.priorityCallSenders, allowCallsFrom); - allowMessagesFrom = prioritySendersToSource(policy.priorityMessageSenders, + allowCallsFrom = normalizePrioritySenders(policy.priorityCallSenders, allowCallsFrom); + allowMessagesFrom = normalizePrioritySenders(policy.priorityMessageSenders, allowMessagesFrom); if (policy.suppressedVisualEffects != Policy.SUPPRESSED_EFFECTS_UNSET) { suppressedVisualEffects = policy.suppressedVisualEffects; } + allowConversations = (policy.priorityCategories + & Policy.PRIORITY_CATEGORY_CONVERSATIONS) != 0; + allowConversationsFrom = normalizeConversationSenders(allowConversations, + policy.priorityConversationSenders, + allowConversationsFrom); if (policy.state != Policy.STATE_UNSET) { areChannelsBypassingDnd = (policy.state & Policy.STATE_CHANNELS_BYPASSING_DND) != 0; } @@ -1919,10 +1983,13 @@ public class ZenModeConfig implements Parcelable { & NotificationManager.Policy.PRIORITY_CATEGORY_EVENTS) != 0; boolean allowRepeatCallers = (policy.priorityCategories & NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS) != 0; + boolean allowConversations = (policy.priorityConversationSenders + & Policy.PRIORITY_CATEGORY_CONVERSATIONS) != 0; boolean areChannelsBypassingDnd = (policy.state & Policy.STATE_CHANNELS_BYPASSING_DND) != 0; boolean allowSystem = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_SYSTEM) != 0; return !allowReminders && !allowCalls && !allowMessages && !allowEvents - && !allowRepeatCallers && !areChannelsBypassingDnd && !allowSystem; + && !allowRepeatCallers && !areChannelsBypassingDnd && !allowSystem + && !allowConversations; } /** diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java index 6e2faa9932ca..87295e1c95b9 100644 --- a/core/java/android/service/notification/ZenPolicy.java +++ b/core/java/android/service/notification/ZenPolicy.java @@ -41,6 +41,7 @@ public final class ZenPolicy implements Parcelable { private ArrayList<Integer> mVisualEffects; private @PeopleType int mPriorityMessages = PEOPLE_TYPE_UNSET; private @PeopleType int mPriorityCalls = PEOPLE_TYPE_UNSET; + private @ConversationSenders int mConversationSenders = CONVERSATION_SENDERS_UNSET; /** @hide */ @IntDef(prefix = { "PRIORITY_CATEGORY_" }, value = { @@ -52,6 +53,7 @@ public final class ZenPolicy implements Parcelable { PRIORITY_CATEGORY_ALARMS, PRIORITY_CATEGORY_MEDIA, PRIORITY_CATEGORY_SYSTEM, + PRIORITY_CATEGORY_CONVERSATIONS, }) @Retention(RetentionPolicy.SOURCE) public @interface PriorityCategory {} @@ -72,6 +74,8 @@ public final class ZenPolicy implements Parcelable { public static final int PRIORITY_CATEGORY_MEDIA = 6; /** @hide */ public static final int PRIORITY_CATEGORY_SYSTEM = 7; + /** @hide */ + public static final int PRIORITY_CATEGORY_CONVERSATIONS = 8; /** @hide */ @IntDef(prefix = { "VISUAL_EFFECT_" }, value = { @@ -138,6 +142,37 @@ public final class ZenPolicy implements Parcelable { */ public static final int PEOPLE_TYPE_NONE = 4; + + /** @hide */ + @IntDef(prefix = { "CONVERSATION_SENDERS_" }, value = { + CONVERSATION_SENDERS_UNSET, + CONVERSATION_SENDERS_ANYONE, + CONVERSATION_SENDERS_IMPORTANT, + CONVERSATION_SENDERS_NONE, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ConversationSenders {} + + /** + * Used to indicate no preference for the type of conversations that can bypass dnd. + */ + public static final int CONVERSATION_SENDERS_UNSET = 0; + + /** + * Used to indicate all conversations can bypass dnd. + */ + public static final int CONVERSATION_SENDERS_ANYONE = 1; + + /** + * Used to indicate important conversations can bypass dnd. + */ + public static final int CONVERSATION_SENDERS_IMPORTANT = 2; + + /** + * Used to indicate no conversations can bypass dnd. + */ + public static final int CONVERSATION_SENDERS_NONE = 3; + /** @hide */ @IntDef(prefix = { "STATE_" }, value = { STATE_UNSET, @@ -165,11 +200,20 @@ public final class ZenPolicy implements Parcelable { /** @hide */ public ZenPolicy() { - mPriorityCategories = new ArrayList<>(Collections.nCopies(8, 0)); + mPriorityCategories = new ArrayList<>(Collections.nCopies(9, 0)); mVisualEffects = new ArrayList<>(Collections.nCopies(7, 0)); } /** + * Conversation type that can bypass DND. + * @return {@link #CONVERSATION_SENDERS_UNSET}, {@link #CONVERSATION_SENDERS_ANYONE}, + * {@link #CONVERSATION_SENDERS_IMPORTANT}, {@link #CONVERSATION_SENDERS_NONE}. + */ + public @PeopleType int getPriorityConversationSenders() { + return mConversationSenders; + } + + /** * Message senders that can bypass DND. * @return {@link #PEOPLE_TYPE_UNSET}, {@link #PEOPLE_TYPE_ANYONE}, * {@link #PEOPLE_TYPE_CONTACTS}, {@link #PEOPLE_TYPE_STARRED} or {@link #PEOPLE_TYPE_NONE} @@ -188,6 +232,16 @@ public final class ZenPolicy implements Parcelable { } /** + * Whether this policy wants to allow conversation notifications + * (see {@link NotificationChannel#getConversationId()}) to play sounds and visually appear + * or to intercept them when DND is active. + * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW} + */ + public @State int getPriorityCategoryConversations() { + return mPriorityCategories.get(PRIORITY_CATEGORY_CONVERSATIONS); + } + + /** * Whether this policy wants to allow notifications with category * {@link Notification#CATEGORY_REMINDER} to play sounds and visually appear * or to intercept them when DND is active. @@ -392,6 +446,7 @@ public final class ZenPolicy implements Parcelable { } mZenPolicy.mPriorityMessages = PEOPLE_TYPE_ANYONE; mZenPolicy.mPriorityCalls = PEOPLE_TYPE_ANYONE; + mZenPolicy.mConversationSenders = CONVERSATION_SENDERS_ANYONE; return this; } @@ -408,6 +463,7 @@ public final class ZenPolicy implements Parcelable { } mZenPolicy.mPriorityMessages = PEOPLE_TYPE_NONE; mZenPolicy.mPriorityCalls = PEOPLE_TYPE_NONE; + mZenPolicy.mConversationSenders = CONVERSATION_SENDERS_NONE; return this; } @@ -443,6 +499,8 @@ public final class ZenPolicy implements Parcelable { mZenPolicy.mPriorityMessages = STATE_UNSET; } else if (category == PRIORITY_CATEGORY_CALLS) { mZenPolicy.mPriorityCalls = STATE_UNSET; + } else if (category == PRIORITY_CATEGORY_CONVERSATIONS) { + mZenPolicy.mConversationSenders = STATE_UNSET; } return this; @@ -479,6 +537,31 @@ public final class ZenPolicy implements Parcelable { } /** + * Whether to allow conversation notifications + * (see {@link NotificationChannel#setConversationId(String, String)}) + * that match audienceType to play sounds and visually appear or to intercept + * them when DND is active. + * @param audienceType callers that are allowed to bypass DND + */ + public @NonNull Builder allowConversations(@ConversationSenders int audienceType) { + if (audienceType == STATE_UNSET) { + return unsetPriorityCategory(PRIORITY_CATEGORY_CONVERSATIONS); + } + + if (audienceType == CONVERSATION_SENDERS_NONE) { + mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CONVERSATIONS, STATE_DISALLOW); + } else if (audienceType == CONVERSATION_SENDERS_ANYONE + || audienceType == CONVERSATION_SENDERS_IMPORTANT) { + mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CONVERSATIONS, STATE_ALLOW); + } else { + return this; + } + + mZenPolicy.mConversationSenders = audienceType; + return this; + } + + /** * Whether to allow notifications with category {@link Notification#CATEGORY_MESSAGE} * that match audienceType to play sounds and visually appear or to intercept * them when DND is active. @@ -537,7 +620,6 @@ public final class ZenPolicy implements Parcelable { return this; } - /** * Whether to allow notifications with category {@link Notification#CATEGORY_ALARM} * to play sounds and visually appear or to intercept them when DND is active. @@ -712,6 +794,7 @@ public final class ZenPolicy implements Parcelable { dest.writeList(mVisualEffects); dest.writeInt(mPriorityCalls); dest.writeInt(mPriorityMessages); + dest.writeInt(mConversationSenders); } public static final @android.annotation.NonNull Parcelable.Creator<ZenPolicy> CREATOR = @@ -723,6 +806,7 @@ public final class ZenPolicy implements Parcelable { policy.mVisualEffects = source.readArrayList(Integer.class.getClassLoader()); policy.mPriorityCalls = source.readInt(); policy.mPriorityMessages = source.readInt(); + policy.mConversationSenders = source.readInt(); return policy; } @@ -738,8 +822,10 @@ public final class ZenPolicy implements Parcelable { .append('{') .append("priorityCategories=[").append(priorityCategoriesToString()) .append("], visualEffects=[").append(visualEffectsToString()) - .append("], priorityCalls=").append(peopleTypeToString(mPriorityCalls)) - .append(", priorityMessages=").append(peopleTypeToString(mPriorityMessages)) + .append("], priorityCallsSenders=").append(peopleTypeToString(mPriorityCalls)) + .append(", priorityMessagesSenders=").append(peopleTypeToString(mPriorityMessages)) + .append(", priorityConversationSenders=").append( + conversationTypeToString(mConversationSenders)) .append('}') .toString(); } @@ -811,6 +897,8 @@ public final class ZenPolicy implements Parcelable { return "media"; case PRIORITY_CATEGORY_SYSTEM: return "system"; + case PRIORITY_CATEGORY_CONVERSATIONS: + return "convs"; } return null; } @@ -843,6 +931,23 @@ public final class ZenPolicy implements Parcelable { return "invalidPeopleType{" + peopleType + "}"; } + /** + * @hide + */ + public static String conversationTypeToString(@ConversationSenders int conversationType) { + switch (conversationType) { + case CONVERSATION_SENDERS_ANYONE: + return "anyone"; + case CONVERSATION_SENDERS_IMPORTANT: + return "important"; + case CONVERSATION_SENDERS_NONE: + return "none"; + case CONVERSATION_SENDERS_UNSET: + return "unset"; + } + return "invalidConversationType{" + conversationType + "}"; + } + @Override public boolean equals(Object o) { if (!(o instanceof ZenPolicy)) return false; @@ -852,12 +957,14 @@ public final class ZenPolicy implements Parcelable { return Objects.equals(other.mPriorityCategories, mPriorityCategories) && Objects.equals(other.mVisualEffects, mVisualEffects) && other.mPriorityCalls == mPriorityCalls - && other.mPriorityMessages == mPriorityMessages; + && other.mPriorityMessages == mPriorityMessages + && other.mConversationSenders == mConversationSenders; } @Override public int hashCode() { - return Objects.hash(mPriorityCategories, mVisualEffects, mPriorityCalls, mPriorityMessages); + return Objects.hash(mPriorityCategories, mVisualEffects, mPriorityCalls, mPriorityMessages, + mConversationSenders); } private @ZenPolicy.State int getZenPolicyPriorityCategoryState(@PriorityCategory int @@ -879,6 +986,8 @@ public final class ZenPolicy implements Parcelable { return getPriorityCategoryMedia(); case PRIORITY_CATEGORY_SYSTEM: return getPriorityCategorySystem(); + case PRIORITY_CATEGORY_CONVERSATIONS: + return getPriorityCategoryConversations(); } return -1; } @@ -953,6 +1062,9 @@ public final class ZenPolicy implements Parcelable { } else if (category == PRIORITY_CATEGORY_CALLS && mPriorityCalls < policyToApply.mPriorityCalls) { mPriorityCalls = policyToApply.mPriorityCalls; + } else if (category == PRIORITY_CATEGORY_CONVERSATIONS + && mConversationSenders < policyToApply.mConversationSenders) { + mConversationSenders = policyToApply.mConversationSenders; } } } |
