summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorJulia Reynolds <juliacr@google.com>2020-02-05 12:21:25 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-02-05 12:21:25 +0000
commite79019393ace0111999f1a52174ba9540f9630a8 (patch)
tree5a3857a04923f0ea39cb63db54392ccf5b92ec46 /core/java/android
parentb85646d57be10ed2b7c9eb7f71050091cbbd906c (diff)
parent24edc003044ca39b9c49f98d878069d7af846646 (diff)
Merge "Separate concept of VIC from DND"
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/NotificationChannel.java37
-rw-r--r--core/java/android/app/NotificationManager.java173
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java83
-rw-r--r--core/java/android/service/notification/ZenPolicy.java124
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;
}
}
}