diff --git a/api/current.txt b/api/current.txt
index cc51943ae5db5..92961eab177d1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5752,8 +5752,15 @@ package android.app {
field public static final int PRIORITY_SENDERS_ANY = 0; // 0x0
field public static final int PRIORITY_SENDERS_CONTACTS = 1; // 0x1
field public static final int PRIORITY_SENDERS_STARRED = 2; // 0x2
- field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
- field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_AMBIENT = 128; // 0x80
+ field public static final int SUPPRESSED_EFFECT_BADGE = 64; // 0x40
+ field public static final int SUPPRESSED_EFFECT_FULL_SCREEN_INTENT = 4; // 0x4
+ field public static final int SUPPRESSED_EFFECT_LIGHTS = 8; // 0x8
+ field public static final int SUPPRESSED_EFFECT_NOTIFICATION_LIST = 256; // 0x100
+ field public static final int SUPPRESSED_EFFECT_PEEK = 16; // 0x10
+ field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
+ field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_STATUS_BAR = 32; // 0x20
field public final int priorityCallSenders;
field public final int priorityCategories;
field public final int priorityMessageSenders;
@@ -40001,8 +40008,8 @@ package android.service.notification {
field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
field public static final int REASON_USER_STOPPED = 6; // 0x6
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
- field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
- field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
+ field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
+ field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
}
public static class NotificationListenerService.Ranking {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index b207d57689c40..46d1264f952d2 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1072,20 +1072,77 @@ public class NotificationManager {
* @hide
*/
public static final int SUPPRESSED_EFFECTS_UNSET = -1;
+
/**
* Whether notifications suppressed by DND should not interrupt visually (e.g. with
* notification lights or by turning the screen on) when the screen is off.
+ *
+ * @deprecated use {@link #SUPPRESSED_EFFECT_FULL_SCREEN_INTENT} and
+ * {@link #SUPPRESSED_EFFECT_AMBIENT} and {@link #SUPPRESSED_EFFECT_LIGHTS} individually.
*/
+ @Deprecated
public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1 << 0;
/**
* Whether notifications suppressed by DND should not interrupt visually when the screen
* is on (e.g. by peeking onto the screen).
+ *
+ * @deprecated use {@link #SUPPRESSED_EFFECT_PEEK}.
*/
+ @Deprecated
public static final int SUPPRESSED_EFFECT_SCREEN_ON = 1 << 1;
+ /**
+ * Whether {@link Notification#fullScreenIntent full screen intents} from
+ * notifications intercepted by DND are blocked.
+ */
+ public static final int SUPPRESSED_EFFECT_FULL_SCREEN_INTENT = 1 << 2;
+
+ /**
+ * Whether {@link NotificationChannel#shouldShowLights() notification lights} from
+ * notifications intercepted by DND are blocked.
+ */
+ public static final int SUPPRESSED_EFFECT_LIGHTS = 1 << 3;
+
+ /**
+ * Whether notifications intercepted by DND are prevented from peeking.
+ */
+ public static final int SUPPRESSED_EFFECT_PEEK = 1 << 4;
+
+ /**
+ * Whether notifications intercepted by DND are prevented from appearing in the status bar,
+ * on devices that support status bars.
+ */
+ public static final int SUPPRESSED_EFFECT_STATUS_BAR = 1 << 5;
+
+ /**
+ * Whether {@link NotificationChannel#canShowBadge() badges} from
+ * notifications intercepted by DND are blocked on devices that support badging.
+ */
+ public static final int SUPPRESSED_EFFECT_BADGE = 1 << 6;
+
+ /**
+ * Whether notification intercepted by DND are prevented from appearing on ambient displays
+ * on devices that support ambient display.
+ */
+ public static final int SUPPRESSED_EFFECT_AMBIENT = 1 << 7;
+
+ /**
+ * Whether notification intercepted by DND are prevented from appearing in notification
+ * list views like the notification shade or lockscreen on devices that support those
+ * views.
+ */
+ public static final int SUPPRESSED_EFFECT_NOTIFICATION_LIST = 1 << 8;
+
private static final int[] ALL_SUPPRESSED_EFFECTS = {
SUPPRESSED_EFFECT_SCREEN_OFF,
SUPPRESSED_EFFECT_SCREEN_ON,
+ SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
+ SUPPRESSED_EFFECT_LIGHTS,
+ SUPPRESSED_EFFECT_PEEK,
+ SUPPRESSED_EFFECT_STATUS_BAR,
+ SUPPRESSED_EFFECT_BADGE,
+ SUPPRESSED_EFFECT_AMBIENT,
+ SUPPRESSED_EFFECT_NOTIFICATION_LIST
};
/**
@@ -1097,6 +1154,12 @@ public class NotificationManager {
/**
* Constructs a policy for Do Not Disturb priority mode behavior.
*
+ *
+ * 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.
+ *
* @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.
@@ -1109,6 +1172,26 @@ public class NotificationManager {
/**
* Constructs a policy for Do Not Disturb priority mode behavior.
*
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
@@ -1190,6 +1273,30 @@ public class NotificationManager {
}
}
+ /**
+ * @hide
+ */
+ public static int getAllSuppressedVisualEffects() {
+ int effects = 0;
+ for (int i = 0; i < ALL_SUPPRESSED_EFFECTS.length; i++) {
+ effects |= ALL_SUPPRESSED_EFFECTS[i];
+ }
+ return effects;
+ }
+
+ /**
+ * @hide
+ */
+ public static boolean areAllVisualEffectsSuppressed(int effects) {
+ for (int i = 0; i < ALL_SUPPRESSED_EFFECTS.length; i++) {
+ final int effect = ALL_SUPPRESSED_EFFECTS[i];
+ if ((effects & effect) == 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static String suppressedEffectsToString(int effects) {
if (effects <= 0) return "";
final StringBuilder sb = new StringBuilder();
@@ -1228,9 +1335,26 @@ public class NotificationManager {
private static String effectToString(int effect) {
switch (effect) {
- case SUPPRESSED_EFFECT_SCREEN_OFF: return "SUPPRESSED_EFFECT_SCREEN_OFF";
- case SUPPRESSED_EFFECT_SCREEN_ON: return "SUPPRESSED_EFFECT_SCREEN_ON";
- case SUPPRESSED_EFFECTS_UNSET: return "SUPPRESSED_EFFECTS_UNSET";
+ case SUPPRESSED_EFFECT_FULL_SCREEN_INTENT:
+ return "SUPPRESSED_EFFECT_FULL_SCREEN_INTENT";
+ case SUPPRESSED_EFFECT_LIGHTS:
+ return "SUPPRESSED_EFFECT_LIGHTS";
+ case SUPPRESSED_EFFECT_PEEK:
+ return "SUPPRESSED_EFFECT_PEEK";
+ case SUPPRESSED_EFFECT_STATUS_BAR:
+ return "SUPPRESSED_EFFECT_STATUS_BAR";
+ case SUPPRESSED_EFFECT_BADGE:
+ return "SUPPRESSED_EFFECT_BADGE";
+ case SUPPRESSED_EFFECT_AMBIENT:
+ return "SUPPRESSED_EFFECT_AMBIENT";
+ case SUPPRESSED_EFFECT_NOTIFICATION_LIST:
+ return "SUPPRESSED_EFFECT_NOTIFICATION_LIST";
+ case SUPPRESSED_EFFECT_SCREEN_OFF:
+ return "SUPPRESSED_EFFECT_SCREEN_OFF";
+ case SUPPRESSED_EFFECT_SCREEN_ON:
+ return "SUPPRESSED_EFFECT_SCREEN_ON";
+ case SUPPRESSED_EFFECTS_UNSET:
+ return "SUPPRESSED_EFFECTS_UNSET";
default: return "UNKNOWN_" + effect;
}
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index eebd22ae64bb9..ea10ae7b38080 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -149,13 +149,19 @@ public abstract class NotificationListenerService extends Service {
/**
* Whether notification suppressed by DND should not interruption visually when the screen is
* off.
+ *
+ * @deprecated Use the more specific visual effects in {@link NotificationManager.Policy}.
*/
+ @Deprecated
public static final int SUPPRESSED_EFFECT_SCREEN_OFF =
NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
/**
* Whether notification suppressed by DND should not interruption visually when the screen is
* on.
+ *
+ * @deprecated Use the more specific visual effects in {@link NotificationManager.Policy}.
*/
+ @Deprecated
public static final int SUPPRESSED_EFFECT_SCREEN_ON =
NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
@@ -1453,7 +1459,8 @@ public abstract class NotificationListenerService extends Service {
/**
* Returns the type(s) of visual effects that should be suppressed for this notification.
- * See {@link #SUPPRESSED_EFFECT_SCREEN_OFF}, {@link #SUPPRESSED_EFFECT_SCREEN_ON}.
+ * See {@link NotificationManager.Policy}, e.g.
+ * {@link NotificationManager.Policy#SUPPRESSED_EFFECT_LIGHTS}.
*/
public int getSuppressedVisualEffects() {
return mSuppressedVisualEffects;
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index b61919eba2507..740a387e078d7 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -92,10 +92,12 @@ 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 = false;
- private static final boolean DEFAULT_ALLOW_SCREEN_OFF = true;
- private static final boolean DEFAULT_ALLOW_SCREEN_ON = true;
+ private static final boolean DEFAULT_ALLOW_SCREEN_OFF = false;
+ private static final boolean DEFAULT_ALLOW_SCREEN_ON = false;
+ private static final int DEFAULT_SUPPRESSED_VISUAL_EFFECTS =
+ Policy.getAllSuppressedVisualEffects();
- public static final int XML_VERSION = 4;
+ public static final int XML_VERSION = 5;
public static final String ZEN_TAG = "zen";
private static final String ZEN_ATT_VERSION = "version";
private static final String ZEN_ATT_USER = "user";
@@ -113,6 +115,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 DISALLOW_TAG = "disallow";
+ private static final String DISALLOW_ATT_VISUAL_EFFECTS = "visualEffects";
private static final String CONDITION_ATT_ID = "id";
private static final String CONDITION_ATT_SUMMARY = "summary";
@@ -146,6 +150,7 @@ public class ZenModeConfig implements Parcelable {
public int allowCallsFrom = DEFAULT_SOURCE;
public int allowMessagesFrom = DEFAULT_SOURCE;
public int user = UserHandle.USER_SYSTEM;
+ public int suppressedVisualEffects = DEFAULT_SUPPRESSED_VISUAL_EFFECTS;
public boolean allowWhenScreenOff = DEFAULT_ALLOW_SCREEN_OFF;
public boolean allowWhenScreenOn = DEFAULT_ALLOW_SCREEN_ON;
public int version;
@@ -180,6 +185,7 @@ public class ZenModeConfig implements Parcelable {
allowAlarms = source.readInt() == 1;
allowMedia = source.readInt() == 1;
allowSystem = source.readInt() == 1;
+ suppressedVisualEffects = source.readInt();
}
@Override
@@ -212,6 +218,7 @@ public class ZenModeConfig implements Parcelable {
dest.writeInt(allowAlarms ? 1 : 0);
dest.writeInt(allowMedia ? 1 : 0);
dest.writeInt(allowSystem ? 1 : 0);
+ dest.writeInt(suppressedVisualEffects);
}
@Override
@@ -230,6 +237,7 @@ public class ZenModeConfig implements Parcelable {
.append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom))
.append(",allowWhenScreenOff=").append(allowWhenScreenOff)
.append(",allowWhenScreenOn=").append(allowWhenScreenOn)
+ .append(",suppressedVisualEffects=").append(suppressedVisualEffects)
.append(",automaticRules=").append(automaticRules)
.append(",manualRule=").append(manualRule)
.append(']').toString();
@@ -279,6 +287,10 @@ public class ZenModeConfig implements Parcelable {
if (allowWhenScreenOn != to.allowWhenScreenOn) {
d.addLine("allowWhenScreenOn", allowWhenScreenOn, to.allowWhenScreenOn);
}
+ if (suppressedVisualEffects != to.suppressedVisualEffects) {
+ d.addLine("suppressedVisualEffects", suppressedVisualEffects,
+ to.suppressedVisualEffects);
+ }
final ArraySet allRules = new ArraySet<>();
addKeys(allRules, automaticRules);
addKeys(allRules, to.automaticRules);
@@ -383,7 +395,8 @@ public class ZenModeConfig implements Parcelable {
&& other.allowWhenScreenOn == allowWhenScreenOn
&& other.user == user
&& Objects.equals(other.automaticRules, automaticRules)
- && Objects.equals(other.manualRule, manualRule);
+ && Objects.equals(other.manualRule, manualRule)
+ && other.suppressedVisualEffects == suppressedVisualEffects;
}
@Override
@@ -391,7 +404,8 @@ public class ZenModeConfig implements Parcelable {
return Objects.hash(allowAlarms, allowMedia, allowSystem, allowCalls,
allowRepeatCallers, allowMessages,
allowCallsFrom, allowMessagesFrom, allowReminders, allowEvents,
- allowWhenScreenOff, allowWhenScreenOn, user, automaticRules, manualRule);
+ allowWhenScreenOff, allowWhenScreenOn, user, automaticRules, manualRule,
+ suppressedVisualEffects);
}
private static String toDayList(int[] days) {
@@ -474,6 +488,8 @@ public class ZenModeConfig implements Parcelable {
rt.allowCallsFrom = DEFAULT_SOURCE;
rt.allowMessagesFrom = DEFAULT_SOURCE;
}
+ // continue to read even though we now have suppressedVisualEffects, in case
+ // we need to revert to users' previous settings
rt.allowWhenScreenOff =
safeBoolean(parser, ALLOW_ATT_SCREEN_OFF, DEFAULT_ALLOW_SCREEN_OFF);
rt.allowWhenScreenOn =
@@ -482,6 +498,9 @@ 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);
+ } else if (DISALLOW_TAG.equals(tag)) {
+ rt.suppressedVisualEffects = safeInt(parser, DISALLOW_ATT_VISUAL_EFFECTS,
+ DEFAULT_SUPPRESSED_VISUAL_EFFECTS);
} else if (MANUAL_TAG.equals(tag)) {
rt.manualRule = readRuleXml(parser);
} else if (AUTOMATIC_TAG.equals(tag)) {
@@ -517,6 +536,10 @@ public class ZenModeConfig implements Parcelable {
out.attribute(null, ALLOW_ATT_SYSTEM, Boolean.toString(allowSystem));
out.endTag(null, ALLOW_TAG);
+ out.startTag(null, DISALLOW_TAG);
+ out.attribute(null, DISALLOW_ATT_VISUAL_EFFECTS, Integer.toString(suppressedVisualEffects));
+ out.endTag(null, DISALLOW_TAG);
+
if (manualRule != null) {
out.startTag(null, MANUAL_TAG);
writeRuleXml(manualRule, out);
@@ -701,13 +724,6 @@ public class ZenModeConfig implements Parcelable {
if (allowRepeatCallers) {
priorityCategories |= Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
}
- int suppressedVisualEffects = 0;
- if (!allowWhenScreenOff) {
- suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
- }
- if (!allowWhenScreenOn) {
- suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_ON;
- }
if (allowAlarms) {
priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
}
@@ -770,10 +786,7 @@ public class ZenModeConfig implements Parcelable {
allowMessagesFrom = prioritySendersToSource(policy.priorityMessageSenders,
allowMessagesFrom);
if (policy.suppressedVisualEffects != Policy.SUPPRESSED_EFFECTS_UNSET) {
- allowWhenScreenOff =
- (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_SCREEN_OFF) == 0;
- allowWhenScreenOn =
- (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_SCREEN_ON) == 0;
+ suppressedVisualEffects = policy.suppressedVisualEffects;
}
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f1c9f676fd573..cf13d1c63db57 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2396,6 +2396,7 @@
- com.android.server.notification.NotificationIntrusivenessExtractor
- com.android.server.notification.VisibilityExtractor
+
- com.android.server.notification.BadgeExtractor
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 15dffc0ba52c3..a5bd179826b14 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4883,7 +4883,7 @@
System changes
- Do Not Disturb has changed
+ Do Not Disturb is hiding notifications to help you focus
- Tap to check your behavior settings for interruptions
+ This is a new feature from the latest system update. Tap to change.
diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index 5e463d866b4df..2d3cd1cd5d29d 100644
--- a/core/res/res/xml/default_zen_mode_config.xml
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -18,7 +18,9 @@
-->
-
+
+
+
diff --git a/services/core/java/com/android/server/notification/BadgeExtractor.java b/services/core/java/com/android/server/notification/BadgeExtractor.java
index d8a30ae7c53f8..d91d5410d0042 100644
--- a/services/core/java/com/android/server/notification/BadgeExtractor.java
+++ b/services/core/java/com/android/server/notification/BadgeExtractor.java
@@ -15,6 +15,8 @@
*/
package com.android.server.notification;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+
import android.content.Context;
import android.util.Slog;
@@ -54,6 +56,11 @@ public class BadgeExtractor implements NotificationSignalExtractor {
}
}
+ if (record.isIntercepted()
+ && (record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_BADGE) != 0) {
+ record.setShowBadge(false);
+ }
+
return null;
}
@@ -64,6 +71,5 @@ public class BadgeExtractor implements NotificationSignalExtractor {
@Override
public void setZenHelper(ZenModeHelper helper) {
-
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index cd387b017c53e..f0b60ec2fe137 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -22,6 +22,16 @@ import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+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_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -60,8 +70,6 @@ import static android.service.notification.NotificationListenerService.REASON_SN
import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
-import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
-import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.service.notification.NotificationListenerService.TRIM_FULL;
import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -1342,6 +1350,7 @@ public class NotificationManagerService extends SystemService {
@Override
void onPolicyChanged() {
sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
+ mRankingHandler.requestSort();
}
});
mRankingHelper = new RankingHelper(getContext(),
@@ -1781,6 +1790,74 @@ public class NotificationManagerService extends SystemService {
UsageEvents.Event.NOTIFICATION_SEEN);
}
+ protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
+ int targetSdkVersion) {
+ if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
+ return incomingPolicy.suppressedVisualEffects;
+ }
+ final int[] effectsIntroducedInP = {
+ SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
+ SUPPRESSED_EFFECT_LIGHTS,
+ SUPPRESSED_EFFECT_PEEK,
+ SUPPRESSED_EFFECT_STATUS_BAR,
+ SUPPRESSED_EFFECT_BADGE,
+ SUPPRESSED_EFFECT_AMBIENT,
+ SUPPRESSED_EFFECT_NOTIFICATION_LIST
+ };
+
+ int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
+ if (targetSdkVersion <= Build.VERSION_CODES.O_MR1) {
+ // unset higher order bits introduced in P, maintain the user's higher order bits
+ for (int i = 0; i < effectsIntroducedInP.length ; i++) {
+ newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
+ newSuppressedVisualEffects |=
+ (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
+ }
+ // set higher order bits according to lower order bits
+ if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
+ }
+ if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
+ }
+ } else {
+ boolean hasNewEffects = (newSuppressedVisualEffects
+ - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
+ // if any of the new effects introduced in P are set
+ if (hasNewEffects) {
+ // clear out the deprecated effects
+ newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
+ | SUPPRESSED_EFFECT_SCREEN_OFF);
+
+ // set the deprecated effects according to the new more specific effects
+ if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
+ }
+ if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
+ && (newSuppressedVisualEffects
+ & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
+ && (newSuppressedVisualEffects
+ & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
+ }
+ } else {
+ // set higher order bits according to lower order bits
+ if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
+ }
+ if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
+ }
+ }
+ }
+
+ return newSuppressedVisualEffects;
+ }
+
/**
* Report to usage stats that the notification was clicked.
* @param r notification record
@@ -3063,10 +3140,9 @@ public class NotificationManagerService extends SystemService {
try {
final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
0, UserHandle.getUserId(MY_UID));
+ Policy currPolicy = mZenModeHelper.getNotificationPolicy();
if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.O_MR1) {
- Policy currPolicy = mZenModeHelper.getNotificationPolicy();
-
int priorityCategories = policy.priorityCategories;
// ignore alarm and media values from new policy
priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
@@ -3084,11 +3160,12 @@ public class NotificationManagerService extends SystemService {
policy.priorityCallSenders, policy.priorityMessageSenders,
policy.suppressedVisualEffects);
}
+ int newVisualEffects = calculateSuppressedVisualEffects(
+ policy, currPolicy, applicationInfo.targetSdkVersion);
+ policy = new Policy(policy.priorityCategories,
+ policy.priorityCallSenders, policy.priorityMessageSenders,
+ newVisualEffects);
- Slog.i(TAG, "setNotificationPolicy pkg=" + pkg
- + " targetSdk=" + applicationInfo.targetSdkVersion
- + " policy="
- + Policy.priorityCategoriesToString(policy.priorityCategories));
mZenModeHelper.setNotificationPolicy(policy);
} catch (RemoteException e) {
} finally {
@@ -4465,8 +4542,7 @@ public class NotificationManagerService extends SystemService {
// release the light
boolean wasShowLights = mLights.remove(key);
if (record.getLight() != null && aboveThreshold
- && ((record.getSuppressedVisualEffects()
- & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
+ && ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) == 0)) {
mLights.add(key);
updateLightsLocked();
if (mUseAttentionLight) {
@@ -4864,11 +4940,8 @@ public class NotificationManagerService extends SystemService {
private void applyZenModeLocked(NotificationRecord record) {
record.setIntercepted(mZenModeHelper.shouldIntercept(record));
if (record.isIntercepted()) {
- int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
- ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
- | (mZenModeHelper.shouldSuppressWhenScreenOn()
- ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
- record.setSuppressedVisualEffects(suppressed);
+ record.setSuppressedVisualEffects(
+ mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
} else {
record.setSuppressedVisualEffects(0);
}
diff --git a/services/core/java/com/android/server/notification/ZenModeExtractor.java b/services/core/java/com/android/server/notification/ZenModeExtractor.java
index 74f9806410811..a0aa1c32645ff 100644
--- a/services/core/java/com/android/server/notification/ZenModeExtractor.java
+++ b/services/core/java/com/android/server/notification/ZenModeExtractor.java
@@ -16,8 +16,8 @@
package com.android.server.notification;
-import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
-import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
import android.content.Context;
import android.util.Log;
@@ -49,11 +49,8 @@ public class ZenModeExtractor implements NotificationSignalExtractor {
record.setIntercepted(mZenModeHelper.shouldIntercept(record));
if (record.isIntercepted()) {
- int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
- ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
- | (mZenModeHelper.shouldSuppressWhenScreenOn()
- ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
- record.setSuppressedVisualEffects(suppressed);
+ record.setSuppressedVisualEffects(
+ mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
} else {
record.setSuppressedVisualEffects(0);
}
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
index a0003a56e537a..a7e0c51081885 100644
--- a/services/core/java/com/android/server/notification/ZenModeFiltering.java
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -16,7 +16,10 @@
package com.android.server.notification;
+import static android.provider.Settings.Global.ZEN_MODE_OFF;
+
import android.app.Notification;
+import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.media.AudioAttributes;
@@ -30,6 +33,8 @@ import android.telecom.TelecomManager;
import android.util.ArrayMap;
import android.util.Slog;
+import com.android.internal.messages.nano.SystemMessageProto;
+
import java.io.PrintWriter;
import java.util.Date;
import java.util.Objects;
@@ -104,6 +109,16 @@ public class ZenModeFiltering {
}
public boolean shouldIntercept(int zen, ZenModeConfig config, NotificationRecord record) {
+ if (zen == ZEN_MODE_OFF) {
+ return false;
+ }
+ // Make an exception to policy for the notification saying that policy has changed
+ if (NotificationManager.Policy.areAllVisualEffectsSuppressed(config.suppressedVisualEffects)
+ && "android".equals(record.sbn.getPackageName())
+ && SystemMessageProto.SystemMessage.NOTE_ZEN_UPGRADE == record.sbn.getId()) {
+ ZenLog.traceNotIntercepted(record, "systemDndChangedNotification");
+ return false;
+ }
switch (zen) {
case Global.ZEN_MODE_NO_INTERRUPTIONS:
// #notevenalarms
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 28d692ad624ad..aa1f7d95845f5 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -602,7 +602,8 @@ public class ZenModeHelper {
pw.println(config);
return;
}
- pw.printf("allow(alarms=%b,media=%b,system=%b,calls=%b,callsFrom=%s,repeatCallers=%b,messages=%b,messagesFrom=%s,"
+ pw.printf("allow(alarms=%b,media=%b,system=%b,calls=%b,callsFrom=%s,repeatCallers=%b,"
+ + "messages=%b,messagesFrom=%s,"
+ "events=%b,reminders=%b,whenScreenOff=%b,whenScreenOn=%b)\n",
config.allowAlarms, config.allowMedia, config.allowSystem,
config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
@@ -610,6 +611,7 @@ public class ZenModeHelper {
ZenModeConfig.sourceToString(config.allowMessagesFrom),
config.allowEvents, config.allowReminders, config.allowWhenScreenOff,
config.allowWhenScreenOn);
+ pw.printf(" disallow(visualEffects=%s)\n", config.suppressedVisualEffects);
pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule);
if (config.automaticRules.isEmpty()) return;
final int N = config.automaticRules.size();
@@ -623,7 +625,7 @@ public class ZenModeHelper {
throws XmlPullParserException, IOException {
final ZenModeConfig config = ZenModeConfig.readXml(parser);
if (config != null) {
- if (config.version < ZenModeConfig.XML_VERSION) {
+ if (config.version < ZenModeConfig.XML_VERSION || forRestore) {
Settings.Global.putInt(mContext.getContentResolver(),
Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
}
@@ -1176,8 +1178,7 @@ public class ZenModeHelper {
@VisibleForTesting
protected Notification createZenUpgradeNotification() {
- Intent intent = new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS)
- .setPackage("com.android.settings")
+ Intent intent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
index 142041a4f7058..cfc7430cc8f4c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
@@ -18,10 +18,13 @@ package com.android.server.notification;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import android.app.ActivityManager;
import android.app.Notification;
@@ -149,4 +152,52 @@ public class BadgeExtractorTest extends UiServiceTestCase {
assertFalse(r.canShowBadge());
}
+
+ @Test
+ public void testDndOverridesYes() {
+ BadgeExtractor extractor = new BadgeExtractor();
+ extractor.setConfig(mConfig);
+
+ when(mConfig.badgingEnabled(mUser)).thenReturn(true);
+ when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
+ NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
+ r.setIntercepted(true);
+ r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_BADGE);
+
+ extractor.process(r);
+
+ assertFalse(r.canShowBadge());
+ }
+
+ @Test
+ public void testDndOConsidersInterception() {
+ BadgeExtractor extractor = new BadgeExtractor();
+ extractor.setConfig(mConfig);
+
+ when(mConfig.badgingEnabled(mUser)).thenReturn(true);
+ when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
+ NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
+ r.setIntercepted(false);
+ r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_BADGE);
+
+ extractor.process(r);
+
+ assertTrue(r.canShowBadge());
+ }
+
+ @Test
+ public void testDndConsidersSuppressedVisualEffects() {
+ BadgeExtractor extractor = new BadgeExtractor();
+ extractor.setConfig(mConfig);
+
+ when(mConfig.badgingEnabled(mUser)).thenReturn(true);
+ when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
+ NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
+ r.setIntercepted(true);
+ r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_LIGHTS);
+
+ extractor.process(r);
+
+ assertTrue(r.canShowBadge());
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 7b2c040db5abf..4fe54b9f15ef1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -22,8 +22,19 @@ import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MAX;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+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_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.os.Build.VERSION_CODES.O_MR1;
+import static android.os.Build.VERSION_CODES.P;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -2530,4 +2541,125 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mAm, times(1)).revokeUriPermissionFromOwner(any(), eq(message1.getDataUri()),
anyInt(), anyInt());
}
+
+ @Test
+ public void testSetNotificationPolicy_preP_setOldFields() {
+ ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = mZenModeHelper;
+ NotificationManager.Policy userPolicy =
+ new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+ NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF);
+
+ int expected = SUPPRESSED_EFFECT_BADGE
+ | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF
+ | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT
+ | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testSetNotificationPolicy_preP_setNewFields() {
+ ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = mZenModeHelper;
+ NotificationManager.Policy userPolicy =
+ new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+ NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_NOTIFICATION_LIST);
+
+ int expected = SUPPRESSED_EFFECT_BADGE;
+ int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testSetNotificationPolicy_preP_setOldNewFields() {
+ ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = mZenModeHelper;
+ NotificationManager.Policy userPolicy =
+ new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+ NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR);
+
+ int expected =
+ SUPPRESSED_EFFECT_BADGE | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK;
+ int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testSetNotificationPolicy_P_setOldFields() {
+ ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = mZenModeHelper;
+ NotificationManager.Policy userPolicy =
+ new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+ NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF);
+
+ int expected = SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF
+ | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT
+ | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testSetNotificationPolicy_P_setNewFields() {
+ ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = mZenModeHelper;
+ NotificationManager.Policy userPolicy =
+ new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+ NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_AMBIENT
+ | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
+
+ int expected = SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_SCREEN_OFF
+ | SUPPRESSED_EFFECT_AMBIENT | SUPPRESSED_EFFECT_LIGHTS
+ | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testSetNotificationPolicy_P_setOldNewFields() {
+ ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = mZenModeHelper;
+ NotificationManager.Policy userPolicy =
+ new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+ NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR);
+
+ int expected = SUPPRESSED_EFFECT_STATUS_BAR;
+ int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
+
+ assertEquals(expected, actual);
+
+ appPolicy = new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_AMBIENT
+ | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
+
+ expected = SUPPRESSED_EFFECT_SCREEN_OFF | SUPPRESSED_EFFECT_AMBIENT
+ | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
+
+ assertEquals(expected, actual);
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeExtractorTest.java
index faba6b6f55b77..beff0d11ef3e8 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeExtractorTest.java
@@ -17,6 +17,8 @@
package com.android.server.notification;
import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -57,6 +59,8 @@ public class ZenModeExtractorTest extends UiServiceTestCase {
assertFalse(r.isIntercepted());
when(mZenModeHelper.shouldIntercept(any())).thenReturn(true);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(
+ new NotificationManager.Policy(0,0,0));
extractor.process(r);
@@ -70,7 +74,8 @@ public class ZenModeExtractorTest extends UiServiceTestCase {
NotificationRecord r = generateRecord();
when(mZenModeHelper.shouldIntercept(any())).thenReturn(false);
- when(mZenModeHelper.shouldSuppressWhenScreenOff()).thenReturn(false);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(
+ new NotificationManager.Policy(0,0,0));
extractor.process(r);
@@ -84,13 +89,14 @@ public class ZenModeExtractorTest extends UiServiceTestCase {
NotificationRecord r = generateRecord();
when(mZenModeHelper.shouldIntercept(any())).thenReturn(true);
- when(mZenModeHelper.shouldSuppressWhenScreenOff()).thenReturn(true);
- when(mZenModeHelper.shouldSuppressWhenScreenOn()).thenReturn(true);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(
+ new NotificationManager.Policy(0,0,0, SUPPRESSED_EFFECT_PEEK
+ | SUPPRESSED_EFFECT_NOTIFICATION_LIST));
extractor.process(r);
- assertEquals(NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF
- | NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON,
+ assertEquals(NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK
+ | NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST,
r.getSuppressedVisualEffects());
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
new file mode 100644
index 0000000000000..1936439240426
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distriZenbuted on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
+import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+import static android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS;
+import static android.provider.Settings.Global.ZEN_MODE_OFF;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.service.notification.StatusBarNotification;
+import android.service.notification.ZenModeConfig;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class ZenModeFilteringTest extends UiServiceTestCase {
+
+ private ZenModeFiltering mZenModeFiltering;
+
+ @Before
+ public void setUp() {
+ mZenModeFiltering = new ZenModeFiltering(mContext);
+ }
+
+ private NotificationRecord getNotificationRecord() {
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getNotification()).thenReturn(mock(Notification.class));
+ return new NotificationRecord(mContext, sbn, mock(NotificationChannel.class));
+ }
+
+ @Test
+ public void testSuppressDNDInfo_yes_VisEffectsAllowed() {
+ NotificationRecord r = getNotificationRecord();
+ when(r.sbn.getPackageName()).thenReturn("android");
+ when(r.sbn.getId()).thenReturn(SystemMessage.NOTE_ZEN_UPGRADE);
+ ZenModeConfig config = mock(ZenModeConfig.class);
+ config.suppressedVisualEffects = NotificationManager.Policy.getAllSuppressedVisualEffects()
+ - SUPPRESSED_EFFECT_STATUS_BAR;
+
+ assertTrue(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config, r));
+ }
+
+ @Test
+ public void testSuppressDNDInfo_yes_WrongId() {
+ NotificationRecord r = getNotificationRecord();
+ when(r.sbn.getPackageName()).thenReturn("android");
+ when(r.sbn.getId()).thenReturn(SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION);
+ ZenModeConfig config = mock(ZenModeConfig.class);
+ config.suppressedVisualEffects = NotificationManager.Policy.getAllSuppressedVisualEffects();
+
+ assertTrue(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config, r));
+ }
+
+ @Test
+ public void testSuppressDNDInfo_yes_WrongPackage() {
+ NotificationRecord r = getNotificationRecord();
+ when(r.sbn.getPackageName()).thenReturn("android2");
+ when(r.sbn.getId()).thenReturn(SystemMessage.NOTE_ZEN_UPGRADE);
+ ZenModeConfig config = mock(ZenModeConfig.class);
+ config.suppressedVisualEffects = NotificationManager.Policy.getAllSuppressedVisualEffects();
+
+ assertTrue(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config, r));
+ }
+
+ @Test
+ public void testSuppressDNDInfo_no() {
+ NotificationRecord r = getNotificationRecord();
+ when(r.sbn.getPackageName()).thenReturn("android");
+ when(r.sbn.getId()).thenReturn(SystemMessage.NOTE_ZEN_UPGRADE);
+ ZenModeConfig config = mock(ZenModeConfig.class);
+ config.suppressedVisualEffects = NotificationManager.Policy.getAllSuppressedVisualEffects();
+
+ assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config, r));
+ assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_ALARMS, config, r));
+ assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_NO_INTERRUPTIONS, config, r));
+ }
+
+ @Test
+ public void testSuppressAnything_yes_ZenModeOff() {
+ NotificationRecord r = getNotificationRecord();
+ when(r.sbn.getPackageName()).thenReturn("bananas");
+ ZenModeConfig config = mock(ZenModeConfig.class);
+
+ assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_OFF, config, r));
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 5bfa15a7b8c04..9008803c2c2f9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -16,6 +16,8 @@
package com.android.server.notification;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertEquals;
import static junit.framework.TestCase.assertTrue;
@@ -34,6 +36,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
@@ -48,8 +51,11 @@ import android.service.notification.ZenModeConfig;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.Xml;
+import com.android.internal.R;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.util.FastXmlSerializer;
import com.android.server.UiServiceTestCase;
import android.util.Slog;
@@ -58,6 +64,13 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -80,12 +93,27 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mContext = spy(getContext());
mContentResolver = mContext.getContentResolver();
when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getString(R.string.zen_mode_default_every_night_name)).thenReturn("night");
+ when(mResources.getString(R.string.zen_mode_default_events_name)).thenReturn("events");
when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(),
mConditionProviders));
}
+ private ByteArrayOutputStream writeXmlAndPurge(boolean forBackup)
+ throws Exception {
+ XmlSerializer serializer = new FastXmlSerializer();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+ serializer.startDocument(null, true);
+ mZenModeHelperSpy.writeXml(serializer, forBackup);
+ serializer.endDocument();
+ serializer.flush();
+ mZenModeHelperSpy.setConfig(new ZenModeConfig(), "writing xml");
+ return baos;
+ }
+
@Test
public void testZenOff_NoMuteApplied() {
mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_OFF;
@@ -497,4 +525,71 @@ public class ZenModeHelperTest extends UiServiceTestCase {
verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL,
mZenModeHelperSpy.TAG);
}
+
+ @Test
+ public void testParcelConfig() {
+ mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mConfig.allowAlarms = false;
+ mZenModeHelperSpy.mConfig.allowMedia = false;
+ mZenModeHelperSpy.mConfig.allowSystem = false;
+ mZenModeHelperSpy.mConfig.allowReminders = true;
+ mZenModeHelperSpy.mConfig.allowCalls = true;
+ mZenModeHelperSpy.mConfig.allowMessages = true;
+ mZenModeHelperSpy.mConfig.allowEvents = true;
+ mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
+ mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
+ mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
+ mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
+ mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
+ mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a");
+ mZenModeHelperSpy.mConfig.manualRule.enabled = true;
+ mZenModeHelperSpy.mConfig.manualRule.snoozing = true;
+
+ ZenModeConfig actual = mZenModeHelperSpy.mConfig.copy();
+
+ assertEquals(mZenModeHelperSpy.mConfig, actual);
+ }
+
+ @Test
+ public void testWriteXml() throws Exception {
+ mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mConfig.allowAlarms = false;
+ mZenModeHelperSpy.mConfig.allowMedia = false;
+ mZenModeHelperSpy.mConfig.allowSystem = false;
+ mZenModeHelperSpy.mConfig.allowReminders = true;
+ mZenModeHelperSpy.mConfig.allowCalls = true;
+ mZenModeHelperSpy.mConfig.allowMessages = true;
+ mZenModeHelperSpy.mConfig.allowEvents = true;
+ mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
+ mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
+ mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
+ mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
+ mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
+ mZenModeHelperSpy.mConfig.manualRule.zenMode =
+ Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a");
+ mZenModeHelperSpy.mConfig.manualRule.enabled = true;
+ mZenModeHelperSpy.mConfig.manualRule.snoozing = true;
+
+ ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(false);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertEquals(expected, mZenModeHelperSpy.mConfig);
+ }
+
+ @Test
+ public void testPolicyReadsSuppressedEffects() {
+ mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
+ mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
+ mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
+
+ NotificationManager.Policy policy = mZenModeHelperSpy.getNotificationPolicy();
+ assertEquals(SUPPRESSED_EFFECT_BADGE, policy.suppressedVisualEffects);
+ }
}