diff options
| author | 2024-08-05 17:10:18 -0400 | |
|---|---|---|
| committer | 2024-08-06 14:46:35 -0400 | |
| commit | 0bd31d305a94847007f3b8ea309750d44632b71c (patch) | |
| tree | 4f0bfc4a1635c391d30c9c25a1ffe4fab4dcddb9 | |
| parent | dbb483a3a40b998a7672aaefedd851be617e59be (diff) | |
Fix manual rule on upgrade to modes_ui if DND was on
If the manual rule is present in the XML, we don't do any of the stuff to make the manual rule set up like a proper rule, with a non-null zenPolicy, etc, but that's incorrect if the manual rule only existed prior to
Also does not restore the manual rule condition when restoring from a backup, which matches previous behavior.
Fixes: 357161279
Test: ZenModeHelperTest, ZenModeConfigTest, manual by turning modes_ui off and then on both with DND on and DND on for a duration
Flag: android.app.modes_ui
Change-Id: I12e9d1713313aa0a3b626e79c66525b3db21056f
4 files changed, 137 insertions, 13 deletions
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 5e15e0160be4..224379b4fd98 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -25,6 +25,8 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; +import static android.service.notification.Condition.STATE_TRUE; +import static android.service.notification.SystemZenRules.PACKAGE_ANDROID; import static android.service.notification.ZenAdapters.peopleTypeToPrioritySenders; import static android.service.notification.ZenAdapters.prioritySendersToPeopleType; import static android.service.notification.ZenAdapters.zenPolicyConversationSendersToNotificationPolicy; @@ -454,7 +456,7 @@ public class ZenModeConfig implements Parcelable { newRule.conditionId = Uri.EMPTY; newRule.allowManualInvocation = true; newRule.zenPolicy = getDefaultZenPolicy(); - newRule.pkg = "android"; + newRule.pkg = PACKAGE_ANDROID; manualRule = newRule; } } @@ -957,15 +959,9 @@ public class ZenModeConfig implements Parcelable { rt.user = safeInt(parser, ZEN_ATT_USER, rt.user); boolean readSuppressedEffects = false; boolean readManualRule = false; + boolean readManualRuleWithoutPolicy = false; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { tag = parser.getName(); - if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) { - if (Flags.modesUi() && !readManualRule) { - // migrate from fields on config into manual rule - rt.manualRule.zenPolicy = rt.toZenPolicy(); - } - return rt; - } if (type == XmlPullParser.START_TAG) { if (ALLOW_TAG.equals(tag)) { rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, @@ -1034,9 +1030,17 @@ public class ZenModeConfig implements Parcelable { rt.suppressedVisualEffects = safeInt(parser, DISALLOW_ATT_VISUAL_EFFECTS, DEFAULT_SUPPRESSED_VISUAL_EFFECTS); } else if (MANUAL_TAG.equals(tag)) { - rt.manualRule = readRuleXml(parser); - if (rt.manualRule != null) { + ZenRule manualRule = readRuleXml(parser); + if (manualRule != null) { + rt.manualRule = manualRule; + + // Manual rule may be present prior to modes_ui if it were on, but in that + // case it would not have a set policy, so make note of the need to set + // it up later. readManualRule = true; + if (rt.manualRule.zenPolicy == null) { + readManualRuleWithoutPolicy = true; + } } } else if (AUTOMATIC_TAG.equals(tag) || (Flags.modesApi() && AUTOMATIC_DELETED_TAG.equals(tag))) { @@ -1058,6 +1062,23 @@ public class ZenModeConfig implements Parcelable { STATE_ATT_CHANNELS_BYPASSING_DND, DEFAULT_CHANNELS_BYPASSING_DND); } } + if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) { + if (Flags.modesUi() && (!readManualRule || readManualRuleWithoutPolicy)) { + // migrate from fields on config into manual rule + rt.manualRule.zenPolicy = rt.toZenPolicy(); + if (readManualRuleWithoutPolicy) { + // indicates that the xml represents a pre-modes_ui XML with an enabled + // manual rule; set rule active, and fill in other fields as would be done + // in ensureManualZenRule() and setManualZenMode(). + rt.manualRule.pkg = PACKAGE_ANDROID; + rt.manualRule.type = AutomaticZenRule.TYPE_OTHER; + rt.manualRule.condition = new Condition( + rt.manualRule.conditionId != null ? rt.manualRule.conditionId + : Uri.EMPTY, "", STATE_TRUE); + } + } + return rt; + } } throw new IllegalStateException("Failed to reach END_DOCUMENT"); } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index b164a52ff5d7..8c280edf03c0 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -1676,7 +1676,11 @@ public class ZenModeHelper { if (config != null) { if (forRestore) { config.user = userId; - if (!Flags.modesUi()) { + if (Flags.modesUi()) { + if (config.manualRule != null) { + config.manualRule.condition = null; // don't restore transient state + } + } else { config.manualRule = null; // don't restore the manual rule } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java index b955a795e94a..60c4ac777906 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java @@ -31,6 +31,8 @@ import static android.service.notification.Condition.SOURCE_USER_ACTION; import static android.service.notification.Condition.STATE_FALSE; import static android.service.notification.Condition.STATE_TRUE; import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON; +import static android.service.notification.ZenModeConfig.XML_VERSION_MODES_API; +import static android.service.notification.ZenModeConfig.ZEN_TAG; import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_IMPORTANT; import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_NONE; import static android.service.notification.ZenPolicy.PEOPLE_TYPE_ANYONE; @@ -283,8 +285,8 @@ public class ZenModeConfigTest extends UiServiceTestCase { // the default value from the zen mode config. Policy policy = config.toNotificationPolicy(zenPolicy); assertEquals(Flags.modesUi() - ? config.manualRule.zenPolicy.getPriorityChannelsAllowed() == STATE_ALLOW - : config.isAllowPriorityChannels(), + ? config.manualRule.zenPolicy.getPriorityChannelsAllowed() == STATE_ALLOW + : config.isAllowPriorityChannels(), policy.allowPriorityChannels()); } @@ -991,6 +993,58 @@ public class ZenModeConfigTest extends UiServiceTestCase { } @Test + @EnableFlags(Flags.FLAG_MODES_UI) + public void testConfigXml_manualRule_upgradeWhenExisting() throws Exception { + // prior to modes_ui, it's possible to have a non-null manual rule that doesn't have much + // data on it because it's meant to indicate that the manual rule is on by merely existing. + ZenModeConfig config = new ZenModeConfig(); + config.manualRule = new ZenModeConfig.ZenRule(); + config.manualRule.enabled = true; + config.manualRule.pkg = "android"; + config.manualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + config.manualRule.conditionId = ZenModeConfig.toTimeCondition(mContext, 200, mUserId).id; + config.manualRule.enabler = "test"; + + // write out entire config xml + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + writeConfigXml(config, XML_VERSION_MODES_API, /* forBackup= */ false, baos); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ZenModeConfig fromXml = readConfigXml(bais); + + // The result should have a manual rule; it should have a non-null ZenPolicy and a condition + // whose state is true. The conditionId and enabler data should also be preserved. + assertThat(fromXml.manualRule).isNotNull(); + assertThat(fromXml.manualRule.zenPolicy).isNotNull(); + assertThat(fromXml.manualRule.condition).isNotNull(); + assertThat(fromXml.manualRule.condition.state).isEqualTo(STATE_TRUE); + assertThat(fromXml.manualRule.conditionId).isEqualTo(config.manualRule.conditionId); + assertThat(fromXml.manualRule.enabler).isEqualTo("test"); + assertThat(fromXml.isManualActive()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_MODES_UI) + public void testConfigXml_manualRule_doesNotTurnOnIfNotUpgrade() throws Exception { + // confirm that if the manual rule is already properly set up for modes_ui, it does not get + // turned on (set to condition with STATE_TRUE) when reading xml. + + // getMutedAllConfig sets up the manual rule with a policy muting everything + ZenModeConfig config = getMutedAllConfig(); + config.manualRule.condition = new Condition(Uri.EMPTY, "", STATE_FALSE, SOURCE_USER_ACTION); + assertThat(config.isManualActive()).isFalse(); + + // write out entire config xml + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + writeConfigXml(config, XML_VERSION_MODES_API, /* forBackup= */ false, baos); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ZenModeConfig fromXml = readConfigXml(bais); + + // The result should have a manual rule; it should not be changed from the previous rule. + assertThat(fromXml.manualRule).isEqualTo(config.manualRule); + assertThat(fromXml.isManualActive()).isFalse(); + } + + @Test public void testGetDescription_off() { ZenModeConfig config = new ZenModeConfig(); if (!modesUi()) { @@ -1238,4 +1292,25 @@ public class ZenModeConfigTest extends UiServiceTestCase { parser.nextTag(); return ZenModeConfig.readZenPolicyXml(parser); } + + private void writeConfigXml(ZenModeConfig config, Integer version, boolean forBackup, + ByteArrayOutputStream os) throws IOException { + String tag = ZEN_TAG; + + TypedXmlSerializer out = Xml.newFastSerializer(); + out.setOutput(new BufferedOutputStream(os), "utf-8"); + out.startDocument(null, true); + out.startTag(null, tag); + config.writeXml(out, version, forBackup); + out.endTag(null, tag); + out.endDocument(); + } + + private ZenModeConfig readConfigXml(ByteArrayInputStream is) + throws XmlPullParserException, IOException { + TypedXmlPullParser parser = Xml.newFastPullParser(); + parser.setInput(new BufferedInputStream(is), null); + parser.nextTag(); + return ZenModeConfig.readXml(parser); + } } 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 63cf1068f51e..776a840466c8 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -1495,6 +1495,30 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test + public void testReadXmlRestore_doesNotEnableManualRule() throws Exception { + setupZenConfig(); + + // Turn on manual zen mode + mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, + ORIGIN_USER_IN_SYSTEMUI, "", "someCaller", SYSTEM_UID); + ZenModeConfig original = mZenModeHelper.mConfig.copy(); + assertThat(original.isManualActive()).isTrue(); + + ByteArrayOutputStream baos = writeXmlAndPurge(null); + TypedXmlPullParser parser = getParserForByteStream(baos); + mZenModeHelper.readXml(parser, true, UserHandle.USER_ALL); + + ZenModeConfig result = mZenModeHelper.getConfig(); + assertThat(result.isManualActive()).isFalse(); + + // confirm that we do still keep policy information, modes_ui only; prior to modes_ui the + // entire rule is intentionally cleared + if (Flags.modesUi()) { + assertThat(result.manualRule.zenPolicy).isNotNull(); + } + } + + @Test public void testWriteXmlWithZenPolicy() throws Exception { final String ruleId = "customRule"; setupZenConfig(); |