Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e0f063d5 authored by Matías Hernández's avatar Matías Hernández Committed by Android (Google) Code Review
Browse files

Merge "Support zen rules with INTERRUPTION_FILTER_ALL" into main

parents acd8692a 7e5a5b1a
Loading
Loading
Loading
Loading
+37 −5
Original line number Diff line number Diff line
@@ -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,10 +400,12 @@ class ZenModeEventLogger {

        // Determine the number of (automatic & manual) rules active after the change takes place.
        int getNumRulesActive() {
            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);

+6 −1
Original line number Diff line number Diff line
@@ -1490,7 +1490,12 @@ public class ZenModeHelper {

            for (ZenRule automaticRule : mConfig.automaticRules.values()) {
                if (automaticRule.isAutomaticActive()) {
                    // 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);
                    }
+4 −1
Original line number Diff line number Diff line
@@ -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);
        }
    }

+98 −2
Original line number Diff line number Diff line
@@ -2429,8 +2429,12 @@ public class ZenModeHelperTest extends UiServiceTestCase {
        assertEquals(0, mZenModeEventLogger.getNumRulesActive(1));
        assertFalse(mZenModeEventLogger.getIsUserAction(1));
        assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(1));
        if (Flags.modesApi()) {
            assertThat(mZenModeEventLogger.getPolicyProto(1)).isNull();
        } else {
            checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1));
        }
    }

    @Test
    public void testZenModeEventLog_automaticRules(@TestParameter ModesApiFlag modesApiFlag)
@@ -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));
        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
@@ -3015,6 +3023,48 @@ public class ZenModeHelperTest extends UiServiceTestCase {
                .isEqualTo(DNDProtoEnums.CHANNEL_TYPE_NONE);
    }

    @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();
@@ -3202,6 +3252,52 @@ public class ZenModeHelperTest extends UiServiceTestCase {
        assertFalse(mZenModeHelper.mConsolidatedPolicy.allowPriorityChannels());
    }

    @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);