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

Commit 36f733f7 authored by Matías Hernández's avatar Matías Hernández
Browse files

Record who has disabled an AutomaticZenRule

Not exposed as part of AutomaticZenRule since only system/settings will access it (through ZenModeConfig).

Fixes: 348177036
Test: atest ZenModeHelperTest
Flag: android.app.modes_ui
Change-Id: Ifc6093794f4439608126ba1ab6bbb0846e21cce9
parent 6a18195a
Loading
Loading
Loading
Loading
+40 −9
Original line number Diff line number Diff line
@@ -262,15 +262,12 @@ public class ZenModeConfig implements Parcelable {
    private static final String CONDITION_ATT_SOURCE = "source";
    private static final String CONDITION_ATT_FLAGS = "flags";

    private static final String ZEN_POLICY_TAG = "zen_policy";

    private static final String MANUAL_TAG = "manual";
    private static final String AUTOMATIC_TAG = "automatic";
    private static final String AUTOMATIC_DELETED_TAG = "deleted";

    private static final String RULE_ATT_ID = "ruleId";
    private static final String RULE_ATT_ENABLED = "enabled";
    private static final String RULE_ATT_SNOOZING = "snoozing";
    private static final String RULE_ATT_NAME = "name";
    private static final String RULE_ATT_PKG = "pkg";
    private static final String RULE_ATT_COMPONENT = "component";
@@ -286,6 +283,7 @@ public class ZenModeConfig implements Parcelable {
    private static final String RULE_ATT_ICON = "rule_icon";
    private static final String RULE_ATT_TRIGGER_DESC = "triggerDesc";
    private static final String RULE_ATT_DELETION_INSTANT = "deletionInstant";
    private static final String RULE_ATT_DISABLED_ORIGIN = "disabledOrigin";

    private static final String DEVICE_EFFECT_DISPLAY_GRAYSCALE = "zdeDisplayGrayscale";
    private static final String DEVICE_EFFECT_SUPPRESS_AMBIENT_DISPLAY =
@@ -1170,6 +1168,10 @@ public class ZenModeConfig implements Parcelable {
            if (deletionInstant != null) {
                rt.deletionInstant = Instant.ofEpochMilli(deletionInstant);
            }
            if (Flags.modesUi()) {
                rt.disabledOrigin = safeInt(parser, RULE_ATT_DISABLED_ORIGIN,
                        UPDATE_ORIGIN_UNKNOWN);
            }
        }
        return rt;
    }
@@ -1224,6 +1226,9 @@ public class ZenModeConfig implements Parcelable {
                out.attributeLong(null, RULE_ATT_DELETION_INSTANT,
                        rule.deletionInstant.toEpochMilli());
            }
            if (Flags.modesUi()) {
                out.attributeInt(null, RULE_ATT_DISABLED_ORIGIN, rule.disabledOrigin);
            }
        }
    }

@@ -2514,6 +2519,8 @@ public class ZenModeConfig implements Parcelable {
        @ZenPolicy.ModifiableField public int zenPolicyUserModifiedFields;
        @ZenDeviceEffects.ModifiableField public int zenDeviceEffectsUserModifiedFields;
        @Nullable public Instant deletionInstant; // Only set on deleted rules.
        @FlaggedApi(Flags.FLAG_MODES_UI)
        @ConfigChangeOrigin public int disabledOrigin = UPDATE_ORIGIN_UNKNOWN;

        public ZenRule() { }

@@ -2552,6 +2559,9 @@ public class ZenModeConfig implements Parcelable {
                if (source.readInt() == 1) {
                    deletionInstant = Instant.ofEpochMilli(source.readLong());
                }
                if (Flags.modesUi()) {
                    disabledOrigin = source.readInt();
                }
            }
        }

@@ -2626,6 +2636,9 @@ public class ZenModeConfig implements Parcelable {
                } else {
                    dest.writeInt(0);
                }
                if (Flags.modesUi()) {
                    dest.writeInt(disabledOrigin);
                }
            }
        }

@@ -2671,6 +2684,9 @@ public class ZenModeConfig implements Parcelable {
                if (deletionInstant != null) {
                    sb.append(",deletionInstant=").append(deletionInstant);
                }
                if (Flags.modesUi()) {
                    sb.append(",disabledOrigin=").append(disabledOrigin);
                }
            }

            return sb.append(']').toString();
@@ -2724,7 +2740,7 @@ public class ZenModeConfig implements Parcelable {
                    && other.modified == modified;

            if (Flags.modesApi()) {
                return finalEquals
                finalEquals = finalEquals
                        && Objects.equals(other.zenDeviceEffects, zenDeviceEffects)
                        && other.allowManualInvocation == allowManualInvocation
                        && Objects.equals(other.iconResName, iconResName)
@@ -2735,6 +2751,11 @@ public class ZenModeConfig implements Parcelable {
                        && other.zenDeviceEffectsUserModifiedFields
                            == zenDeviceEffectsUserModifiedFields
                        && Objects.equals(other.deletionInstant, deletionInstant);

                if (Flags.modesUi()) {
                    finalEquals = finalEquals
                            && other.disabledOrigin == disabledOrigin;
                }
            }

            return finalEquals;
@@ -2743,12 +2764,22 @@ public class ZenModeConfig implements Parcelable {
        @Override
        public int hashCode() {
            if (Flags.modesApi()) {
                if (Flags.modesUi()) {
                    return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
                            component, configurationActivity, pkg, id, enabler, zenPolicy,
                            zenDeviceEffects, modified, allowManualInvocation, iconResName,
                        triggerDescription, type, userModifiedFields, zenPolicyUserModifiedFields,
                            triggerDescription, type, userModifiedFields,
                            zenPolicyUserModifiedFields,
                            zenDeviceEffectsUserModifiedFields, deletionInstant, disabledOrigin);
                } else {
                    return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
                            component, configurationActivity, pkg, id, enabler, zenPolicy,
                            zenDeviceEffects, modified, allowManualInvocation, iconResName,
                            triggerDescription, type, userModifiedFields,
                            zenPolicyUserModifiedFields,
                            zenDeviceEffectsUserModifiedFields, deletionInstant);
                }
            }
            return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
                    component, configurationActivity, pkg, id, enabler, zenPolicy, modified);
        }
+12 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import static android.service.notification.ZenModeConfig.UPDATE_ORIGIN_INIT;
import static android.service.notification.ZenModeConfig.UPDATE_ORIGIN_INIT_USER;
import static android.service.notification.ZenModeConfig.UPDATE_ORIGIN_RESTORE_BACKUP;
import static android.service.notification.ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI;
import static android.service.notification.ZenModeConfig.UPDATE_ORIGIN_UNKNOWN;
import static android.service.notification.ZenModeConfig.UPDATE_ORIGIN_USER;

import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
@@ -1143,6 +1144,17 @@ public class ZenModeHelper {
                modified = true;
            }

            if (Flags.modesUi()) {
                if (!azr.isEnabled() && (isNew || rule.enabled)) {
                    // Creating a rule as disabled, or disabling a previously enabled rule.
                    // Record whodunit.
                    rule.disabledOrigin = origin;
                } else if (azr.isEnabled()) {
                    // Enabling or previously enabled. Clear disabler.
                    rule.disabledOrigin = UPDATE_ORIGIN_UNKNOWN;
                }
            }

            if (!Objects.equals(rule.conditionId, azr.getConditionId())) {
                rule.conditionId = azr.getConditionId();
                modified = true;
+12 −0
Original line number Diff line number Diff line
@@ -511,6 +511,9 @@ public class ZenModeConfigTest extends UiServiceTestCase {
        rule.iconResName = ICON_RES_NAME;
        rule.triggerDescription = TRIGGER_DESC;
        rule.deletionInstant = Instant.ofEpochMilli(1701790147000L);
        if (Flags.modesUi()) {
            rule.disabledOrigin = ZenModeConfig.UPDATE_ORIGIN_USER;
        }

        Parcel parcel = Parcel.obtain();
        rule.writeToParcel(parcel, 0);
@@ -540,6 +543,9 @@ public class ZenModeConfigTest extends UiServiceTestCase {
        assertEquals(rule.triggerDescription, parceled.triggerDescription);
        assertEquals(rule.zenPolicy, parceled.zenPolicy);
        assertEquals(rule.deletionInstant, parceled.deletionInstant);
        if (Flags.modesUi()) {
            assertEquals(rule.disabledOrigin, parceled.disabledOrigin);
        }

        assertEquals(rule, parceled);
        assertEquals(rule.hashCode(), parceled.hashCode());
@@ -620,6 +626,9 @@ public class ZenModeConfigTest extends UiServiceTestCase {
        rule.iconResName = ICON_RES_NAME;
        rule.triggerDescription = TRIGGER_DESC;
        rule.deletionInstant = Instant.ofEpochMilli(1701790147000L);
        if (Flags.modesUi()) {
            rule.disabledOrigin = ZenModeConfig.UPDATE_ORIGIN_APP;
        }

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        writeRuleXml(rule, baos);
@@ -653,6 +662,9 @@ public class ZenModeConfigTest extends UiServiceTestCase {
        assertEquals(rule.triggerDescription, fromXml.triggerDescription);
        assertEquals(rule.iconResName, fromXml.iconResName);
        assertEquals(rule.deletionInstant, fromXml.deletionInstant);
        if (Flags.modesUi()) {
            assertEquals(rule.disabledOrigin, fromXml.disabledOrigin);
        }
    }

    @Test
+7 −4
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.notification;

import static android.app.Flags.FLAG_MODES_API;
import static android.app.Flags.FLAG_MODES_UI;

import static com.google.common.truth.Truth.assertThat;
@@ -32,6 +33,7 @@ import android.app.Flags;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.FlagsParameterization;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
@@ -79,16 +81,17 @@ public class ZenModeDiffTest extends UiServiceTestCase {
                    : Set.of("version", "manualRule", "automaticRules");

    // Differences for flagged fields are only generated if the flag is enabled.
    // "Metadata" fields (userModifiedFields & co, deletionInstant) are not compared.
    // "Metadata" fields (userModifiedFields, deletionInstant, disabledOrigin) are not compared.
    private static final Set<String> ZEN_RULE_EXEMPT_FIELDS =
            android.app.Flags.modesApi()
                    ? Set.of("userModifiedFields", "zenPolicyUserModifiedFields",
                            "zenDeviceEffectsUserModifiedFields", "deletionInstant")
                            "zenDeviceEffectsUserModifiedFields", "deletionInstant",
                            "disabledOrigin")
                    : Set.of(RuleDiff.FIELD_TYPE, RuleDiff.FIELD_TRIGGER_DESCRIPTION,
                            RuleDiff.FIELD_ICON_RES, RuleDiff.FIELD_ALLOW_MANUAL,
                            RuleDiff.FIELD_ZEN_DEVICE_EFFECTS, "userModifiedFields",
                            "zenPolicyUserModifiedFields", "zenDeviceEffectsUserModifiedFields",
                            "deletionInstant");
                            "deletionInstant", "disabledOrigin");

    // allowPriorityChannels is flagged by android.app.modes_api
    public static final Set<String> ZEN_MODE_CONFIG_FLAGGED_FIELDS =
@@ -201,8 +204,8 @@ public class ZenModeDiffTest extends UiServiceTestCase {
    }

    @Test
    @EnableFlags(FLAG_MODES_API)
    public void testConfigDiff_fieldDiffs_flagOn() throws Exception {
        mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
        // these two start the same
        ZenModeConfig c1 = new ZenModeConfig();
        ZenModeConfig c2 = new ZenModeConfig();
+95 −0
Original line number Diff line number Diff line
@@ -6226,6 +6226,101 @@ public class ZenModeHelperTest extends UiServiceTestCase {
        assertThat(mZenModeHelper.getConfig().manualRule.zenDeviceEffects).isEqualTo(effects);
    }

    @Test
    @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
    public void addAutomaticZenRule_startsDisabled_recordsDisabledOrigin() {
        AutomaticZenRule startsDisabled = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
                .setOwner(new ComponentName(mPkg, "SomeProvider"))
                .setEnabled(false)
                .build();

        String ruleId = mZenModeHelper.addAutomaticZenRule(mPkg, startsDisabled, UPDATE_ORIGIN_APP,
                "new", CUSTOM_PKG_UID);

        assertThat(mZenModeHelper.mConfig.automaticRules.get(ruleId).disabledOrigin).isEqualTo(
                UPDATE_ORIGIN_APP);
    }

    @Test
    @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
    public void updateAutomaticZenRule_disabling_recordsDisabledOrigin() {
        AutomaticZenRule startsEnabled = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
                .setOwner(new ComponentName(mPkg, "SomeProvider"))
                .setEnabled(true)
                .build();
        String ruleId = mZenModeHelper.addAutomaticZenRule(mPkg, startsEnabled, UPDATE_ORIGIN_APP,
                "new", CUSTOM_PKG_UID);
        assertThat(mZenModeHelper.mConfig.automaticRules.get(ruleId).disabledOrigin).isEqualTo(
                UPDATE_ORIGIN_UNKNOWN);

        AutomaticZenRule nowDisabled = new AutomaticZenRule.Builder(startsEnabled)
                .setEnabled(false)
                .build();
        mZenModeHelper.updateAutomaticZenRule(ruleId, nowDisabled, UPDATE_ORIGIN_USER, "off",
                Process.SYSTEM_UID);

        assertThat(mZenModeHelper.mConfig.automaticRules.get(ruleId).disabledOrigin).isEqualTo(
                UPDATE_ORIGIN_USER);
    }

    @Test
    @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
    public void updateAutomaticZenRule_keepingDisabled_preservesPreviousDisabledOrigin() {
        AutomaticZenRule startsEnabled = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
                .setOwner(new ComponentName(mPkg, "SomeProvider"))
                .setEnabled(true)
                .build();
        String ruleId = mZenModeHelper.addAutomaticZenRule(mPkg, startsEnabled, UPDATE_ORIGIN_APP,
                "new", CUSTOM_PKG_UID);
        AutomaticZenRule nowDisabled = new AutomaticZenRule.Builder(startsEnabled)
                .setEnabled(false)
                .build();
        mZenModeHelper.updateAutomaticZenRule(ruleId, nowDisabled, UPDATE_ORIGIN_USER, "off",
                Process.SYSTEM_UID);
        assertThat(mZenModeHelper.mConfig.automaticRules.get(ruleId).disabledOrigin).isEqualTo(
                UPDATE_ORIGIN_USER);

        // Now update it again, for an unrelated reason with a different origin.
        AutomaticZenRule nowRenamed = new AutomaticZenRule.Builder(nowDisabled)
                .setName("Fancy pants rule")
                .build();
        mZenModeHelper.updateAutomaticZenRule(ruleId, nowRenamed, UPDATE_ORIGIN_APP, "update",
                CUSTOM_PKG_UID);

        // Identity of the disabler is preserved.
        assertThat(mZenModeHelper.mConfig.automaticRules.get(ruleId).disabledOrigin).isEqualTo(
                UPDATE_ORIGIN_USER);
    }

    @Test
    @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
    public void updateAutomaticZenRule_enabling_clearsDisabledOrigin() {
        AutomaticZenRule startsEnabled = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
                .setOwner(new ComponentName(mPkg, "SomeProvider"))
                .setEnabled(true)
                .build();
        String ruleId = mZenModeHelper.addAutomaticZenRule(mPkg, startsEnabled, UPDATE_ORIGIN_APP,
                "new", CUSTOM_PKG_UID);
        AutomaticZenRule nowDisabled = new AutomaticZenRule.Builder(startsEnabled)
                .setEnabled(false)
                .build();
        mZenModeHelper.updateAutomaticZenRule(ruleId, nowDisabled, UPDATE_ORIGIN_USER, "off",
                Process.SYSTEM_UID);
        assertThat(mZenModeHelper.mConfig.automaticRules.get(ruleId).disabledOrigin).isEqualTo(
                UPDATE_ORIGIN_USER);

        // Now enable it again
        AutomaticZenRule nowEnabled = new AutomaticZenRule.Builder(nowDisabled)
                .setEnabled(true)
                .build();
        mZenModeHelper.updateAutomaticZenRule(ruleId, nowEnabled, UPDATE_ORIGIN_APP, "on",
                CUSTOM_PKG_UID);

        // Identity of the disabler was cleared.
        assertThat(mZenModeHelper.mConfig.automaticRules.get(ruleId).disabledOrigin).isEqualTo(
                UPDATE_ORIGIN_UNKNOWN);
    }

    private static void addZenRule(ZenModeConfig config, String id, String ownerPkg, int zenMode,
            @Nullable ZenPolicy zenPolicy) {
        ZenRule rule = new ZenRule();