diff options
4 files changed, 145 insertions, 9 deletions
diff --git a/services/core/java/com/android/server/notification/ZenModeEventLogger.java b/services/core/java/com/android/server/notification/ZenModeEventLogger.java index df570a02eba5..0145577fb945 100644 --- a/services/core/java/com/android/server/notification/ZenModeEventLogger.java +++ b/services/core/java/com/android/server/notification/ZenModeEventLogger.java @@ -23,6 +23,7 @@ import static android.service.notification.NotificationServiceProto.RULE_TYPE_MA import static android.service.notification.NotificationServiceProto.RULE_TYPE_UNKNOWN; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Flags; import android.app.NotificationManager; import android.content.pm.PackageManager; @@ -256,13 +257,21 @@ class ZenModeEventLogger { return true; } + if (Flags.modesApi() && hasActiveRuleCountDiff()) { + // Rules with INTERRUPTION_FILTER_ALL were always possible but before MODES_API + // they were completely useless; now they can apply effects, so we want to log + // when they become active/inactive, even though DND itself (as in "notification + // blocking") is off. + return true; + } + // If zen mode didn't change, did the policy or number of active rules change? We only // care about changes that take effect while zen mode is on, so make sure the current // zen mode is not "OFF" if (mNewZenMode == ZEN_MODE_OFF) { return false; } - return hasPolicyDiff() || hasRuleCountDiff(); + return hasPolicyDiff() || hasActiveRuleCountDiff(); } // Does the difference in zen mode go from off to on or vice versa? @@ -294,6 +303,16 @@ class ZenModeEventLogger { } } + if (Flags.modesApi() && mNewZenMode == ZEN_MODE_OFF) { + // If the mode is OFF -> OFF then there cannot be any *effective* change to policy. + // (Note that, in theory, a policy diff is impossible since we don't merge the + // policies of INTERRUPTION_FILTER_ALL rules; this is a "just in case" check). + if (hasPolicyDiff() || hasChannelsBypassingDiff()) { + Log.wtf(TAG, "Detected policy diff even though DND is OFF and not toggled"); + } + return ZenStateChangedEvent.DND_ACTIVE_RULES_CHANGED; + } + // zen mode didn't change; we must be here because of a policy change or rule change if (hasPolicyDiff() || hasChannelsBypassingDiff()) { return ZenStateChangedEvent.DND_POLICY_CHANGED; @@ -345,7 +364,7 @@ class ZenModeEventLogger { * Returns whether the previous config and new config have a different number of active * automatic or manual rules. */ - private boolean hasRuleCountDiff() { + private boolean hasActiveRuleCountDiff() { return numActiveRulesInConfig(mPrevConfig) != numActiveRulesInConfig(mNewConfig); } @@ -381,9 +400,11 @@ class ZenModeEventLogger { // Determine the number of (automatic & manual) rules active after the change takes place. int getNumRulesActive() { - // If the zen mode has turned off, that means nothing can be active. - if (mNewZenMode == ZEN_MODE_OFF) { - return 0; + if (!Flags.modesApi()) { + // If the zen mode has turned off, that means nothing can be active. + if (mNewZenMode == ZEN_MODE_OFF) { + return 0; + } } return numActiveRulesInConfig(mNewConfig); } @@ -478,8 +499,19 @@ class ZenModeEventLogger { /** * Convert the new policy to a DNDPolicyProto format for output in logs. + * + * <p>If {@code mNewZenMode} is {@code ZEN_MODE_OFF} (which can mean either no rules + * active, or only rules with {@code INTERRUPTION_FILTER_ALL} active) then this returns + * {@code null} (which will be mapped to a missing submessage in the proto). Although this + * is not the value of {@code NotificationManager#getConsolidatedNotificationPolicy()}, it + * makes sense for logging since that policy is not actually influencing anything. */ + @Nullable byte[] getDNDPolicyProto() { + if (Flags.modesApi() && mNewZenMode == ZEN_MODE_OFF) { + return null; + } + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); ProtoOutputStream proto = new ProtoOutputStream(bytes); diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 0a46901a93d1..b7a203814c94 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -1490,7 +1490,12 @@ public class ZenModeHelper { for (ZenRule automaticRule : mConfig.automaticRules.values()) { if (automaticRule.isAutomaticActive()) { - applyCustomPolicy(policy, automaticRule); + // Active rules with INTERRUPTION_FILTER_ALL are not included in consolidated + // 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); + } if (Flags.modesApi()) { deviceEffectsBuilder.add(automaticRule.zenDeviceEffects); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java index 1fcee0658afc..5b35e345e46b 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java @@ -118,10 +118,13 @@ public class ZenModeEventLoggerFake extends ZenModeEventLogger { public DNDPolicyProto getPolicyProto(int i) throws IllegalArgumentException { checkInRange(i); byte[] policyBytes = mChanges.get(i).getDNDPolicyProto(); + if (policyBytes == null) { + return null; + } try { return DNDPolicyProto.parseFrom(policyBytes); } catch (InvalidProtocolBufferException e) { - return null; // couldn't turn it into proto + throw new RuntimeException("Couldn't parse DNDPolicyProto!", e); } } 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 44f0894f76d7..25c0cd9fae25 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -2429,7 +2429,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertEquals(0, mZenModeEventLogger.getNumRulesActive(1)); assertFalse(mZenModeEventLogger.getIsUserAction(1)); assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(1)); - checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1)); + if (Flags.modesApi()) { + assertThat(mZenModeEventLogger.getPolicyProto(1)).isNull(); + } else { + checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1)); + } } @Test @@ -2511,7 +2515,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertEquals(0, mZenModeEventLogger.getNumRulesActive(1)); assertTrue(mZenModeEventLogger.getIsUserAction(1)); assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(1)); - checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1)); + if (Flags.modesApi()) { + assertThat(mZenModeEventLogger.getPolicyProto(1)).isNull(); + } else { + checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1)); + } // When the system rule is enabled, this counts as an automatic action that comes from the // system and turns on DND @@ -3016,6 +3024,48 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test + @EnableFlags(Flags.FLAG_MODES_API) + public void testZenModeEventLog_ruleWithInterruptionFilterAll_notLoggedAsDndChange() { + mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true); + setupZenConfig(); + + // An app adds an automatic zen rule + AutomaticZenRule zenRule = new AutomaticZenRule("name", + null, + new ComponentName(CUSTOM_PKG_NAME, "cls"), + Uri.parse("condition"), + null, + NotificationManager.INTERRUPTION_FILTER_ALL, true); + String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule, + UPDATE_ORIGIN_APP, "test", CUSTOM_PKG_UID); + + // Event 1: App activates the rule automatically. + mZenModeHelper.setAutomaticZenRuleState(id, + new Condition(zenRule.getConditionId(), "", STATE_TRUE, SOURCE_SCHEDULE), + UPDATE_ORIGIN_APP, CUSTOM_PKG_UID); + + // Event 2: App deactivates the rule automatically. + mZenModeHelper.setAutomaticZenRuleState(id, + new Condition(zenRule.getConditionId(), "", STATE_FALSE, SOURCE_SCHEDULE), + UPDATE_ORIGIN_APP, CUSTOM_PKG_UID); + + // In total, this represents 2 events. + assertEquals(2, mZenModeEventLogger.numLoggedChanges()); + + // However, they are not DND_TURNED_ON/_OFF (no notification filtering is taking place). + // Also, no consolidated ZenPolicy is logged (because of the same reason). + assertThat(mZenModeEventLogger.getEventId(0)).isEqualTo( + ZenModeEventLogger.ZenStateChangedEvent.DND_ACTIVE_RULES_CHANGED.getId()); + assertThat(mZenModeEventLogger.getNumRulesActive(0)).isEqualTo(1); + assertThat(mZenModeEventLogger.getPolicyProto(0)).isNull(); + + assertThat(mZenModeEventLogger.getEventId(1)).isEqualTo( + ZenModeEventLogger.ZenStateChangedEvent.DND_ACTIVE_RULES_CHANGED.getId()); + assertThat(mZenModeEventLogger.getNumRulesActive(1)).isEqualTo(0); + assertThat(mZenModeEventLogger.getPolicyProto(1)).isNull(); + } + + @Test public void testUpdateConsolidatedPolicy_defaultRulesOnly() { setupZenConfig(); @@ -3203,6 +3253,52 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test + @EnableFlags(Flags.FLAG_MODES_API) + public void testUpdateConsolidatedPolicy_ignoresActiveRulesWithInterruptionFilterAll() { + setupZenConfig(); + + // Rules with INTERRUPTION_FILTER_ALL are skipped when calculating consolidated policy. + // Note: rules with filter != PRIORITY should not have a custom policy. However, as of V + // this is only validated on rule addition, but not on rule update. :/ + + // Rule 1: PRIORITY, custom policy but not very strict (in fact, less strict than default). + AutomaticZenRule zenRuleWithPriority = new AutomaticZenRule("Priority", + null, + new ComponentName(CUSTOM_PKG_NAME, "cls"), + Uri.parse("priority"), + new ZenPolicy.Builder().allowMedia(true).build(), + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String rule1Id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), + zenRuleWithPriority, UPDATE_ORIGIN_APP, "test", CUSTOM_PKG_UID); + mZenModeHelper.setAutomaticZenRuleState(rule1Id, + new Condition(zenRuleWithPriority.getConditionId(), "", STATE_TRUE), + UPDATE_ORIGIN_APP, CUSTOM_PKG_UID); + + // Rule 2: ALL, but somehow with a super strict ZenPolicy. + AutomaticZenRule zenRuleWithAll = new AutomaticZenRule("All", + null, + new ComponentName(CUSTOM_PKG_NAME, "cls"), + Uri.parse("priority"), + new ZenPolicy.Builder().disallowAllSounds().build(), + NotificationManager.INTERRUPTION_FILTER_ALL, true); + String rule2Id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), + zenRuleWithAll, UPDATE_ORIGIN_APP, "test", CUSTOM_PKG_UID); + mZenModeHelper.setAutomaticZenRuleState(rule2Id, + new Condition(zenRuleWithPriority.getConditionId(), "", STATE_TRUE), + UPDATE_ORIGIN_APP, CUSTOM_PKG_UID); + + // Consolidated Policy should be default + rule1. + assertThat(mZenModeHelper.mConsolidatedPolicy.allowAlarms()).isFalse(); // default + assertThat(mZenModeHelper.mConsolidatedPolicy.allowMedia()).isTrue(); // priority rule + assertThat(mZenModeHelper.mConsolidatedPolicy.allowSystem()).isFalse(); // default + assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isTrue(); // default + assertThat(mZenModeHelper.mConsolidatedPolicy.allowCalls()).isTrue(); // default + assertThat(mZenModeHelper.mConsolidatedPolicy.allowMessages()).isTrue(); // default + assertThat(mZenModeHelper.mConsolidatedPolicy.allowConversations()).isTrue(); // default + assertThat(mZenModeHelper.mConsolidatedPolicy.allowRepeatCallers()).isTrue(); // default + } + + @Test public void zenRuleToAutomaticZenRule_allFields() { mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API); when(mPackageManager.getPackagesForUid(anyInt())).thenReturn( |