summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Yuri Lin <yurilin@google.com> 2023-12-06 17:25:48 -0500
committer Yuri Lin <yurilin@google.com> 2024-01-18 16:25:31 -0500
commitce2ae319be56b95e18929ccbe700dda4f63be988 (patch)
treea13285101f90a6b208772fe7855fc8e30fd2eb3e
parent5eba07633a0d8dd79285b2d5eb2bb1a3d94bcccc (diff)
Change default ZenPolicy to use device defaults.
If a rule has no specified zen policy, it will apply the device default config rather than the policy attached to manual DND. Manual DND continues to have its configuration tied to the "global" ZenModeConfig. Further, as part of this change, all policies become fully specified: rather than having the default inherently implied by a null ZenPolicy, all rules have a fully-specified ZenPolicy object with all fields set. This adds some upgrade-specific behavior for devices moving from a previous XML version, as all pre-existing rules get a copy of the manual/global DND policy to preserve consistency with their previous behavior. Bug: 312739308 Test: manual by navigating Settings on device and observing changed upgrade behavior Test: ZenModeHelperTest, NotificationManagerServiceTest, NotificationManagerZenTest (cts), ZenPolicyTest Change-Id: I9130f5fa83f9dc8cd61dc576edf9cc65915d60be
-rw-r--r--core/api/test-current.txt5
-rw-r--r--core/java/android/app/INotificationManager.aidl2
-rw-r--r--core/java/android/app/NotificationManager.java14
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java20
-rw-r--r--core/java/android/service/notification/ZenPolicy.aidl19
-rw-r--r--core/java/android/service/notification/ZenPolicy.java48
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java15
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java118
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java723
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java72
10 files changed, 928 insertions, 108 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index a5c2af76479b..bf75fcc6853a 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -371,6 +371,7 @@ package android.app {
public class NotificationManager {
method @FlaggedApi("android.app.modes_api") @NonNull public String addAutomaticZenRule(@NonNull android.app.AutomaticZenRule, boolean);
method public void cleanUpCallersAfter(long);
+ method @FlaggedApi("android.app.modes_api") @NonNull public android.service.notification.ZenPolicy getDefaultZenPolicy();
method public android.content.ComponentName getEffectsSuppressor();
method public boolean isNotificationPolicyAccessGrantedForPackage(@NonNull String);
method @FlaggedApi("android.app.modes_api") public boolean removeAutomaticZenRule(@NonNull String, boolean);
@@ -3017,6 +3018,10 @@ package android.service.notification {
method @Deprecated public boolean isBound();
}
+ public final class ZenPolicy implements android.os.Parcelable {
+ method @FlaggedApi("android.app.modes_api") @NonNull public android.service.notification.ZenPolicy overwrittenWith(@Nullable android.service.notification.ZenPolicy);
+ }
+
public static final class ZenPolicy.Builder {
ctor public ZenPolicy.Builder(@Nullable android.service.notification.ZenPolicy);
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index c3adbc30641f..578105f9f99e 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -38,6 +38,7 @@ import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
import android.service.notification.NotificationListenerFilter;
import android.service.notification.StatusBarNotification;
+import android.service.notification.ZenPolicy;
import android.app.AutomaticZenRule;
import android.service.notification.ZenModeConfig;
@@ -213,6 +214,7 @@ interface INotificationManager
boolean isNotificationPolicyAccessGrantedForPackage(String pkg);
void setNotificationPolicyAccessGranted(String pkg, boolean granted);
void setNotificationPolicyAccessGrantedForUser(String pkg, int userId, boolean granted);
+ ZenPolicy getDefaultZenPolicy();
AutomaticZenRule getAutomaticZenRule(String id);
Map<String, AutomaticZenRule> getAutomaticZenRules();
// TODO: b/310620812 - Remove getZenRules() when MODES_API is inlined.
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 0b6e24cf5545..366b45badcfd 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1750,6 +1750,20 @@ public class NotificationManager {
@NonNull ComponentName listener, boolean granted) {
setNotificationListenerAccessGranted(listener, granted, true);
}
+ /**
+ * Gets the device-default notification policy as a ZenPolicy.
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public @NonNull ZenPolicy getDefaultZenPolicy() {
+ INotificationManager service = getService();
+ try {
+ return service.getDefaultZenPolicy();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
/**
* For apps targeting {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} and above, the
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index c479877fe98e..9895551a8672 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -185,7 +185,13 @@ public class ZenModeConfig implements Parcelable {
SUPPRESSED_EFFECT_SCREEN_OFF | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
| SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT;
- public static final int XML_VERSION = 8;
+ // ZenModeConfig XML versions distinguishing key changes.
+ public static final int XML_VERSION_ZEN_UPGRADE = 8;
+ public static final int XML_VERSION_MODES_API = 11;
+
+ // TODO: b/310620812 - Update XML_VERSION and update default_zen_config.xml accordingly when
+ // modes_api is inlined.
+ private static final int XML_VERSION = 10;
public static final String ZEN_TAG = "zen";
private static final String ZEN_ATT_VERSION = "version";
private static final String ZEN_ATT_USER = "user";
@@ -586,6 +592,10 @@ public class ZenModeConfig implements Parcelable {
}
}
+ public static int getCurrentXmlVersion() {
+ return Flags.modesApi() ? XML_VERSION_MODES_API : XML_VERSION;
+ }
+
public static ZenModeConfig readXml(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
int type = parser.getEventType();
@@ -593,7 +603,7 @@ public class ZenModeConfig implements Parcelable {
String tag = parser.getName();
if (!ZEN_TAG.equals(tag)) return null;
final ZenModeConfig rt = new ZenModeConfig();
- rt.version = safeInt(parser, ZEN_ATT_VERSION, XML_VERSION);
+ rt.version = safeInt(parser, ZEN_ATT_VERSION, getCurrentXmlVersion());
rt.user = safeInt(parser, ZEN_ATT_USER, rt.user);
boolean readSuppressedEffects = false;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -707,14 +717,16 @@ public class ZenModeConfig implements Parcelable {
/**
* Writes XML of current ZenModeConfig
* @param out serializer
- * @param version uses XML_VERSION if version is null
+ * @param version uses the current XML version if version is null
* @throws IOException
*/
+
public void writeXml(TypedXmlSerializer out, Integer version, boolean forBackup)
throws IOException {
+ int xmlVersion = getCurrentXmlVersion();
out.startTag(null, ZEN_TAG);
out.attribute(null, ZEN_ATT_VERSION, version == null
- ? Integer.toString(XML_VERSION) : Integer.toString(version));
+ ? Integer.toString(xmlVersion) : Integer.toString(version));
out.attributeInt(null, ZEN_ATT_USER, user);
out.startTag(null, ALLOW_TAG);
out.attributeBoolean(null, ALLOW_ATT_CALLS, allowCalls);
diff --git a/core/java/android/service/notification/ZenPolicy.aidl b/core/java/android/service/notification/ZenPolicy.aidl
new file mode 100644
index 000000000000..b56f5c6989bf
--- /dev/null
+++ b/core/java/android/service/notification/ZenPolicy.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2023 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 distributed 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 android.service.notification;
+
+parcelable ZenPolicy; \ No newline at end of file
diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java
index fb491d010f54..d8318a6bee7c 100644
--- a/core/java/android/service/notification/ZenPolicy.java
+++ b/core/java/android/service/notification/ZenPolicy.java
@@ -1422,6 +1422,54 @@ public final class ZenPolicy implements Parcelable {
}
/**
+ * Overwrites any policy values in this ZenPolicy with set values from newPolicy and
+ * returns a copy of the resulting ZenPolicy.
+ * Unlike apply(), values set in newPolicy will always be kept over pre-existing
+ * fields. Any values in newPolicy that are not set keep their currently set values.
+ *
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public @NonNull ZenPolicy overwrittenWith(@Nullable ZenPolicy newPolicy) {
+ ZenPolicy result = this.copy();
+
+ if (newPolicy == null) {
+ return result;
+ }
+
+ // set priority categories
+ for (int category = 0; category < mPriorityCategories.size(); category++) {
+ @State int newState = newPolicy.mPriorityCategories.get(category);
+ if (newState != STATE_UNSET) {
+ result.mPriorityCategories.set(category, newState);
+
+ if (category == PRIORITY_CATEGORY_MESSAGES) {
+ result.mPriorityMessages = newPolicy.mPriorityMessages;
+ } else if (category == PRIORITY_CATEGORY_CALLS) {
+ result.mPriorityCalls = newPolicy.mPriorityCalls;
+ } else if (category == PRIORITY_CATEGORY_CONVERSATIONS) {
+ result.mConversationSenders = newPolicy.mConversationSenders;
+ }
+ }
+ }
+
+ // set visual effects
+ for (int visualEffect = 0; visualEffect < mVisualEffects.size(); visualEffect++) {
+ if (newPolicy.mVisualEffects.get(visualEffect) != STATE_UNSET) {
+ result.mVisualEffects.set(visualEffect, newPolicy.mVisualEffects.get(visualEffect));
+ }
+ }
+
+ // set allowed channels
+ if (newPolicy.mAllowChannels != CHANNEL_POLICY_UNSET) {
+ result.mAllowChannels = newPolicy.mAllowChannels;
+ }
+
+ return result;
+ }
+
+ /**
* @hide
*/
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 2ae040a69583..4ba0217da8a7 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -281,6 +281,7 @@ import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeProto;
+import android.service.notification.ZenPolicy;
import android.telecom.TelecomManager;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
@@ -5944,6 +5945,20 @@ public class NotificationManagerService extends SystemService {
}
}
+ /**
+ * Gets the device-default zen policy as a ZenPolicy.
+ */
+ @Override
+ public ZenPolicy getDefaultZenPolicy() {
+ enforceSystemOrSystemUI("INotificationManager.getDefaultZenPolicy");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mZenModeHelper.getDefaultZenPolicy();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
@Override
public List<String> getEnabledNotificationListenerPackages() {
checkCallerIsSystem();
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 93ffd974bb80..8d4381c35ad5 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -603,6 +603,14 @@ public class ZenModeHelper {
ZenRule rule = newConfig.automaticRules.get(implicitRuleId(callingPkg));
if (rule == null) {
rule = newImplicitZenRule(callingPkg);
+
+ // For new implicit rules, create a policy matching the current global
+ // (manual rule) settings, for consistency with the policy that
+ // would apply if changing the global interruption filter. We only do this
+ // for newly created rules, as existing rules have a pre-existing policy
+ // (whether initialized here or set via app or user).
+ rule.zenPolicy = mConfig.toZenPolicy();
+
newConfig.automaticRules.put(rule.id, rule);
}
// If the user has changed the rule's *zenMode*, then don't let app overwrite it.
@@ -614,6 +622,7 @@ public class ZenModeHelper {
rule.condition = new Condition(rule.conditionId,
mContext.getString(R.string.zen_mode_implicit_activated),
Condition.STATE_TRUE);
+
setConfigLocked(newConfig, /* triggeringComponent= */ null, UPDATE_ORIGIN_APP,
"applyGlobalZenModeAsImplicitZenRule", callingUid);
}
@@ -642,8 +651,10 @@ public class ZenModeHelper {
return;
}
ZenModeConfig newConfig = mConfig.copy();
+ boolean isNew = false;
ZenRule rule = newConfig.automaticRules.get(implicitRuleId(callingPkg));
if (rule == null) {
+ isNew = true;
rule = newImplicitZenRule(callingPkg);
rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
newConfig.automaticRules.put(rule.id, rule);
@@ -651,10 +662,20 @@ public class ZenModeHelper {
// If the user has changed the rule's *ZenPolicy*, then don't let app overwrite it.
// We allow the update if the user has only changed other aspects of the rule.
if (rule.zenPolicyUserModifiedFields == 0) {
+ ZenPolicy newZenPolicy = ZenAdapters.notificationPolicyToZenPolicy(policy);
+ if (isNew) {
+ // For new rules only, fill anything underspecified in the new policy with
+ // values from the global configuration, for consistency with the policy that
+ // would take effect if changing the global policy.
+ // Note that NotificationManager.Policy cannot have any unset priority
+ // categories, but *can* have unset visual effects, which is why we do this.
+ newZenPolicy = mConfig.toZenPolicy().overwrittenWith(newZenPolicy);
+ }
updatePolicy(
rule,
- ZenAdapters.notificationPolicyToZenPolicy(policy),
- /* updateBitmask= */ false);
+ newZenPolicy,
+ /* updateBitmask= */ false,
+ isNew);
setConfigLocked(newConfig, /* triggeringComponent= */ null, UPDATE_ORIGIN_APP,
"applyGlobalPolicyAsImplicitZenRule", callingUid);
@@ -684,6 +705,11 @@ public class ZenModeHelper {
}
ZenRule implicitRule = mConfig.automaticRules.get(implicitRuleId(callingPkg));
if (implicitRule != null && implicitRule.zenPolicy != null) {
+ // toNotificationPolicy takes defaults from mConfig, and technically, those are not
+ // the defaults that would apply if any fields were unset. However, all rules should
+ // have all fields set in their ZenPolicy objects upon rule creation, so in
+ // practice, this is only filling in the areChannelsBypassingDnd field, which is a
+ // state rather than a part of the policy.
return mConfig.toNotificationPolicy(implicitRule.zenPolicy);
} else {
return getNotificationPolicy();
@@ -1071,7 +1097,8 @@ public class ZenModeHelper {
rule.zenMode = newZenMode;
// Updates the bitmask and values for all policy fields, based on the origin.
- updatePolicy(rule, automaticZenRule.getZenPolicy(), updateBitmask);
+ updatePolicy(rule, automaticZenRule.getZenPolicy(), updateBitmask, isNew);
+
// Updates the bitmask and values for all device effect fields, based on the origin.
updateZenDeviceEffects(rule, automaticZenRule.getDeviceEffects(),
origin == UPDATE_ORIGIN_APP, updateBitmask);
@@ -1110,14 +1137,19 @@ public class ZenModeHelper {
/**
* Modifies the {@link ZenPolicy} associated to a new or updated ZenRule.
*
- * <p>The new policy is {@code newPolicy}, while the user-modified bitmask is updated to reflect
- * the changes being applied (if applicable, i.e. if the update is from the user).
+ * <p>The update takes any set fields in {@code newPolicy} as new policy settings for the
+ * provided {@code ZenRule}, keeping any pre-existing settings from {@code zenRule.zenPolicy}
+ * for any unset policy fields in {@code newPolicy}. The user-modified bitmask is updated to
+ * reflect the changes being applied (if applicable, i.e. if the update is from the user).
*/
private void updatePolicy(ZenRule zenRule, @Nullable ZenPolicy newPolicy,
- boolean updateBitmask) {
+ boolean updateBitmask, boolean isNew) {
if (newPolicy == null) {
- // TODO: b/319242206 - Treat as newPolicy == default policy and continue below.
- zenRule.zenPolicy = null;
+ if (isNew) {
+ // Newly created rule with no provided policy; fill in with the default.
+ zenRule.zenPolicy = mDefaultConfig.toZenPolicy();
+ }
+ // Otherwise, a null policy means no policy changes, so we can stop here.
return;
}
@@ -1126,6 +1158,16 @@ public class ZenModeHelper {
ZenPolicy oldPolicy =
zenRule.zenPolicy != null ? zenRule.zenPolicy : mDefaultConfig.toZenPolicy();
+ // If this is updating a rule rather than creating a new one, keep any fields from the
+ // old policy if they are unspecified in the new policy. For newly created rules, oldPolicy
+ // has been set to the default settings above, so any unspecified fields in a newly created
+ // policy are filled with default values. Then use the fully-specified version of the new
+ // policy for comparison below.
+ //
+ // Although we do not expect a policy update from the user to contain any unset fields,
+ // filling in fields here also guards against any unset fields counting as a "diff" when
+ // comparing fields for bitmask editing below.
+ newPolicy = oldPolicy.overwrittenWith(newPolicy);
zenRule.zenPolicy = newPolicy;
if (updateBitmask) {
@@ -1451,11 +1493,27 @@ public class ZenModeHelper {
}
allRulesDisabled &= !automaticRule.enabled;
+
+ // Upon upgrading to a version with modes_api enabled, keep all behaviors of
+ // rules with null ZenPolicies explicitly as a copy of the global policy.
+ if (Flags.modesApi() && config.version < ZenModeConfig.XML_VERSION_MODES_API) {
+ // Keep the manual ("global") policy that from config.
+ ZenPolicy manualRulePolicy = config.toZenPolicy();
+ if (automaticRule.zenPolicy == null) {
+ automaticRule.zenPolicy = manualRulePolicy;
+ } else {
+ // newPolicy is a policy with all unset fields in the rule's zenPolicy
+ // set to their values from the values in config. Then convert that back
+ // to ZenPolicy to store with the automatic zen rule.
+ automaticRule.zenPolicy =
+ manualRulePolicy.overwrittenWith(automaticRule.zenPolicy);
+ }
+ }
}
}
if (!hasDefaultRules && allRulesDisabled
- && (forRestore || config.version < ZenModeConfig.XML_VERSION)) {
+ && (forRestore || config.version < ZenModeConfig.XML_VERSION_ZEN_UPGRADE)) {
// reset zen automatic rules to default on restore or upgrade if:
// - doesn't already have default rules and
// - all previous automatic rules were disabled
@@ -1472,7 +1530,7 @@ public class ZenModeHelper {
// Resolve user id for settings.
userId = userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
- if (config.version < ZenModeConfig.XML_VERSION) {
+ if (config.version < ZenModeConfig.XML_VERSION_ZEN_UPGRADE) {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 1, userId);
} else {
@@ -1599,6 +1657,14 @@ public class ZenModeHelper {
return mConsolidatedPolicy.copy();
}
+ /**
+ * Returns a copy of the device default policy as a ZenPolicy object.
+ */
+ @VisibleForTesting
+ protected ZenPolicy getDefaultZenPolicy() {
+ return mDefaultConfig.toZenPolicy();
+ }
+
@GuardedBy("mConfigLock")
private boolean setConfigLocked(ZenModeConfig config, ComponentName triggeringComponent,
@ConfigChangeOrigin int origin, String reason, int callingUid) {
@@ -1782,7 +1848,7 @@ public class ZenModeHelper {
}
@GuardedBy("mConfigLock")
- private void applyCustomPolicy(ZenPolicy policy, ZenRule rule) {
+ private void applyCustomPolicy(ZenPolicy policy, ZenRule rule, boolean useManualConfig) {
if (rule.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
policy.apply(new ZenPolicy.Builder()
.disallowAllSounds()
@@ -1796,8 +1862,22 @@ public class ZenModeHelper {
} else if (rule.zenPolicy != null) {
policy.apply(rule.zenPolicy);
} else {
- // active rule with no specified policy inherits the default settings
- policy.apply(mConfig.toZenPolicy());
+ if (Flags.modesApi()) {
+ if (useManualConfig) {
+ // manual rule is configured using the settings stored directly in mConfig
+ policy.apply(mConfig.toZenPolicy());
+ } else {
+ // under modes_api flag, an active automatic rule with no specified policy
+ // inherits the device default settings as stored in mDefaultConfig. While the
+ // rule's policy fields should be set upon creation, this is a fallback to
+ // catch any that may have fallen through the cracks.
+ Log.wtf(TAG, "active automatic rule found with no specified policy: " + rule);
+ policy.apply(mDefaultConfig.toZenPolicy());
+ }
+ } else {
+ // active rule with no specified policy inherits the global config settings
+ policy.apply(mConfig.toZenPolicy());
+ }
}
}
@@ -1809,7 +1889,7 @@ public class ZenModeHelper {
ZenPolicy policy = new ZenPolicy();
ZenDeviceEffects.Builder deviceEffectsBuilder = new ZenDeviceEffects.Builder();
if (mConfig.manualRule != null) {
- applyCustomPolicy(policy, mConfig.manualRule);
+ applyCustomPolicy(policy, mConfig.manualRule, true);
if (Flags.modesApi()) {
deviceEffectsBuilder.add(mConfig.manualRule.zenDeviceEffects);
}
@@ -1821,7 +1901,7 @@ public class ZenModeHelper {
// policy. This is relevant in case some other active rule has a more
// restrictive INTERRUPTION_FILTER but a more lenient ZenPolicy!
if (!Flags.modesApi() || automaticRule.zenMode != Global.ZEN_MODE_OFF) {
- applyCustomPolicy(policy, automaticRule);
+ applyCustomPolicy(policy, automaticRule, false);
}
if (Flags.modesApi()) {
deviceEffectsBuilder.add(automaticRule.zenDeviceEffects);
@@ -1829,6 +1909,14 @@ public class ZenModeHelper {
}
}
+ // While mConfig.toNotificationPolicy fills in any unset fields from the provided
+ // config (which, in this case is the manual "global" config), under modes API changes,
+ // we should have no remaining unset fields: the manual policy gets every field from
+ // the global policy, and each automatic rule has all policy fields filled in on
+ // creation or update.
+ // However, the piece of information that comes from mConfig that we must keep is the
+ // areChannelsBypassingDnd bit, which is a state, rather than a policy, and even when
+ // all policy fields are set, this state comes to the new policy from this call.
Policy newPolicy = mConfig.toNotificationPolicy(policy);
if (!Objects.equals(mConsolidatedPolicy, newPolicy)) {
mConsolidatedPolicy = newPolicy;
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 edc876aab388..5b73b0339e34 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -59,6 +59,7 @@ import static android.service.notification.ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR
import static android.service.notification.ZenModeConfig.UPDATE_ORIGIN_UNKNOWN;
import static android.service.notification.ZenModeConfig.UPDATE_ORIGIN_USER;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_CONTACTS;
+import static android.service.notification.ZenPolicy.PEOPLE_TYPE_NONE;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_STARRED;
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.LOG_DND_STATE_EVENTS;
@@ -123,6 +124,7 @@ import android.os.Parcel;
import android.os.Process;
import android.os.SimpleClock;
import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
@@ -238,15 +240,19 @@ public class ZenModeHelperTest extends UiServiceTestCase {
public TestWithLooperRule mLooperRule = new TestWithLooperRule();
ConditionProviders mConditionProviders;
- @Mock NotificationManager mNotificationManager;
- @Mock PackageManager mPackageManager;
+ @Mock
+ NotificationManager mNotificationManager;
+ @Mock
+ PackageManager mPackageManager;
private Resources mResources;
private TestableLooper mTestableLooper;
private final TestClock mTestClock = new TestClock();
private ZenModeHelper mZenModeHelper;
private ContentResolver mContentResolver;
- @Mock DeviceEffectsApplier mDeviceEffectsApplier;
- @Mock AppOpsManager mAppOps;
+ @Mock
+ DeviceEffectsApplier mDeviceEffectsApplier;
+ @Mock
+ AppOpsManager mAppOps;
TestableFlagResolver mTestFlagResolver = new TestableFlagResolver();
ZenModeEventLoggerFake mZenModeEventLogger;
@@ -290,7 +296,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
when(mPackageManager.getPackageUidAsUser(eq(CUSTOM_PKG_NAME), anyInt()))
.thenReturn(CUSTOM_PKG_UID);
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(
- new String[] {pkg});
+ new String[]{pkg});
ApplicationInfo appInfoSpy = spy(new ApplicationInfo());
appInfoSpy.icon = ICON_RES_ID;
@@ -305,24 +311,26 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
private XmlResourceParser getDefaultConfigParser() throws IOException, XmlPullParserException {
- String xml = "<zen version=\"8\" user=\"0\">\n"
- + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
- + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
- + "visualScreenOff=\"true\" alarms=\"true\" "
- + "media=\"true\" system=\"false\" conversations=\"true\""
- + " conversationsFrom=\"2\"/>\n"
- + "<automatic ruleId=\"" + EVENTS_DEFAULT_RULE_ID
- + "\" enabled=\"false\" snoozing=\"false\""
- + " name=\"Event\" zen=\"1\""
- + " component=\"android/com.android.server.notification.EventConditionProvider\""
- + " conditionId=\"condition://android/event?userId=-10000&amp;calendar=&amp;"
+ String xml = "<zen version=\"10\">\n"
+ + "<allow alarms=\"true\" media=\"true\" system=\"false\" calls=\"true\" "
+ + "callsFrom=\"2\" messages=\"true\"\n"
+ + "messagesFrom=\"2\" reminders=\"false\" events=\"false\" "
+ + "repeatCallers=\"true\" convos=\"true\"\n"
+ + "convosFrom=\"2\"/>\n"
+ + "<automatic ruleId=" + EVENTS_DEFAULT_RULE_ID
+ + " enabled=\"false\" snoozing=\"false\""
+ + " name=\"Event\" zen=\"1\"\n"
+ + " component=\"android/com.android.server.notification.EventConditionProvider\"\n"
+ + " conditionId=\"condition://android/event?userId=-10000&amp;calendar=&amp;"
+ "reply=1\"/>\n"
- + "<automatic ruleId=\"" + SCHEDULE_DEFAULT_RULE_ID + "\" enabled=\"false\""
- + " snoozing=\"false\" name=\"Sleeping\" zen=\"1\""
- + " component=\"android/com.android.server.notification.ScheduleConditionProvider\""
- + " conditionId=\"condition://android/schedule?days=1.2.3.4.5.6.7 &amp;start=22.0"
- + "&amp;end=7.0&amp;exitAtAlarm=true\"/>"
- + "<disallow visualEffects=\"511\" />"
+ + "<automatic ruleId=" + SCHEDULE_DEFAULT_RULE_ID + " enabled=\"false\""
+ + " snoozing=\"false\" name=\"Sleeping\"\n zen=\"1\""
+ + " component=\"android/com.android.server.notification"
+ + ".ScheduleConditionProvider\"\n"
+ + " conditionId=\"condition://android/schedule?days=1.2.3.4.5.6.7&amp;start=22.0"
+ + "&amp;end=7.0&amp;exitAtAlarm=true\"/>\n"
+ + "<disallow visualEffects=\"157\" />\n"
+ + "<state areChannelsBypassingDnd=\"false\" />\n"
+ "</zen>";
TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), null);
@@ -408,7 +416,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testZenOff_NoMuteApplied() {
mZenModeHelper.mZenMode = ZEN_MODE_OFF;
- mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+ mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[]{PKG_O});
mZenModeHelper.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS
| PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0);
mZenModeHelper.applyRestrictions();
@@ -421,7 +429,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testZenOn_NotificationApplied() {
mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+ mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[]{PKG_O});
// The most permissive policy
mZenModeHelper.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS
| PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES
@@ -442,7 +450,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testZenOn_StarredCallers_CallTypesBlocked() {
mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+ mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[]{PKG_O});
// The most permissive policy
mZenModeHelper.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS
| PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES
@@ -462,7 +470,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testZenOn_AllCallers_CallTypesAllowed() {
mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+ mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[]{PKG_O});
// The most permissive policy
mZenModeHelper.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS
| PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES
@@ -481,7 +489,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testZenOn_AllowAlarmsMedia_NoAlarmMediaMuteApplied() {
mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+ mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[]{PKG_O});
mZenModeHelper.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS
| PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0);
@@ -493,7 +501,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testZenOn_DisallowAlarmsMedia_AlarmMediaMuteApplied() {
mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+ mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[]{PKG_O});
mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
mZenModeHelper.applyRestrictions();
verifyApplyRestrictions(true, true, AudioAttributes.USAGE_ALARM);
@@ -506,7 +514,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testTotalSilence() {
mZenModeHelper.mZenMode = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS;
- mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+ mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[]{PKG_O});
mZenModeHelper.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS
| PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0);
mZenModeHelper.applyRestrictions();
@@ -525,7 +533,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testAlarmsOnly_alarmMediaMuteNotApplied() {
mZenModeHelper.mZenMode = Settings.Global.ZEN_MODE_ALARMS;
- mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+ mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[]{PKG_O});
mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
mZenModeHelper.applyRestrictions();
@@ -545,7 +553,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testAlarmsOnly_callsMuteApplied() {
mZenModeHelper.mZenMode = Settings.Global.ZEN_MODE_ALARMS;
- mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+ mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[]{PKG_O});
mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
mZenModeHelper.applyRestrictions();
@@ -559,7 +567,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
public void testAlarmsOnly_allZenConfigToggledCannotBypass_alarmMuteNotApplied() {
// Only audio attributes with SUPPRESIBLE_NEVER can bypass
mZenModeHelper.mZenMode = Settings.Global.ZEN_MODE_ALARMS;
- mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+ mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[]{PKG_O});
mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
mZenModeHelper.applyRestrictions();
@@ -571,7 +579,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// Only audio attributes with SUPPRESIBLE_NEVER can bypass
// with special case USAGE_ASSISTANCE_SONIFICATION
mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+ mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[]{PKG_O});
mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
mZenModeHelper.applyRestrictions();
@@ -592,7 +600,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testApplyRestrictions_whitelist_priorityOnlyMode() {
- mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+ mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[]{PKG_O});
mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
mZenModeHelper.applyRestrictions();
@@ -607,7 +615,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testApplyRestrictions_whitelist_alarmsOnlyMode() {
- mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+ mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[]{PKG_O});
mZenModeHelper.mZenMode = Global.ZEN_MODE_ALARMS;
mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
mZenModeHelper.applyRestrictions();
@@ -622,7 +630,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testApplyRestrictions_whitelist_totalSilenceMode() {
- mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+ mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[]{PKG_O});
mZenModeHelper.mZenMode = Global.ZEN_MODE_NO_INTERRUPTIONS;
mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
mZenModeHelper.applyRestrictions();
@@ -1007,7 +1015,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
assertEquals("Config mismatch: current vs expected: "
- + new ZenModeDiff.ConfigDiff(mZenModeHelper.mConfig, expected), expected,
+ + new ZenModeDiff.ConfigDiff(mZenModeHelper.mConfig, expected), expected,
mZenModeHelper.mConfig);
}
@@ -1314,7 +1322,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mZenModeHelper.readXml(parser, true, UserHandle.USER_SYSTEM);
assertEquals("Config mismatch: current vs original: "
- + new ZenModeDiff.ConfigDiff(mZenModeHelper.mConfig, original),
+ + new ZenModeDiff.ConfigDiff(mZenModeHelper.mConfig, original),
original, mZenModeHelper.mConfig);
assertEquals(original.hashCode(), mZenModeHelper.mConfig.hashCode());
}
@@ -1756,6 +1764,225 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void testReadXml_onModesApi_noUpgrade() throws Exception {
+ // When reading XML for something that is already on the modes API system, make sure no
+ // rules' policies get changed.
+ setupZenConfig();
+
+ // Shared for rules
+ ArrayMap<String, ZenModeConfig.ZenRule> enabledAutoRules = new ArrayMap<>();
+ final ScheduleInfo weeknights = new ScheduleInfo();
+
+ // Custom rule with a custom policy
+ ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
+ customRule.enabled = true;
+ customRule.name = "Custom Rule";
+ customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
+ customRule.component = new ComponentName("android", "ScheduleConditionProvider");
+ ZenPolicy policy = new ZenPolicy.Builder()
+ .allowCalls(PEOPLE_TYPE_CONTACTS)
+ .allowAlarms(true)
+ .allowRepeatCallers(false)
+ .build();
+ // Fill in policy fields, since on modes api we do not expect any rules to have unset fields
+ customRule.zenPolicy = mZenModeHelper.getDefaultZenPolicy().overwrittenWith(policy);
+ enabledAutoRules.put("customRule", customRule);
+ mZenModeHelper.mConfig.automaticRules = enabledAutoRules;
+
+ // set version to post-modes-API = 11
+ ByteArrayOutputStream baos = writeXmlAndPurge(11);
+ TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
+
+ // basic check: global config maintained
+ setupZenConfigMaintained();
+
+ // Find our automatic rules.
+ ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules;
+ assertThat(rules).hasSize(1);
+ assertThat(rules).containsKey("customRule");
+ ZenRule rule = rules.get("customRule");
+ assertThat(rule.zenPolicy).isEqualTo(customRule.zenPolicy);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void testReadXml_upgradeToModesApi_makesCustomPolicies() throws Exception {
+ // When reading in an XML file written from a pre-modes-API version, confirm that we create
+ // a custom policy matching the global config for any automatic rule with no specified
+ // policy.
+ setupZenConfig();
+
+ ArrayMap<String, ZenModeConfig.ZenRule> enabledAutoRule = new ArrayMap<>();
+ ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
+ final ScheduleInfo weeknights = new ScheduleInfo();
+ customRule.enabled = true;
+ customRule.name = "Custom Rule";
+ customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
+ customRule.component = new ComponentName("android", "ScheduleConditionProvider");
+ enabledAutoRule.put("customRule", customRule); // no custom policy set
+ mZenModeHelper.mConfig.automaticRules = enabledAutoRule;
+
+ // set version to pre-modes-API = 10
+ ByteArrayOutputStream baos = writeXmlAndPurge(10);
+ TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
+
+ // basic check: global config maintained
+ setupZenConfigMaintained();
+
+ // Find our automatic rule and check that it has a policy set now
+ ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules;
+ assertThat(rules).hasSize(1);
+ assertThat(rules).containsKey("customRule");
+ ZenRule rule = rules.get("customRule");
+ assertThat(rule.zenPolicy).isNotNull();
+
+ // Check policy values as set up in setupZenConfig() to confirm they match
+ assertThat(rule.zenPolicy.getPriorityCategoryAlarms()).isEqualTo(STATE_DISALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryMedia()).isEqualTo(STATE_DISALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategorySystem()).isEqualTo(STATE_DISALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryReminders()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryCalls()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCallSenders()).isEqualTo(PEOPLE_TYPE_STARRED);
+ assertThat(rule.zenPolicy.getPriorityCategoryMessages()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryConversations()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryEvents()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryRepeatCallers()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getVisualEffectBadge()).isEqualTo(STATE_DISALLOW);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void testReadXml_upgradeToModesApi_fillsInCustomPolicies() throws Exception {
+ // When reading in an XML file written from a pre-modes-API version, confirm that for an
+ // underspecified ZenPolicy, we fill in all of the gaps with things from the global config
+ // in order to maintain consistency of behavior.
+ setupZenConfig();
+
+ ArrayMap<String, ZenModeConfig.ZenRule> enabledAutoRule = new ArrayMap<>();
+ ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
+ final ScheduleInfo weeknights = new ScheduleInfo();
+ customRule.enabled = true;
+ customRule.name = "Custom Rule";
+ customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
+ customRule.component = new ComponentName("android", "ScheduleConditionProvider");
+ customRule.zenPolicy = new ZenPolicy.Builder()
+ .allowAlarms(true)
+ .allowMedia(true)
+ .allowRepeatCallers(false)
+ .build();
+ enabledAutoRule.put("customRule", customRule);
+ mZenModeHelper.mConfig.automaticRules = enabledAutoRule;
+
+ // set version to pre-modes-API = 10
+ ByteArrayOutputStream baos = writeXmlAndPurge(10);
+ TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
+
+ // basic check: global config maintained
+ setupZenConfigMaintained();
+
+ // Find our automatic rule and check that it has a policy set now
+ ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules;
+ assertThat(rules).hasSize(1);
+ assertThat(rules).containsKey("customRule");
+ ZenRule rule = rules.get("customRule");
+ assertThat(rule.zenPolicy).isNotNull();
+
+ // Check unset policy values match values in setupZenConfig().
+ // Check that set policy values match the values set in the policy.
+ assertThat(rule.zenPolicy.getPriorityCategoryAlarms()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryMedia()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryRepeatCallers()).isEqualTo(STATE_DISALLOW);
+
+ // Check that the rest is filled in from the default
+ assertThat(rule.zenPolicy.getPriorityCategorySystem()).isEqualTo(STATE_DISALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryReminders()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryCalls()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCallSenders()).isEqualTo(PEOPLE_TYPE_STARRED);
+ assertThat(rule.zenPolicy.getPriorityCategoryMessages()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryConversations()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryEvents()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getVisualEffectBadge()).isEqualTo(STATE_DISALLOW);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void testReadXml_upgradeToModesApi_existingDefaultRulesGetCustomPolicy()
+ throws Exception {
+ setupZenConfig();
+
+ // Default rules, if they exist and have no policies, should get a snapshot of the global
+ // policy, even if they are disabled upon upgrade.
+ ArrayMap<String, ZenModeConfig.ZenRule> automaticRules = new ArrayMap<>();
+ ZenModeConfig.ZenRule defaultScheduleRule = new ZenModeConfig.ZenRule();
+ final ScheduleInfo defaultScheduleRuleInfo = new ScheduleInfo();
+ defaultScheduleRule.enabled = false;
+ defaultScheduleRule.name = "Default Schedule Rule";
+ defaultScheduleRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ defaultScheduleRule.conditionId = ZenModeConfig.toScheduleConditionId(
+ defaultScheduleRuleInfo);
+ defaultScheduleRule.id = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID;
+ automaticRules.put(ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID, defaultScheduleRule);
+
+ ZenModeConfig.ZenRule defaultEventRule = new ZenModeConfig.ZenRule();
+ final ScheduleInfo defaultEventRuleInfo = new ScheduleInfo();
+ defaultEventRule.enabled = false;
+ defaultEventRule.name = "Default Event Rule";
+ defaultEventRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ defaultEventRule.conditionId = ZenModeConfig.toScheduleConditionId(
+ defaultEventRuleInfo);
+ defaultEventRule.id = ZenModeConfig.EVENTS_DEFAULT_RULE_ID;
+ automaticRules.put(ZenModeConfig.EVENTS_DEFAULT_RULE_ID, defaultEventRule);
+
+ mZenModeHelper.mConfig.automaticRules = automaticRules;
+
+ // set previous version
+ ByteArrayOutputStream baos = writeXmlAndPurge(10);
+ TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
+
+ // check default rules
+ ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules;
+ assertThat(rules.size()).isGreaterThan(0);
+ for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) {
+ assertThat(rules).containsKey(defaultId);
+ ZenRule rule = rules.get(defaultId);
+ assertThat(rule.zenPolicy).isNotNull();
+
+ // Check policy values as set up in setupZenConfig() to confirm they match
+ assertThat(rule.zenPolicy.getPriorityCategoryAlarms()).isEqualTo(STATE_DISALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryMedia()).isEqualTo(STATE_DISALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategorySystem()).isEqualTo(STATE_DISALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryReminders()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryCalls()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCallSenders()).isEqualTo(PEOPLE_TYPE_STARRED);
+ assertThat(rule.zenPolicy.getPriorityCategoryMessages()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryConversations()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryEvents()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getPriorityCategoryRepeatCallers()).isEqualTo(STATE_ALLOW);
+ assertThat(rule.zenPolicy.getVisualEffectBadge()).isEqualTo(STATE_DISALLOW);
+ }
+ }
+
+ @Test
public void testCountdownConditionSubscription() throws Exception {
ZenModeConfig config = new ZenModeConfig();
mZenModeHelper.mConfig = config;
@@ -2014,6 +2241,69 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void testAddAutomaticZenRule_modesApi_fillsInDefaultValues() {
+ // When a new automatic zen rule is added with only some fields filled in, ensure that
+ // all unset fields are filled in with device defaults.
+
+ // Zen rule with null policy: should get entirely the default state
+ AutomaticZenRule zenRule1 = new AutomaticZenRule("name",
+ new ComponentName("android", "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id1 = mZenModeHelper.addAutomaticZenRule("android", zenRule1,
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "test", Process.SYSTEM_UID);
+
+ // Zen rule with partially-filled policy: should get all of the filled fields set, and the
+ // rest filled with default state
+ AutomaticZenRule zenRule2 = new AutomaticZenRule("name",
+ null,
+ new ComponentName(mContext.getPackageName(), "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ new ZenPolicy.Builder()
+ .allowCalls(PEOPLE_TYPE_NONE)
+ .allowMessages(PEOPLE_TYPE_CONTACTS)
+ .showFullScreenIntent(true)
+ .build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id2 = mZenModeHelper.addAutomaticZenRule("android", zenRule2,
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "test", Process.SYSTEM_UID);
+
+ // rule 1 should exist
+ assertThat(id1).isNotNull();
+ ZenModeConfig.ZenRule rule1InConfig = mZenModeHelper.mConfig.automaticRules.get(id1);
+ assertThat(rule1InConfig).isNotNull();
+ assertThat(rule1InConfig.zenPolicy).isNotNull(); // we passed in null; it should now not be
+
+ // all of rule 1 should be the device default's policy
+ assertThat(rule1InConfig.zenPolicy).isEqualTo(mZenModeHelper.getDefaultZenPolicy());
+
+ // rule 2 should exist
+ assertThat(id2).isNotNull();
+ ZenModeConfig.ZenRule rule2InConfig = mZenModeHelper.mConfig.automaticRules.get(id2);
+ assertThat(rule2InConfig).isNotNull();
+
+ // rule 2: values set from the policy itself
+ assertThat(rule2InConfig.zenPolicy.getPriorityCallSenders()).isEqualTo(PEOPLE_TYPE_NONE);
+ assertThat(rule2InConfig.zenPolicy.getPriorityMessageSenders())
+ .isEqualTo(PEOPLE_TYPE_CONTACTS);
+ assertThat(rule2InConfig.zenPolicy.getVisualEffectFullScreenIntent())
+ .isEqualTo(ZenPolicy.STATE_ALLOW);
+
+ // the rest of rule 2's settings should be the device defaults
+ assertThat(rule2InConfig.zenPolicy.getPriorityConversationSenders())
+ .isEqualTo(CONVERSATION_SENDERS_IMPORTANT);
+ assertThat(rule2InConfig.zenPolicy.getPriorityCategorySystem())
+ .isEqualTo(ZenPolicy.STATE_DISALLOW);
+ assertThat(rule2InConfig.zenPolicy.getPriorityCategoryAlarms())
+ .isEqualTo(ZenPolicy.STATE_ALLOW);
+ assertThat(rule2InConfig.zenPolicy.getVisualEffectPeek())
+ .isEqualTo(ZenPolicy.STATE_DISALLOW);
+ assertThat(rule2InConfig.zenPolicy.getVisualEffectNotificationList())
+ .isEqualTo(ZenPolicy.STATE_ALLOW);
+ }
+
+ @Test
public void testSetAutomaticZenRuleState_nullPkg() {
AutomaticZenRule zenRule = new AutomaticZenRule("name",
null,
@@ -2335,6 +2625,68 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
@EnableFlags(Flags.FLAG_MODES_API)
+ public void updateAutomaticZenRule_nullPolicy_doesNothing() {
+ // Test that when updateAutomaticZenRule is called with a null policy, nothing changes
+ // about the existing policy.
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
+ new AutomaticZenRule.Builder("Rule", CONDITION_ID)
+ .setOwner(OWNER)
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowCalls(ZenPolicy.PEOPLE_TYPE_NONE) // default is stars
+ .build())
+ .build(),
+ UPDATE_ORIGIN_APP, "reasons", 0);
+
+ mZenModeHelper.updateAutomaticZenRule(ruleId,
+ new AutomaticZenRule.Builder("Rule", CONDITION_ID)
+ // no zen policy
+ .build(),
+ UPDATE_ORIGIN_APP, "reasons", 0);
+
+ AutomaticZenRule savedRule = mZenModeHelper.getAutomaticZenRule(ruleId);
+ assertThat(savedRule.getZenPolicy().getPriorityCategoryCalls())
+ .isEqualTo(ZenPolicy.STATE_DISALLOW);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void updateAutomaticZenRule_overwritesExistingPolicy() {
+ // Test that when updating an automatic zen rule with an existing policy, the newly set
+ // fields overwrite those from the previous policy, but unset fields in the new policy
+ // keep values from the previous one.
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
+ new AutomaticZenRule.Builder("Rule", CONDITION_ID)
+ .setOwner(OWNER)
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowCalls(ZenPolicy.PEOPLE_TYPE_NONE) // default is stars
+ .allowAlarms(false)
+ .allowReminders(true)
+ .build())
+ .build(),
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "reasons", 0);
+
+ mZenModeHelper.updateAutomaticZenRule(ruleId,
+ new AutomaticZenRule.Builder("Rule", CONDITION_ID)
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS)
+ .build())
+ .build(),
+ UPDATE_ORIGIN_APP, "reasons", 0);
+
+ AutomaticZenRule savedRule = mZenModeHelper.getAutomaticZenRule(ruleId);
+ assertThat(savedRule.getZenPolicy().getPriorityCategoryCalls())
+ .isEqualTo(ZenPolicy.STATE_ALLOW); // from update
+ assertThat(savedRule.getZenPolicy().getPriorityCallSenders())
+ .isEqualTo(ZenPolicy.PEOPLE_TYPE_CONTACTS); // from update
+ assertThat(savedRule.getZenPolicy().getPriorityCategoryAlarms())
+ .isEqualTo(ZenPolicy.STATE_DISALLOW); // from original
+ assertThat(savedRule.getZenPolicy().getPriorityCategoryReminders())
+ .isEqualTo(ZenPolicy.STATE_ALLOW); // from original
+ }
+
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
public void addAutomaticZenRule_withTypeBedtime_replacesDisabledSleeping() {
ZenRule sleepingRule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS,
ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
@@ -2438,7 +2790,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
DISABLED(false, /* originForUserActionInSystemUi= */ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI);
private final boolean mEnabled;
- @ConfigChangeOrigin private final int mOriginForUserActionInSystemUi;
+ @ConfigChangeOrigin
+ private final int mOriginForUserActionInSystemUi;
ModesApiFlag(boolean enabled, @ConfigChangeOrigin int originForUserActionInSystemUi) {
this.mEnabled = enabled;
@@ -2484,7 +2837,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// - rules active = 1
// - user action = true (system-based turning zen mode on)
// - package uid = system (as set above)
- // - resulting DNDPolicyProto the same as the values in setupZenConfig()
+ // - resulting DNDPolicyProto the same as the values in setupZenConfig() (global policy)
assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_ON.getId(),
mZenModeEventLogger.getEventId(0));
assertEquals(ZEN_MODE_OFF, mZenModeEventLogger.getPrevZenMode(0));
@@ -2578,7 +2931,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// - 1 rule (newly) active
// - automatic (is not a user action)
// - package UID is written to be the rule *owner* even though it "comes from system"
- // - zen policy is the same as the set-up zen config
+ // - zen policy is the default as it's unspecified
assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_ON.getId(),
mZenModeEventLogger.getEventId(0));
assertEquals(ZEN_MODE_OFF, mZenModeEventLogger.getPrevZenMode(0));
@@ -2587,10 +2940,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(1, mZenModeEventLogger.getNumRulesActive(0));
assertFalse(mZenModeEventLogger.getIsUserAction(0));
assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(0));
- checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(0));
+ checkDndProtoMatchesDefaultZenConfig(mZenModeEventLogger.getPolicyProto(0));
// When the automatic rule is disabled, this should turn off zen mode and also count as a
- // user action.
+ // user action. We don't care what the consolidated policy is when DND turns off.
assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_OFF.getId(),
mZenModeEventLogger.getEventId(1));
assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeEventLogger.getPrevZenMode(1));
@@ -2813,28 +3166,28 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// First: turn on rule 1
mZenModeHelper.setAutomaticZenRuleState(id,
new Condition(zenRule.getConditionId(), "", STATE_TRUE),
- UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
// Second: turn on rule 2
mZenModeHelper.setAutomaticZenRuleState(id2,
new Condition(zenRule2.getConditionId(), "", STATE_TRUE),
- UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
// Third: turn on rule 3
mZenModeHelper.setAutomaticZenRuleState(id3,
new Condition(zenRule3.getConditionId(), "", STATE_TRUE),
- UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
// Fourth: Turn *off* rule 2
mZenModeHelper.setAutomaticZenRuleState(id2,
new Condition(zenRule2.getConditionId(), "", STATE_FALSE),
- UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
// This should result in a total of four events
assertEquals(4, mZenModeEventLogger.numLoggedChanges());
// Event 1: rule 1 turns on. We expect this to turn on DND (zen mode) overall, so that's
- // what the event should reflect. At this time, the policy is the same as initial setup.
+ // what the event should reflect. At this time, the policy is the default.
assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_ON.getId(),
mZenModeEventLogger.getEventId(0));
assertEquals(ZEN_MODE_OFF, mZenModeEventLogger.getPrevZenMode(0));
@@ -2842,7 +3195,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(1, mZenModeEventLogger.getNumRulesActive(0));
assertFalse(mZenModeEventLogger.getIsUserAction(0));
assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(0));
- checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(0));
+ checkDndProtoMatchesDefaultZenConfig(mZenModeEventLogger.getPolicyProto(0));
// Event 2: rule 2 turns on. This should not change anything about the policy, so the only
// change is that there are more rules active now.
@@ -2851,7 +3204,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(2, mZenModeEventLogger.getNumRulesActive(1));
assertFalse(mZenModeEventLogger.getIsUserAction(1));
assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(1));
- checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1));
+ checkDndProtoMatchesDefaultZenConfig(mZenModeEventLogger.getPolicyProto(1));
// Event 3: rule 3 turns on. This should trigger a policy change, and be classified as such,
// but meanwhile also change the number of active rules.
@@ -2904,12 +3257,16 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
+ // Explicitly set up all rules with the same policy as the manual rule so there will be
+ // no policy changes in this test case.
+ ZenPolicy manualRulePolicy = mZenModeHelper.mConfig.toZenPolicy();
+
// Rule 1, owned by a package
AutomaticZenRule zenRule = new AutomaticZenRule("name",
null,
new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
- null,
+ manualRulePolicy,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule,
UPDATE_ORIGIN_APP, "test", Process.SYSTEM_UID);
@@ -2919,7 +3276,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
new ComponentName("android", "ScheduleConditionProvider"),
ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
- null,
+ manualRulePolicy,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id2 = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule2,
modesApiFlag.mOriginForUserActionInSystemUi, "test", Process.SYSTEM_UID);
@@ -3150,7 +3507,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- public void testUpdateConsolidatedPolicy_defaultRulesOnly() {
+ @DisableFlags(Flags.FLAG_MODES_API)
+ public void testUpdateConsolidatedPolicy_preModesApiDefaultRulesOnly_takesGlobalDefault() {
setupZenConfig();
// When there's one automatic rule active and it doesn't specify a policy, test that the
@@ -3183,12 +3541,39 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- public void testUpdateConsolidatedPolicy_customPolicyOnly() {
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void testUpdateConsolidatedPolicy_modesApiDefaultRulesOnly_takesDeviceDefault() {
+ setupZenConfig();
+
+ // When there's one automatic rule active and it doesn't specify a policy, test that the
+ // resulting consolidated policy is one that matches the default *device* settings.
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ null,
+ new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ null, // null policy
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule,
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "test", Process.SYSTEM_UID);
+
+ // enable the rule
+ mZenModeHelper.setAutomaticZenRuleState(id,
+ new Condition(zenRule.getConditionId(), "", STATE_TRUE),
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
+
+ // inspect the consolidated policy, which should match the device default settings.
+ assertThat(ZenAdapters.notificationPolicyToZenPolicy(mZenModeHelper.mConsolidatedPolicy))
+ .isEqualTo(mZenModeHelper.getDefaultZenPolicy());
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MODES_API)
+ public void testUpdateConsolidatedPolicy_preModesApiCustomPolicyOnly_fillInWithGlobal() {
setupZenConfig();
// when there's only one automatic rule active and it has a custom policy, make sure that's
- // what the consolidated policy reflects whether or not it's stricter than what the default
- // would specify.
+ // what the consolidated policy reflects whether or not it's stricter than what the global
+ // config would specify.
ZenPolicy customPolicy = new ZenPolicy.Builder()
.allowAlarms(true) // more lenient than default
.allowMedia(true) // more lenient than default
@@ -3227,7 +3612,51 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- public void testUpdateConsolidatedPolicy_defaultAndCustomActive() {
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void testUpdateConsolidatedPolicy_modesApiCustomPolicyOnly_fillInWithDeviceDefault() {
+ setupZenConfig();
+
+ // when there's only one automatic rule active and it has a custom policy, make sure that's
+ // what the consolidated policy reflects whether or not it's stricter than what the default
+ // would specify.
+ ZenPolicy customPolicy = new ZenPolicy.Builder()
+ .allowSystem(true) // more lenient than default
+ .allowRepeatCallers(false) // more restrictive than default
+ .allowCalls(ZenPolicy.PEOPLE_TYPE_NONE) // more restrictive than default
+ .showFullScreenIntent(true) // more lenient
+ .showBadges(false) // more restrictive
+ .build();
+
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ null,
+ new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ customPolicy,
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule,
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "test", Process.SYSTEM_UID);
+
+ // enable the rule; this will update the consolidated policy
+ mZenModeHelper.setAutomaticZenRuleState(id,
+ new Condition(zenRule.getConditionId(), "", STATE_TRUE),
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
+
+ // since this is the only active rule, the consolidated policy should match the custom
+ // policy for every field specified, and take default values for unspecified things
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowAlarms()).isTrue(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowMedia()).isTrue(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowSystem()).isTrue(); // custom
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isFalse(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowCalls()).isFalse(); // custom
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowMessages()).isTrue(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowRepeatCallers()).isFalse(); // custom
+ assertThat(mZenModeHelper.mConsolidatedPolicy.showBadges()).isFalse(); // custom
+ assertThat(mZenModeHelper.mConsolidatedPolicy.showFullScreenIntents()).isTrue(); // custom
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MODES_API)
+ public void testUpdateConsolidatedPolicy_preModesApiDefaultAndCustomActive_mergesWithGlobal() {
setupZenConfig();
// when there are two rules active, one inheriting the default policy and one setting its
@@ -3287,6 +3716,68 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void testUpdateConsolidatedPolicy_modesApiDefaultAndCustomActive_mergesWithDefault() {
+ setupZenConfig();
+
+ // when there are two rules active, one inheriting the default policy and one setting its
+ // own custom policy, they should be merged to form the most restrictive combination.
+
+ // rule 1: no custom policy
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ null,
+ new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ null,
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule,
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "test", Process.SYSTEM_UID);
+
+ // enable rule 1
+ mZenModeHelper.setAutomaticZenRuleState(id,
+ new Condition(zenRule.getConditionId(), "", STATE_TRUE),
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
+
+ // custom policy for rule 2
+ ZenPolicy customPolicy = new ZenPolicy.Builder()
+ .allowAlarms(false) // more restrictive than default
+ .allowSystem(true) // more lenient than default
+ .allowRepeatCallers(false) // more restrictive than default
+ .allowCalls(ZenPolicy.PEOPLE_TYPE_NONE) // more restrictive than default
+ .showBadges(false) // more restrictive
+ .showPeeking(true) // more lenient
+ .build();
+
+ AutomaticZenRule zenRule2 = new AutomaticZenRule("name2",
+ null,
+ new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ customPolicy,
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id2 = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule2,
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "test", Process.SYSTEM_UID);
+
+ // enable rule 2; this will update the consolidated policy
+ mZenModeHelper.setAutomaticZenRuleState(id2,
+ new Condition(zenRule2.getConditionId(), "", STATE_TRUE),
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
+
+ // now both rules should be on, and the consolidated policy should reflect the most
+ // restrictive option of each of the two
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowAlarms()).isFalse(); // custom stricter
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowMedia()).isTrue(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowSystem()).isFalse(); // default stricter
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isFalse(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowCalls()).isFalse(); // custom stricter
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowMessages()).isTrue(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowConversations()).isTrue(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowRepeatCallers())
+ .isFalse(); // custom stricter
+ assertThat(mZenModeHelper.mConsolidatedPolicy.showBadges()).isFalse(); // custom stricter
+ assertThat(mZenModeHelper.mConsolidatedPolicy.showPeeking()).isFalse(); // default stricter
+ }
+
+ @Test
public void testUpdateConsolidatedPolicy_allowChannels() {
mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
setupZenConfig();
@@ -3350,7 +3841,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
null,
new ComponentName(CUSTOM_PKG_NAME, "cls"),
Uri.parse("priority"),
- new ZenPolicy.Builder().allowMedia(true).build(),
+ new ZenPolicy.Builder()
+ .allowMedia(true)
+ .allowSystem(true)
+ .build(),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String rule1Id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
zenRuleWithPriority, UPDATE_ORIGIN_APP, "test", CUSTOM_PKG_UID);
@@ -3372,10 +3866,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
UPDATE_ORIGIN_APP, CUSTOM_PKG_UID);
// Consolidated Policy should be default + rule1.
- assertThat(mZenModeHelper.mConsolidatedPolicy.allowAlarms()).isFalse(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowAlarms()).isTrue(); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowMedia()).isTrue(); // priority rule
- assertThat(mZenModeHelper.mConsolidatedPolicy.allowSystem()).isFalse(); // default
- assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isTrue(); // default
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowSystem()).isTrue(); // priority rule
+ assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isFalse(); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowCalls()).isTrue(); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowMessages()).isTrue(); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowConversations()).isTrue(); // default
@@ -3386,7 +3880,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
public void zenRuleToAutomaticZenRule_allFields() {
mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(
- new String[] {OWNER.getPackageName()});
+ new String[]{OWNER.getPackageName()});
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.configurationActivity = CONFIG_ACTIVITY;
@@ -3430,7 +3924,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
public void automaticZenRuleToZenRule_allFields() {
mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(
- new String[] {OWNER.getPackageName()});
+ new String[]{OWNER.getPackageName()});
AutomaticZenRule azr = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
.setEnabled(true)
@@ -3456,7 +3950,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(CONDITION_ID, storedRule.conditionId);
assertEquals(INTERRUPTION_FILTER_ZR, storedRule.zenMode);
assertEquals(ENABLED, storedRule.enabled);
- assertEquals(POLICY, storedRule.zenPolicy);
+ assertEquals(mZenModeHelper.getDefaultZenPolicy().overwrittenWith(POLICY),
+ storedRule.zenPolicy);
assertEquals(CONFIG_ACTIVITY, storedRule.configurationActivity);
assertEquals(TYPE, storedRule.type);
assertEquals(ALLOW_MANUAL, storedRule.allowManualInvocation);
@@ -3539,12 +4034,12 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// Modifies the zen policy and device effects
ZenPolicy policy = new ZenPolicy.Builder(rule.getZenPolicy())
- .allowPriorityChannels(true)
+ .allowPriorityChannels(false)
.build();
ZenDeviceEffects deviceEffects =
new ZenDeviceEffects.Builder(rule.getDeviceEffects())
- .setShouldDisplayGrayscale(true)
- .build();
+ .setShouldDisplayGrayscale(true)
+ .build();
AutomaticZenRule azrUpdate = new AutomaticZenRule.Builder(rule)
.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
.setZenPolicy(policy)
@@ -3558,7 +4053,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// UPDATE_ORIGIN_USER should change the bitmask and change the values.
assertThat(rule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_PRIORITY);
- assertThat(rule.getZenPolicy().getPriorityChannels()).isEqualTo(ZenPolicy.STATE_ALLOW);
+ assertThat(rule.getZenPolicy().getPriorityChannels()).isEqualTo(ZenPolicy.STATE_DISALLOW);
+
assertThat(rule.getDeviceEffects().shouldDisplayGrayscale()).isTrue();
ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
@@ -3748,9 +4244,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
@EnableFlags(Flags.FLAG_MODES_API)
public void updateAutomaticZenRule_nullPolicyUpdate() {
- // Adds a starting rule with empty zen policies and device effects
+ // Adds a starting rule with set zen policy and empty device effects
AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
- .setZenPolicy(new ZenPolicy.Builder().build())
+ .setZenPolicy(POLICY)
.build();
// Adds the rule using the app, to avoid having any user modified bits set.
String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
@@ -3768,8 +4264,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
Process.SYSTEM_UID);
rule = mZenModeHelper.getAutomaticZenRule(ruleId);
- // When AZR's ZenPolicy is null, we expect the updated rule's policy to be null.
- assertThat(rule.getZenPolicy()).isNull();
+ // When AZR's ZenPolicy is null, we expect the updated rule's policy to be unchanged
+ // (equivalent to the provided policy, with additional fields filled in with defaults).
+ assertThat(rule.getZenPolicy()).isEqualTo(
+ mZenModeHelper.getDefaultZenPolicy().overwrittenWith(POLICY));
}
@Test
@@ -3825,13 +4323,13 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertThat(storedRule.canBeUpdatedByApp()).isFalse();
assertThat(storedRule.zenPolicyUserModifiedFields).isEqualTo(
ZenPolicy.FIELD_ALLOW_CHANNELS
- | ZenPolicy.FIELD_PRIORITY_CATEGORY_REMINDERS
- | ZenPolicy.FIELD_PRIORITY_CATEGORY_EVENTS
- | ZenPolicy.FIELD_PRIORITY_CATEGORY_SYSTEM
- | ZenPolicy.FIELD_VISUAL_EFFECT_FULL_SCREEN_INTENT
- | ZenPolicy.FIELD_VISUAL_EFFECT_LIGHTS
- | ZenPolicy.FIELD_VISUAL_EFFECT_PEEK
- | ZenPolicy.FIELD_VISUAL_EFFECT_AMBIENT
+ | ZenPolicy.FIELD_PRIORITY_CATEGORY_REMINDERS
+ | ZenPolicy.FIELD_PRIORITY_CATEGORY_EVENTS
+ | ZenPolicy.FIELD_PRIORITY_CATEGORY_SYSTEM
+ | ZenPolicy.FIELD_VISUAL_EFFECT_FULL_SCREEN_INTENT
+ | ZenPolicy.FIELD_VISUAL_EFFECT_LIGHTS
+ | ZenPolicy.FIELD_VISUAL_EFFECT_PEEK
+ | ZenPolicy.FIELD_VISUAL_EFFECT_AMBIENT
);
}
@@ -3994,6 +4492,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
final int[] actualStatus = new int[2];
ZenModeHelper.Callback callback = new ZenModeHelper.Callback() {
int i = 0;
+
@Override
void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) {
if (Objects.equals(createdId, id)) {
@@ -4034,6 +4533,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
final int[] actualStatus = new int[2];
ZenModeHelper.Callback callback = new ZenModeHelper.Callback() {
int i = 0;
+
@Override
void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) {
if (Objects.equals(createdId, id)) {
@@ -4180,6 +4680,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
.build()),
eq(UPDATE_ORIGIN_APP));
}
+
@Test
public void testDeviceEffects_noChangeToConsolidatedEffects_notApplied() {
mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
@@ -4585,7 +5086,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
.comparingElementsUsing(IGNORE_METADATA)
.containsExactly(
expectedImplicitRule(CUSTOM_PKG_NAME, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
- null, true));
+ mZenModeHelper.mConfig.toZenPolicy(), // copy of global config
+ true));
}
@Test
@@ -4604,7 +5106,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertThat(mZenModeHelper.mConfig.automaticRules.values())
.comparingElementsUsing(IGNORE_METADATA)
.containsExactly(
- expectedImplicitRule(CUSTOM_PKG_NAME, ZEN_MODE_ALARMS, null, true));
+ expectedImplicitRule(CUSTOM_PKG_NAME, ZEN_MODE_ALARMS,
+ mZenModeHelper.mConfig.toZenPolicy(), // copy of global config
+ true));
}
@Test
@@ -4798,6 +5302,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(pkg, CUSTOM_PKG_UID, originalPolicy);
String ruleId = getOnlyElement(mZenModeHelper.mConfig.automaticRules.keySet());
+ // Store this for checking later.
+ ZenPolicy originalEffectiveZenPolicy = new ZenPolicy.Builder(
+ mZenModeHelper.mConfig.toZenPolicy()).allowMedia(true).build();
+
// From user, update that rule's policy.
AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId);
ZenPolicy userUpdateZenPolicy = new ZenPolicy.Builder().disallowAllSounds()
@@ -4817,7 +5325,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
.comparingElementsUsing(IGNORE_METADATA)
.containsExactly(
expectedImplicitRule(pkg, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
- userUpdateZenPolicy,
+ // the final policy for the rule should contain the user's update
+ // overlaid on top of the original existing policy.
+ originalEffectiveZenPolicy.overwrittenWith(userUpdateZenPolicy),
/* conditionActive= */ null));
}
@@ -4832,6 +5342,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(pkg, CUSTOM_PKG_UID, originalPolicy);
String ruleId = getOnlyElement(mZenModeHelper.mConfig.automaticRules.keySet());
+ // Store this for checking later.
+ ZenPolicy originalEffectiveZenPolicy = new ZenPolicy.Builder(
+ mZenModeHelper.mConfig.toZenPolicy()).allowMedia(true).build();
+
// From user, update something in that rule, but not the ZenPolicy.
AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId);
AutomaticZenRule userUpdateRule = new AutomaticZenRule.Builder(rule)
@@ -4851,7 +5365,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
.allowPriorityChannels(true)
.build();
assertThat(getOnlyElement(mZenModeHelper.mConfig.automaticRules.values()).zenPolicy)
- .isEqualTo(appsSecondZenPolicy);
+ .isEqualTo(originalEffectiveZenPolicy.overwrittenWith(appsSecondZenPolicy));
}
@Test
@@ -4883,13 +5397,17 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- public void getNotificationPolicyFromImplicitZenRule_ruleWithoutPolicy_returnsGlobalPolicy() {
+ public void getNotificationPolicyFromImplicitZenRule_ruleWithoutPolicy_copiesGlobalPolicy() {
mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.mConfig.allowCalls = true;
+ mZenModeHelper.mConfig.allowConversations = false;
+ // Implicit rule will get the global policy at the time of rule creation.
mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
ZEN_MODE_ALARMS);
- mZenModeHelper.mConfig.allowCalls = true;
- mZenModeHelper.mConfig.allowConversations = false;
+
+ // If the policy then changes afterwards, we should keep the snapshotted version.
+ mZenModeHelper.mConfig.allowCalls = false;
Policy readPolicy = mZenModeHelper.getNotificationPolicyFromImplicitZenRule(
CUSTOM_PKG_NAME);
@@ -4930,7 +5448,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
p.recycle();
}
},
- "Ignoring timestamp and userModifiedFields");
+ "Ignoring timestamp and userModifiedFields");
private ZenRule expectedImplicitRule(String ownerPkg, int zenMode, ZenPolicy policy,
@Nullable Boolean conditionActive) {
@@ -4940,7 +5458,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
if (conditionActive != null) {
rule.condition = conditionActive
? new Condition(rule.conditionId,
- mContext.getString(R.string.zen_mode_implicit_activated), STATE_TRUE)
+ mContext.getString(R.string.zen_mode_implicit_activated), STATE_TRUE)
: new Condition(rule.conditionId,
mContext.getString(R.string.zen_mode_implicit_deactivated),
STATE_FALSE);
@@ -5008,8 +5526,35 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(STATE_ALLOW, dndProto.getNotificationList().getNumber());
}
+ private void checkDndProtoMatchesDefaultZenConfig(DNDPolicyProto dndProto) {
+ if (!Flags.modesApi()) {
+ checkDndProtoMatchesSetupZenConfig(dndProto);
+ return;
+ }
+
+ // When modes_api flag is on, the default zen config is the device defaults.
+ assertThat(dndProto.getAlarms().getNumber()).isEqualTo(STATE_ALLOW);
+ assertThat(dndProto.getMedia().getNumber()).isEqualTo(STATE_ALLOW);
+ assertThat(dndProto.getSystem().getNumber()).isEqualTo(STATE_DISALLOW);
+ assertThat(dndProto.getReminders().getNumber()).isEqualTo(STATE_DISALLOW);
+ assertThat(dndProto.getCalls().getNumber()).isEqualTo(STATE_ALLOW);
+ assertThat(dndProto.getAllowCallsFrom().getNumber()).isEqualTo(PEOPLE_STARRED);
+ assertThat(dndProto.getMessages().getNumber()).isEqualTo(STATE_ALLOW);
+ assertThat(dndProto.getAllowMessagesFrom().getNumber()).isEqualTo(PEOPLE_STARRED);
+ assertThat(dndProto.getEvents().getNumber()).isEqualTo(STATE_DISALLOW);
+ assertThat(dndProto.getRepeatCallers().getNumber()).isEqualTo(STATE_ALLOW);
+ assertThat(dndProto.getFullscreen().getNumber()).isEqualTo(STATE_DISALLOW);
+ assertThat(dndProto.getLights().getNumber()).isEqualTo(STATE_DISALLOW);
+ assertThat(dndProto.getPeek().getNumber()).isEqualTo(STATE_DISALLOW);
+ assertThat(dndProto.getStatusBar().getNumber()).isEqualTo(STATE_ALLOW);
+ assertThat(dndProto.getBadge().getNumber()).isEqualTo(STATE_ALLOW);
+ assertThat(dndProto.getAmbient().getNumber()).isEqualTo(STATE_DISALLOW);
+ assertThat(dndProto.getNotificationList().getNumber()).isEqualTo(STATE_ALLOW);
+ }
+
private static void withoutWtfCrash(Runnable test) {
- Log.TerribleFailureHandler oldHandler = Log.setWtfHandler((tag, what, system) -> {});
+ Log.TerribleFailureHandler oldHandler = Log.setWtfHandler((tag, what, system) -> {
+ });
try {
test.run();
} finally {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
index 4ed55df7775c..57e11328d5e1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
@@ -269,6 +269,78 @@ public class ZenPolicyTest extends UiServiceTestCase {
}
@Test
+ public void testZenPolicyOverwrite_allUnsetPolicies() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
+
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+ ZenPolicy unset = builder.build();
+
+ builder.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+ builder.allowMedia(false);
+ builder.allowEvents(true);
+ builder.showFullScreenIntent(false);
+ builder.showInNotificationList(false);
+ ZenPolicy set = builder.build();
+
+ ZenPolicy overwritten = set.overwrittenWith(unset);
+ assertThat(overwritten).isEqualTo(set);
+
+ // should actually work the other way too.
+ ZenPolicy overwrittenWithSet = unset.overwrittenWith(set);
+ assertThat(overwrittenWithSet).isEqualTo(set);
+ }
+
+ @Test
+ public void testZenPolicyOverwrite_someOverlappingFields_takeNewPolicy() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
+
+ ZenPolicy p1 = new ZenPolicy.Builder()
+ .allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS)
+ .allowMessages(ZenPolicy.PEOPLE_TYPE_STARRED)
+ .allowMedia(false)
+ .showBadges(true)
+ .build();
+
+ ZenPolicy p2 = new ZenPolicy.Builder()
+ .allowRepeatCallers(false)
+ .allowConversations(ZenPolicy.CONVERSATION_SENDERS_IMPORTANT)
+ .allowMessages(ZenPolicy.PEOPLE_TYPE_NONE)
+ .showBadges(false)
+ .showPeeking(true)
+ .build();
+
+ // when p1 is overwritten with p2, all values from p2 win regardless of strictness, and
+ // remaining fields take values from p1.
+ ZenPolicy p1OverwrittenWithP2 = p1.overwrittenWith(p2);
+ assertThat(p1OverwrittenWithP2.getPriorityCallSenders())
+ .isEqualTo(ZenPolicy.PEOPLE_TYPE_CONTACTS); // from p1
+ assertThat(p1OverwrittenWithP2.getPriorityMessageSenders())
+ .isEqualTo(ZenPolicy.PEOPLE_TYPE_NONE); // from p2
+ assertThat(p1OverwrittenWithP2.getPriorityCategoryRepeatCallers())
+ .isEqualTo(ZenPolicy.STATE_DISALLOW); // from p2
+ assertThat(p1OverwrittenWithP2.getPriorityCategoryMedia())
+ .isEqualTo(ZenPolicy.STATE_DISALLOW); // from p1
+ assertThat(p1OverwrittenWithP2.getVisualEffectBadge())
+ .isEqualTo(ZenPolicy.STATE_DISALLOW); // from p2
+ assertThat(p1OverwrittenWithP2.getVisualEffectPeek())
+ .isEqualTo(ZenPolicy.STATE_ALLOW); // from p2
+
+ ZenPolicy p2OverwrittenWithP1 = p2.overwrittenWith(p1);
+ assertThat(p2OverwrittenWithP1.getPriorityCallSenders())
+ .isEqualTo(ZenPolicy.PEOPLE_TYPE_CONTACTS); // from p1
+ assertThat(p2OverwrittenWithP1.getPriorityMessageSenders())
+ .isEqualTo(ZenPolicy.PEOPLE_TYPE_STARRED); // from p1
+ assertThat(p2OverwrittenWithP1.getPriorityCategoryRepeatCallers())
+ .isEqualTo(ZenPolicy.STATE_DISALLOW); // from p2
+ assertThat(p2OverwrittenWithP1.getPriorityCategoryMedia())
+ .isEqualTo(ZenPolicy.STATE_DISALLOW); // from p1
+ assertThat(p2OverwrittenWithP1.getVisualEffectBadge())
+ .isEqualTo(ZenPolicy.STATE_ALLOW); // from p1
+ assertThat(p2OverwrittenWithP1.getVisualEffectPeek())
+ .isEqualTo(ZenPolicy.STATE_ALLOW); // from p2
+ }
+
+ @Test
public void testZenPolicyMessagesInvalid() {
ZenPolicy.Builder builder = new ZenPolicy.Builder();