diff options
13 files changed, 244 insertions, 597 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 15c054f0b5e8..52ce4dce7102 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -5317,7 +5317,6 @@ package android.app { ctor @Deprecated public AutomaticZenRule(String, android.content.ComponentName, android.net.Uri, int, boolean); ctor public AutomaticZenRule(@NonNull String, @Nullable android.content.ComponentName, @Nullable android.content.ComponentName, @NonNull android.net.Uri, @Nullable android.service.notification.ZenPolicy, int, boolean); ctor public AutomaticZenRule(android.os.Parcel); - method @FlaggedApi("android.app.modes_api") public boolean canUpdate(); method public int describeContents(); method public android.net.Uri getConditionId(); method @Nullable public android.content.ComponentName getConfigurationActivity(); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index bbe03a3d11a2..d566216bd669 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -284,16 +284,6 @@ package android.app { method public default void onOpActiveChanged(@NonNull String, int, @NonNull String, @Nullable String, boolean, int, int); } - public final class AutomaticZenRule implements android.os.Parcelable { - method @FlaggedApi("android.app.modes_api") public int getUserModifiedFields(); - field @FlaggedApi("android.app.modes_api") public static final int FIELD_INTERRUPTION_FILTER = 2; // 0x2 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_NAME = 1; // 0x1 - } - - @FlaggedApi("android.app.modes_api") public static final class AutomaticZenRule.Builder { - method @FlaggedApi("android.app.modes_api") @NonNull public android.app.AutomaticZenRule.Builder setUserModifiedFields(int); - } - public class BroadcastOptions extends android.app.ComponentOptions { ctor public BroadcastOptions(); ctor public BroadcastOptions(@NonNull android.os.Bundle); @@ -3021,47 +3011,8 @@ package android.service.notification { method @Deprecated public boolean isBound(); } - @FlaggedApi("android.app.modes_api") public final class ZenDeviceEffects implements android.os.Parcelable { - method public int getUserModifiedFields(); - field public static final int FIELD_DIM_WALLPAPER = 4; // 0x4 - field public static final int FIELD_DISABLE_AUTO_BRIGHTNESS = 16; // 0x10 - field public static final int FIELD_DISABLE_TAP_TO_WAKE = 32; // 0x20 - field public static final int FIELD_DISABLE_TILT_TO_WAKE = 64; // 0x40 - field public static final int FIELD_DISABLE_TOUCH = 128; // 0x80 - field public static final int FIELD_GRAYSCALE = 1; // 0x1 - field public static final int FIELD_MAXIMIZE_DOZE = 512; // 0x200 - field public static final int FIELD_MINIMIZE_RADIO_USAGE = 256; // 0x100 - field public static final int FIELD_NIGHT_MODE = 8; // 0x8 - field public static final int FIELD_SUPPRESS_AMBIENT_DISPLAY = 2; // 0x2 - } - - @FlaggedApi("android.app.modes_api") public static final class ZenDeviceEffects.Builder { - method @NonNull public android.service.notification.ZenDeviceEffects.Builder setUserModifiedFields(int); - } - - public final class ZenPolicy implements android.os.Parcelable { - method @FlaggedApi("android.app.modes_api") public int getUserModifiedFields(); - field @FlaggedApi("android.app.modes_api") public static final int FIELD_ALLOW_CHANNELS = 8; // 0x8 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_CALLS = 2; // 0x2 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_CONVERSATIONS = 4; // 0x4 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_MESSAGES = 1; // 0x1 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_PRIORITY_CATEGORY_ALARMS = 128; // 0x80 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_PRIORITY_CATEGORY_EVENTS = 32; // 0x20 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_PRIORITY_CATEGORY_MEDIA = 256; // 0x100 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_PRIORITY_CATEGORY_REPEAT_CALLERS = 64; // 0x40 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_PRIORITY_CATEGORY_SYSTEM = 512; // 0x200 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_VISUAL_EFFECT_AMBIENT = 32768; // 0x8000 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_VISUAL_EFFECT_BADGE = 16384; // 0x4000 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_VISUAL_EFFECT_FULL_SCREEN_INTENT = 1024; // 0x400 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_VISUAL_EFFECT_LIGHTS = 2048; // 0x800 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_VISUAL_EFFECT_NOTIFICATION_LIST = 65536; // 0x10000 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_VISUAL_EFFECT_PEEK = 4096; // 0x1000 - field @FlaggedApi("android.app.modes_api") public static final int FIELD_VISUAL_EFFECT_STATUS_BAR = 8192; // 0x2000 - } - public static final class ZenPolicy.Builder { ctor public ZenPolicy.Builder(@Nullable android.service.notification.ZenPolicy); - method @FlaggedApi("android.app.modes_api") @NonNull public android.service.notification.ZenPolicy.Builder setUserModifiedFields(int); } } diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java index 5b354fc3b9ed..d57a4e583a1a 100644 --- a/core/java/android/app/AutomaticZenRule.java +++ b/core/java/android/app/AutomaticZenRule.java @@ -23,7 +23,6 @@ import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.TestApi; import android.app.NotificationManager.InterruptionFilter; import android.content.ComponentName; import android.net.Uri; @@ -113,8 +112,8 @@ public final class AutomaticZenRule implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface Type {} - /** Used to track which rule variables have been modified by the user. - * Should be checked against the bitmask {@link #getUserModifiedFields()}. + /** + * Enum for the user-modifiable fields in this object. * @hide */ @IntDef(flag = true, prefix = { "FIELD_" }, value = { @@ -128,13 +127,11 @@ public final class AutomaticZenRule implements Parcelable { * @hide */ @FlaggedApi(Flags.FLAG_MODES_API) - @TestApi public static final int FIELD_NAME = 1 << 0; /** * @hide */ @FlaggedApi(Flags.FLAG_MODES_API) - @TestApi public static final int FIELD_INTERRUPTION_FILTER = 1 << 1; private boolean enabled; @@ -153,7 +150,6 @@ public final class AutomaticZenRule implements Parcelable { private int mIconResId; private String mTriggerDescription; private boolean mAllowManualInvocation; - private @ModifiableField int mUserModifiedFields; // Bitwise representation /** * The maximum string length for any string contained in this automatic zen rule. This pertains @@ -256,7 +252,6 @@ public final class AutomaticZenRule implements Parcelable { mIconResId = source.readInt(); mTriggerDescription = getTrimmedString(source.readString(), MAX_DESC_LENGTH); mType = source.readInt(); - mUserModifiedFields = source.readInt(); } } @@ -307,8 +302,7 @@ public final class AutomaticZenRule implements Parcelable { * Returns whether this rule's name has been modified by the user. * @hide */ - // TODO: b/310620812 - Replace with mUserModifiedFields & FIELD_NAME once - // FLAG_MODES_API is inlined. + // TODO: b/310620812 - Consider removing completely. Seems not be used anywhere except tests. public boolean isModified() { return mModified; } @@ -506,32 +500,6 @@ public final class AutomaticZenRule implements Parcelable { return type; } - /** - * Gets the bitmask representing which fields are user modified. Bits are set using - * {@link ModifiableField}. - * @hide - */ - @FlaggedApi(Flags.FLAG_MODES_API) - @TestApi - public @ModifiableField int getUserModifiedFields() { - return mUserModifiedFields; - } - - /** - * Returns {@code true} if the {@link AutomaticZenRule} can be updated. - * When this returns {@code false}, calls to - * {@link NotificationManager#updateAutomaticZenRule(String, AutomaticZenRule)}) with this rule - * will ignore changes to user-configurable fields. - */ - @FlaggedApi(Flags.FLAG_MODES_API) - public boolean canUpdate() { - // The rule is considered updateable if its bitmask has no user modifications, and - // the bitmasks of the policy and device effects have no modification. - return mUserModifiedFields == 0 - && (mZenPolicy == null || mZenPolicy.getUserModifiedFields() == 0) - && (mDeviceEffects == null || mDeviceEffects.getUserModifiedFields() == 0); - } - @Override public int describeContents() { return 0; @@ -560,7 +528,6 @@ public final class AutomaticZenRule implements Parcelable { dest.writeInt(mIconResId); dest.writeString(mTriggerDescription); dest.writeInt(mType); - dest.writeInt(mUserModifiedFields); } } @@ -582,16 +549,14 @@ public final class AutomaticZenRule implements Parcelable { .append(",allowManualInvocation=").append(mAllowManualInvocation) .append(",iconResId=").append(mIconResId) .append(",triggerDescription=").append(mTriggerDescription) - .append(",type=").append(mType) - .append(",userModifiedFields=") - .append(modifiedFieldsToString(mUserModifiedFields)); + .append(",type=").append(mType); } return sb.append(']').toString(); } - @FlaggedApi(Flags.FLAG_MODES_API) - private String modifiedFieldsToString(int bitmask) { + /** @hide */ + public static String fieldsToString(@ModifiableField int bitmask) { ArrayList<String> modified = new ArrayList<>(); if ((bitmask & FIELD_NAME) != 0) { modified.add("FIELD_NAME"); @@ -623,8 +588,7 @@ public final class AutomaticZenRule implements Parcelable { && other.mAllowManualInvocation == mAllowManualInvocation && other.mIconResId == mIconResId && Objects.equals(other.mTriggerDescription, mTriggerDescription) - && other.mType == mType - && other.mUserModifiedFields == mUserModifiedFields; + && other.mType == mType; } return finalEquals; } @@ -634,8 +598,7 @@ public final class AutomaticZenRule implements Parcelable { if (Flags.modesApi()) { return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, configurationActivity, mZenPolicy, mDeviceEffects, mModified, creationTime, - mPkg, mAllowManualInvocation, mIconResId, mTriggerDescription, mType, - mUserModifiedFields); + mPkg, mAllowManualInvocation, mIconResId, mTriggerDescription, mType); } return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, configurationActivity, mZenPolicy, mModified, creationTime, mPkg); @@ -704,7 +667,6 @@ public final class AutomaticZenRule implements Parcelable { private boolean mAllowManualInvocation; private long mCreationTime; private String mPkg; - private @ModifiableField int mUserModifiedFields; public Builder(@NonNull AutomaticZenRule rule) { mName = rule.getName(); @@ -721,7 +683,6 @@ public final class AutomaticZenRule implements Parcelable { mAllowManualInvocation = rule.isManualInvocationAllowed(); mCreationTime = rule.getCreationTime(); mPkg = rule.getPackageName(); - mUserModifiedFields = rule.mUserModifiedFields; } public Builder(@NonNull String name, @NonNull Uri conditionId) { @@ -848,19 +809,6 @@ public final class AutomaticZenRule implements Parcelable { return this; } - /** - * Sets the bitmask representing which fields have been user-modified. - * This method should not be used outside of tests. The value of userModifiedFields - * should be set based on what values are changed when a rule is populated or updated.. - * @hide - */ - @FlaggedApi(Flags.FLAG_MODES_API) - @TestApi - public @NonNull Builder setUserModifiedFields(@ModifiableField int userModifiedFields) { - mUserModifiedFields = userModifiedFields; - return this; - } - public @NonNull AutomaticZenRule build() { AutomaticZenRule rule = new AutomaticZenRule(mName, mOwner, mConfigurationActivity, mConditionId, mPolicy, mInterruptionFilter, mEnabled); @@ -871,7 +819,6 @@ public final class AutomaticZenRule implements Parcelable { rule.mIconResId = mIconResId; rule.mAllowManualInvocation = mAllowManualInvocation; rule.setPackageName(mPkg); - rule.mUserModifiedFields = mUserModifiedFields; return rule; } diff --git a/core/java/android/service/notification/ZenDeviceEffects.java b/core/java/android/service/notification/ZenDeviceEffects.java index 03ebae5c5199..90049e6a934a 100644 --- a/core/java/android/service/notification/ZenDeviceEffects.java +++ b/core/java/android/service/notification/ZenDeviceEffects.java @@ -20,7 +20,6 @@ import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.TestApi; import android.app.Flags; import android.os.Parcel; import android.os.Parcelable; @@ -37,8 +36,8 @@ import java.util.Objects; @FlaggedApi(Flags.FLAG_MODES_API) public final class ZenDeviceEffects implements Parcelable { - /** Used to track which rule variables have been modified by the user. - * Should be checked against the bitmask {@link #getUserModifiedFields()}. + /** + * Enum for the user-modifiable fields in this object. * @hide */ @IntDef(flag = true, prefix = { "FIELD_" }, value = { @@ -59,52 +58,42 @@ public final class ZenDeviceEffects implements Parcelable { /** * @hide */ - @TestApi public static final int FIELD_GRAYSCALE = 1 << 0; /** * @hide */ - @TestApi public static final int FIELD_SUPPRESS_AMBIENT_DISPLAY = 1 << 1; /** * @hide */ - @TestApi public static final int FIELD_DIM_WALLPAPER = 1 << 2; /** * @hide */ - @TestApi public static final int FIELD_NIGHT_MODE = 1 << 3; /** * @hide */ - @TestApi public static final int FIELD_DISABLE_AUTO_BRIGHTNESS = 1 << 4; /** * @hide */ - @TestApi public static final int FIELD_DISABLE_TAP_TO_WAKE = 1 << 5; /** * @hide */ - @TestApi public static final int FIELD_DISABLE_TILT_TO_WAKE = 1 << 6; /** * @hide */ - @TestApi public static final int FIELD_DISABLE_TOUCH = 1 << 7; /** * @hide */ - @TestApi public static final int FIELD_MINIMIZE_RADIO_USAGE = 1 << 8; /** * @hide */ - @TestApi public static final int FIELD_MAXIMIZE_DOZE = 1 << 9; private final boolean mGrayscale; @@ -119,13 +108,10 @@ public final class ZenDeviceEffects implements Parcelable { private final boolean mMinimizeRadioUsage; private final boolean mMaximizeDoze; - private final @ModifiableField int mUserModifiedFields; // Bitwise representation - private ZenDeviceEffects(boolean grayscale, boolean suppressAmbientDisplay, boolean dimWallpaper, boolean nightMode, boolean disableAutoBrightness, boolean disableTapToWake, boolean disableTiltToWake, boolean disableTouch, - boolean minimizeRadioUsage, boolean maximizeDoze, - @ModifiableField int userModifiedFields) { + boolean minimizeRadioUsage, boolean maximizeDoze) { mGrayscale = grayscale; mSuppressAmbientDisplay = suppressAmbientDisplay; mDimWallpaper = dimWallpaper; @@ -136,7 +122,6 @@ public final class ZenDeviceEffects implements Parcelable { mDisableTouch = disableTouch; mMinimizeRadioUsage = minimizeRadioUsage; mMaximizeDoze = maximizeDoze; - mUserModifiedFields = userModifiedFields; } @Override @@ -153,15 +138,14 @@ public final class ZenDeviceEffects implements Parcelable { && this.mDisableTiltToWake == that.mDisableTiltToWake && this.mDisableTouch == that.mDisableTouch && this.mMinimizeRadioUsage == that.mMinimizeRadioUsage - && this.mMaximizeDoze == that.mMaximizeDoze - && this.mUserModifiedFields == that.mUserModifiedFields; + && this.mMaximizeDoze == that.mMaximizeDoze; } @Override public int hashCode() { return Objects.hash(mGrayscale, mSuppressAmbientDisplay, mDimWallpaper, mNightMode, mDisableAutoBrightness, mDisableTapToWake, mDisableTiltToWake, mDisableTouch, - mMinimizeRadioUsage, mMaximizeDoze, mUserModifiedFields); + mMinimizeRadioUsage, mMaximizeDoze); } @Override @@ -177,11 +161,11 @@ public final class ZenDeviceEffects implements Parcelable { if (mDisableTouch) effects.add("disableTouch"); if (mMinimizeRadioUsage) effects.add("minimizeRadioUsage"); if (mMaximizeDoze) effects.add("maximizeDoze"); - return "[" + String.join(", ", effects) + "]" - + " userModifiedFields: " + modifiedFieldsToString(mUserModifiedFields); + return "[" + String.join(", ", effects) + "]"; } - private String modifiedFieldsToString(int bitmask) { + /** @hide */ + public static String fieldsToString(@ModifiableField int bitmask) { ArrayList<String> modified = new ArrayList<>(); if ((bitmask & FIELD_GRAYSCALE) != 0) { modified.add("FIELD_GRAYSCALE"); @@ -312,7 +296,7 @@ public final class ZenDeviceEffects implements Parcelable { return new ZenDeviceEffects(in.readBoolean(), in.readBoolean(), in.readBoolean(), in.readBoolean(), in.readBoolean(), in.readBoolean(), in.readBoolean(), in.readBoolean(), in.readBoolean(), - in.readBoolean(), in.readInt()); + in.readBoolean()); } @Override @@ -321,16 +305,6 @@ public final class ZenDeviceEffects implements Parcelable { } }; - /** - * Gets the bitmask representing which fields are user modified. Bits are set using - * {@link ModifiableField}. - * @hide - */ - @TestApi - public @ModifiableField int getUserModifiedFields() { - return mUserModifiedFields; - } - @Override public int describeContents() { return 0; @@ -348,7 +322,6 @@ public final class ZenDeviceEffects implements Parcelable { dest.writeBoolean(mDisableTouch); dest.writeBoolean(mMinimizeRadioUsage); dest.writeBoolean(mMaximizeDoze); - dest.writeInt(mUserModifiedFields); } /** Builder class for {@link ZenDeviceEffects} objects. */ @@ -365,7 +338,6 @@ public final class ZenDeviceEffects implements Parcelable { private boolean mDisableTouch; private boolean mMinimizeRadioUsage; private boolean mMaximizeDoze; - private @ModifiableField int mUserModifiedFields; /** * Instantiates a new {@link ZenPolicy.Builder} with all effects set to default (disabled). @@ -388,7 +360,6 @@ public final class ZenDeviceEffects implements Parcelable { mDisableTouch = zenDeviceEffects.shouldDisableTouch(); mMinimizeRadioUsage = zenDeviceEffects.shouldMinimizeRadioUsage(); mMaximizeDoze = zenDeviceEffects.shouldMaximizeDoze(); - mUserModifiedFields = zenDeviceEffects.mUserModifiedFields; } /** @@ -510,24 +481,13 @@ public final class ZenDeviceEffects implements Parcelable { return this; } - /** - * Sets the bitmask representing which fields are user modified. See the FIELD_ constants. - * @hide - */ - @TestApi - @NonNull - public Builder setUserModifiedFields(@ModifiableField int userModifiedFields) { - mUserModifiedFields = userModifiedFields; - return this; - } - /** Builds a {@link ZenDeviceEffects} object based on the builder's state. */ @NonNull public ZenDeviceEffects build() { return new ZenDeviceEffects(mGrayscale, mSuppressAmbientDisplay, mDimWallpaper, mNightMode, mDisableAutoBrightness, mDisableTapToWake, mDisableTiltToWake, mDisableTouch, mMinimizeRadioUsage, - mMaximizeDoze, mUserModifiedFields); + mMaximizeDoze); } } } diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index d4d602da0071..c479877fe98e 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -206,7 +206,7 @@ public class ZenModeConfig implements Parcelable { private static final String ALLOW_ATT_CONV = "convos"; private static final String ALLOW_ATT_CONV_FROM = "convosFrom"; private static final String ALLOW_ATT_CHANNELS = "priorityChannels"; - private static final String USER_MODIFIED_FIELDS = "policyUserModifiedFields"; + private static final String POLICY_USER_MODIFIED_FIELDS = "policyUserModifiedFields"; private static final String DISALLOW_TAG = "disallow"; private static final String DISALLOW_ATT_VISUAL_EFFECTS = "visualEffects"; private static final String STATE_TAG = "state"; @@ -806,6 +806,9 @@ public class ZenModeConfig implements Parcelable { rt.triggerDescription = parser.getAttributeValue(null, RULE_ATT_TRIGGER_DESC); rt.type = safeInt(parser, RULE_ATT_TYPE, AutomaticZenRule.TYPE_UNKNOWN); rt.userModifiedFields = safeInt(parser, RULE_ATT_USER_MODIFIED_FIELDS, 0); + rt.zenPolicyUserModifiedFields = safeInt(parser, POLICY_USER_MODIFIED_FIELDS, 0); + rt.zenDeviceEffectsUserModifiedFields = safeInt(parser, + DEVICE_EFFECT_USER_MODIFIED_FIELDS, 0); Long deletionInstant = tryParseLong( parser.getAttributeValue(null, RULE_ATT_DELETION_INSTANT), null); if (deletionInstant != null) { @@ -858,6 +861,9 @@ public class ZenModeConfig implements Parcelable { } out.attributeInt(null, RULE_ATT_TYPE, rule.type); out.attributeInt(null, RULE_ATT_USER_MODIFIED_FIELDS, rule.userModifiedFields); + out.attributeInt(null, POLICY_USER_MODIFIED_FIELDS, rule.zenPolicyUserModifiedFields); + out.attributeInt(null, DEVICE_EFFECT_USER_MODIFIED_FIELDS, + rule.zenDeviceEffectsUserModifiedFields); if (rule.deletionInstant != null) { out.attributeLong(null, RULE_ATT_DELETION_INSTANT, rule.deletionInstant.toEpochMilli()); @@ -924,7 +930,6 @@ public class ZenModeConfig implements Parcelable { builder.allowPriorityChannels(channels == ZenPolicy.STATE_ALLOW); policySet = true; } - builder.setUserModifiedFields(safeInt(parser, USER_MODIFIED_FIELDS, 0)); } if (calls != ZenPolicy.PEOPLE_TYPE_UNSET) { @@ -1037,7 +1042,6 @@ public class ZenModeConfig implements Parcelable { if (Flags.modesApi()) { writeZenPolicyState(ALLOW_ATT_CHANNELS, policy.getPriorityChannels(), out); - out.attributeInt(null, USER_MODIFIED_FIELDS, policy.getUserModifiedFields()); } } @@ -1083,7 +1087,6 @@ public class ZenModeConfig implements Parcelable { .setShouldMinimizeRadioUsage( safeBoolean(parser, DEVICE_EFFECT_MINIMIZE_RADIO_USAGE, false)) .setShouldMaximizeDoze(safeBoolean(parser, DEVICE_EFFECT_MAXIMIZE_DOZE, false)) - .setUserModifiedFields(safeInt(parser, DEVICE_EFFECT_USER_MODIFIED_FIELDS, 0)) .build(); return deviceEffects.hasEffects() ? deviceEffects : null; @@ -1108,8 +1111,6 @@ public class ZenModeConfig implements Parcelable { writeBooleanIfTrue(out, DEVICE_EFFECT_MINIMIZE_RADIO_USAGE, deviceEffects.shouldMinimizeRadioUsage()); writeBooleanIfTrue(out, DEVICE_EFFECT_MAXIMIZE_DOZE, deviceEffects.shouldMaximizeDoze()); - out.attributeInt(null, DEVICE_EFFECT_USER_MODIFIED_FIELDS, - deviceEffects.getUserModifiedFields()); } private static void writeBooleanIfTrue(TypedXmlSerializer out, String att, boolean value) @@ -2041,7 +2042,9 @@ public class ZenModeConfig implements Parcelable { public String triggerDescription; public String iconResName; public boolean allowManualInvocation; - public int userModifiedFields; + @AutomaticZenRule.ModifiableField public int userModifiedFields; + @ZenPolicy.ModifiableField public int zenPolicyUserModifiedFields; + @ZenDeviceEffects.ModifiableField public int zenDeviceEffectsUserModifiedFields; @Nullable public Instant deletionInstant; // Only set on deleted rules. public ZenRule() { } @@ -2076,6 +2079,8 @@ public class ZenModeConfig implements Parcelable { triggerDescription = source.readString(); type = source.readInt(); userModifiedFields = source.readInt(); + zenPolicyUserModifiedFields = source.readInt(); + zenDeviceEffectsUserModifiedFields = source.readInt(); if (source.readInt() == 1) { deletionInstant = Instant.ofEpochMilli(source.readLong()); } @@ -2083,15 +2088,21 @@ public class ZenModeConfig implements Parcelable { } /** - * @see AutomaticZenRule#canUpdate() + * Whether this ZenRule can be updated by an app. In general, rules that have been + * customized by the user cannot be further updated by an app, with some exceptions: + * <ul> + * <li>Non user-configurable fields, like type, icon, configurationActivity, etc. + * <li>Name, if the name was not specifically modified by the user (to support language + * switches). + * </ul> */ @FlaggedApi(Flags.FLAG_MODES_API) public boolean canBeUpdatedByApp() { // The rule is considered updateable if its bitmask has no user modifications, and // the bitmasks of the policy and device effects have no modification. return userModifiedFields == 0 - && (zenPolicy == null || zenPolicy.getUserModifiedFields() == 0) - && (zenDeviceEffects == null || zenDeviceEffects.getUserModifiedFields() == 0); + && zenPolicyUserModifiedFields == 0 + && zenDeviceEffectsUserModifiedFields == 0; } @Override @@ -2139,6 +2150,8 @@ public class ZenModeConfig implements Parcelable { dest.writeString(triggerDescription); dest.writeInt(type); dest.writeInt(userModifiedFields); + dest.writeInt(zenPolicyUserModifiedFields); + dest.writeInt(zenDeviceEffectsUserModifiedFields); if (deletionInstant != null) { dest.writeInt(1); dest.writeLong(deletionInstant.toEpochMilli()); @@ -2173,8 +2186,20 @@ public class ZenModeConfig implements Parcelable { .append(",allowManualInvocation=").append(allowManualInvocation) .append(",iconResName=").append(iconResName) .append(",triggerDescription=").append(triggerDescription) - .append(",type=").append(type) - .append(",userModifiedFields=").append(userModifiedFields); + .append(",type=").append(type); + if (userModifiedFields != 0) { + sb.append(",userModifiedFields=") + .append(AutomaticZenRule.fieldsToString(userModifiedFields)); + } + if (zenPolicyUserModifiedFields != 0) { + sb.append(",zenPolicyUserModifiedFields=") + .append(ZenPolicy.fieldsToString(zenPolicyUserModifiedFields)); + } + if (zenDeviceEffectsUserModifiedFields != 0) { + sb.append(",zenDeviceEffectsUserModifiedFields=") + .append(ZenDeviceEffects.fieldsToString( + zenDeviceEffectsUserModifiedFields)); + } if (deletionInstant != null) { sb.append(",deletionInstant=").append(deletionInstant); } @@ -2238,6 +2263,9 @@ public class ZenModeConfig implements Parcelable { && Objects.equals(other.triggerDescription, triggerDescription) && other.type == type && other.userModifiedFields == userModifiedFields + && other.zenPolicyUserModifiedFields == zenPolicyUserModifiedFields + && other.zenDeviceEffectsUserModifiedFields + == zenDeviceEffectsUserModifiedFields && Objects.equals(other.deletionInstant, deletionInstant); } @@ -2250,7 +2278,8 @@ public class ZenModeConfig implements Parcelable { return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition, component, configurationActivity, pkg, id, enabler, zenPolicy, zenDeviceEffects, modified, allowManualInvocation, iconResName, - triggerDescription, type, userModifiedFields, deletionInstant); + triggerDescription, type, userModifiedFields, zenPolicyUserModifiedFields, + zenDeviceEffectsUserModifiedFields, deletionInstant); } return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition, component, configurationActivity, pkg, id, enabler, zenPolicy, modified); diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java index 2cda7c882cdb..fb491d010f54 100644 --- a/core/java/android/service/notification/ZenPolicy.java +++ b/core/java/android/service/notification/ZenPolicy.java @@ -45,8 +45,8 @@ import java.util.Objects; */ public final class ZenPolicy implements Parcelable { - /** Used to track which rule variables have been modified by the user. - * Should be checked against the bitmask {@link #getUserModifiedFields()}. + /** + * Enum for the user-modifiable fields in this object. * @hide */ @IntDef(flag = true, prefix = { "FIELD_" }, value = { @@ -76,7 +76,6 @@ public final class ZenPolicy implements Parcelable { * the same time. * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_MESSAGES = 1 << 0; /** @@ -84,7 +83,6 @@ public final class ZenPolicy implements Parcelable { * the same time. * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_CALLS = 1 << 1; /** @@ -92,13 +90,11 @@ public final class ZenPolicy implements Parcelable { * set at the same time. * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_CONVERSATIONS = 1 << 2; /** * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_ALLOW_CHANNELS = 1 << 3; /** @@ -109,73 +105,61 @@ public final class ZenPolicy implements Parcelable { /** * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_PRIORITY_CATEGORY_EVENTS = 1 << 5; /** * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_PRIORITY_CATEGORY_REPEAT_CALLERS = 1 << 6; /** * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_PRIORITY_CATEGORY_ALARMS = 1 << 7; /** * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_PRIORITY_CATEGORY_MEDIA = 1 << 8; /** * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_PRIORITY_CATEGORY_SYSTEM = 1 << 9; /** * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_VISUAL_EFFECT_FULL_SCREEN_INTENT = 1 << 10; /** * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_VISUAL_EFFECT_LIGHTS = 1 << 11; /** * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_VISUAL_EFFECT_PEEK = 1 << 12; /** * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_VISUAL_EFFECT_STATUS_BAR = 1 << 13; /** * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_VISUAL_EFFECT_BADGE = 1 << 14; /** * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_VISUAL_EFFECT_AMBIENT = 1 << 15; /** * @hide */ - @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public static final int FIELD_VISUAL_EFFECT_NOTIFICATION_LIST = 1 << 16; @@ -186,7 +170,6 @@ public final class ZenPolicy implements Parcelable { private @ConversationSenders int mConversationSenders = CONVERSATION_SENDERS_UNSET; @FlaggedApi(Flags.FLAG_MODES_API) private @ChannelType int mAllowChannels = CHANNEL_POLICY_UNSET; - private final @ModifiableField int mUserModifiedFields; // Bitwise representation /** @hide */ @IntDef(prefix = { "PRIORITY_CATEGORY_" }, value = { @@ -388,22 +371,19 @@ public final class ZenPolicy implements Parcelable { public ZenPolicy() { mPriorityCategories = new ArrayList<>(Collections.nCopies(NUM_PRIORITY_CATEGORIES, 0)); mVisualEffects = new ArrayList<>(Collections.nCopies(NUM_VISUAL_EFFECTS, 0)); - mUserModifiedFields = 0; } /** @hide */ @FlaggedApi(Flags.FLAG_MODES_API) public ZenPolicy(List<Integer> priorityCategories, List<Integer> visualEffects, @PeopleType int priorityMessages, @PeopleType int priorityCalls, - @ConversationSenders int conversationSenders, @ChannelType int allowChannels, - @ModifiableField int userModifiedFields) { + @ConversationSenders int conversationSenders, @ChannelType int allowChannels) { mPriorityCategories = priorityCategories; mVisualEffects = visualEffects; mPriorityMessages = priorityMessages; mPriorityCalls = priorityCalls; mConversationSenders = conversationSenders; mAllowChannels = allowChannels; - mUserModifiedFields = userModifiedFields; } /** @@ -633,8 +613,6 @@ public final class ZenPolicy implements Parcelable { * is not set, it is (@link STATE_UNSET} and will not change the current set policy. */ public static final class Builder { - private @ModifiableField int mUserModifiedFields; - private ZenPolicy mZenPolicy; public Builder() { @@ -649,9 +627,6 @@ public final class ZenPolicy implements Parcelable { public Builder(@Nullable ZenPolicy policy) { if (policy != null) { mZenPolicy = policy.copy(); - if (Flags.modesApi()) { - mUserModifiedFields = policy.mUserModifiedFields; - } } else { mZenPolicy = new ZenPolicy(); } @@ -662,11 +637,10 @@ public final class ZenPolicy implements Parcelable { */ public @NonNull ZenPolicy build() { if (Flags.modesApi()) { - return new ZenPolicy(new ArrayList<Integer>(mZenPolicy.mPriorityCategories), - new ArrayList<Integer>(mZenPolicy.mVisualEffects), + return new ZenPolicy(new ArrayList<>(mZenPolicy.mPriorityCategories), + new ArrayList<>(mZenPolicy.mVisualEffects), mZenPolicy.mPriorityMessages, mZenPolicy.mPriorityCalls, - mZenPolicy.mConversationSenders, mZenPolicy.mAllowChannels, - mUserModifiedFields); + mZenPolicy.mConversationSenders, mZenPolicy.mAllowChannels); } else { return mZenPolicy.copy(); } @@ -1025,28 +999,6 @@ public final class ZenPolicy implements Parcelable { mZenPolicy.mAllowChannels = allow ? CHANNEL_POLICY_PRIORITY : CHANNEL_POLICY_NONE; return this; } - - /** - * Sets the user modified fields bitmask. - * @hide - */ - @TestApi - @FlaggedApi(Flags.FLAG_MODES_API) - public @NonNull Builder setUserModifiedFields(@ModifiableField int userModifiedFields) { - mUserModifiedFields = userModifiedFields; - return this; - } - } - - /** - Gets the bitmask representing which fields are user modified. Bits are set using - * {@link ModifiableField}. - * @hide - */ - @TestApi - @FlaggedApi(Flags.FLAG_MODES_API) - public @ModifiableField int getUserModifiedFields() { - return mUserModifiedFields; } @Override @@ -1063,7 +1015,6 @@ public final class ZenPolicy implements Parcelable { dest.writeInt(mConversationSenders); if (Flags.modesApi()) { dest.writeInt(mAllowChannels); - dest.writeInt(mUserModifiedFields); } } @@ -1079,7 +1030,7 @@ public final class ZenPolicy implements Parcelable { trimList(source.readArrayList(Integer.class.getClassLoader(), Integer.class), NUM_VISUAL_EFFECTS), source.readInt(), source.readInt(), source.readInt(), - source.readInt(), source.readInt() + source.readInt() ); } else { policy = new ZenPolicy(); @@ -1114,14 +1065,12 @@ public final class ZenPolicy implements Parcelable { conversationTypeToString(mConversationSenders)); if (Flags.modesApi()) { sb.append(", allowChannels=").append(channelTypeToString(mAllowChannels)); - sb.append(", userModifiedFields=") - .append(modifiedFieldsToString(mUserModifiedFields)); } return sb.append('}').toString(); } - @FlaggedApi(Flags.FLAG_MODES_API) - private String modifiedFieldsToString(@ModifiableField int bitmask) { + /** @hide */ + public static String fieldsToString(@ModifiableField int bitmask) { ArrayList<String> modified = new ArrayList<>(); if ((bitmask & FIELD_MESSAGES) != 0) { modified.add("FIELD_MESSAGES"); @@ -1332,8 +1281,7 @@ public final class ZenPolicy implements Parcelable { && other.mPriorityMessages == mPriorityMessages && other.mConversationSenders == mConversationSenders; if (Flags.modesApi()) { - return eq && other.mAllowChannels == mAllowChannels - && other.mUserModifiedFields == mUserModifiedFields; + return eq && other.mAllowChannels == mAllowChannels; } return eq; } @@ -1342,7 +1290,7 @@ public final class ZenPolicy implements Parcelable { public int hashCode() { if (Flags.modesApi()) { return Objects.hash(mPriorityCategories, mVisualEffects, mPriorityCalls, - mPriorityMessages, mConversationSenders, mAllowChannels, mUserModifiedFields); + mPriorityMessages, mConversationSenders, mAllowChannels); } return Objects.hash(mPriorityCategories, mVisualEffects, mPriorityCalls, mPriorityMessages, mConversationSenders); diff --git a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java index 9d85b65d4dac..1925588e8904 100644 --- a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java +++ b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java @@ -16,8 +16,6 @@ package android.app; -import static com.google.common.truth.Truth.assertThat; - import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.fail; @@ -28,8 +26,6 @@ import android.net.Uri; import android.os.Parcel; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; -import android.service.notification.ZenDeviceEffects; -import android.service.notification.ZenPolicy; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -230,66 +226,4 @@ public class AutomaticZenRuleTest { assertThrows(IllegalArgumentException.class, () -> builder.setType(100)); } - - @Test - @EnableFlags(Flags.FLAG_MODES_API) - public void testCanUpdate_nullPolicyAndDeviceEffects() { - AutomaticZenRule.Builder builder = new AutomaticZenRule.Builder("name", - Uri.parse("uri://short")); - - AutomaticZenRule rule = builder.setUserModifiedFields(0) - .setZenPolicy(null) - .setDeviceEffects(null) - .build(); - - assertThat(rule.canUpdate()).isTrue(); - - rule = builder.setUserModifiedFields(1).build(); - assertThat(rule.canUpdate()).isFalse(); - } - - @Test - @EnableFlags(Flags.FLAG_MODES_API) - public void testCanUpdate_policyModified() { - ZenPolicy.Builder policyBuilder = new ZenPolicy.Builder().setUserModifiedFields(0); - ZenPolicy policy = policyBuilder.build(); - - AutomaticZenRule.Builder builder = new AutomaticZenRule.Builder("name", - Uri.parse("uri://short")); - AutomaticZenRule rule = builder.setUserModifiedFields(0) - .setZenPolicy(policy) - .setDeviceEffects(null).build(); - - // Newly created ZenPolicy is not user modified. - assertThat(policy.getUserModifiedFields()).isEqualTo(0); - assertThat(rule.canUpdate()).isTrue(); - - policy = policyBuilder.setUserModifiedFields(1).build(); - assertThat(policy.getUserModifiedFields()).isEqualTo(1); - rule = builder.setZenPolicy(policy).build(); - assertThat(rule.canUpdate()).isFalse(); - } - - @Test - @EnableFlags(Flags.FLAG_MODES_API) - public void testCanUpdate_deviceEffectsModified() { - ZenDeviceEffects.Builder deviceEffectsBuilder = - new ZenDeviceEffects.Builder().setUserModifiedFields(0); - ZenDeviceEffects deviceEffects = deviceEffectsBuilder.build(); - - AutomaticZenRule.Builder builder = new AutomaticZenRule.Builder("name", - Uri.parse("uri://short")); - AutomaticZenRule rule = builder.setUserModifiedFields(0) - .setZenPolicy(null) - .setDeviceEffects(deviceEffects).build(); - - // Newly created ZenDeviceEffects is not user modified. - assertThat(deviceEffects.getUserModifiedFields()).isEqualTo(0); - assertThat(rule.canUpdate()).isTrue(); - - deviceEffects = deviceEffectsBuilder.setUserModifiedFields(1).build(); - assertThat(deviceEffects.getUserModifiedFields()).isEqualTo(1); - rule = builder.setDeviceEffects(deviceEffects).build(); - assertThat(rule.canUpdate()).isFalse(); - } } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index c7f570353a5b..1f3fe3f0fcb9 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -32,6 +32,7 @@ import static android.service.notification.ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR import static android.service.notification.ZenModeConfig.UPDATE_ORIGIN_USER; import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE; +import static com.android.internal.util.Preconditions.checkArgument; import android.annotation.DrawableRes; import android.annotation.NonNull; @@ -427,6 +428,7 @@ public class ZenModeHelper { public String addAutomaticZenRule(String pkg, AutomaticZenRule automaticZenRule, @ConfigChangeOrigin int origin, String reason, int callingUid) { + requirePublicOrigin("addAutomaticZenRule", origin); if (!ZenModeConfig.SYSTEM_AUTHORITY.equals(pkg)) { PackageItemInfo component = getServiceInfo(automaticZenRule.getOwner()); if (component == null) { @@ -525,6 +527,7 @@ public class ZenModeHelper { public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule, @ConfigChangeOrigin int origin, String reason, int callingUid) { + requirePublicOrigin("updateAutomaticZenRule", origin); ZenModeConfig newConfig; synchronized (mConfigLock) { if (mConfig == null) return false; @@ -726,6 +729,7 @@ public class ZenModeHelper { boolean removeAutomaticZenRule(String id, @ConfigChangeOrigin int origin, String reason, int callingUid) { + requirePublicOrigin("removeAutomaticZenRule", origin); ZenModeConfig newConfig; synchronized (mConfigLock) { if (mConfig == null) return false; @@ -758,6 +762,7 @@ public class ZenModeHelper { boolean removeAutomaticZenRules(String packageName, @ConfigChangeOrigin int origin, String reason, int callingUid) { + requirePublicOrigin("removeAutomaticZenRules", origin); ZenModeConfig newConfig; synchronized (mConfigLock) { if (mConfig == null) return false; @@ -806,6 +811,7 @@ public class ZenModeHelper { void setAutomaticZenRuleState(String id, Condition condition, @ConfigChangeOrigin int origin, int callingUid) { + requirePublicOrigin("setAutomaticZenRuleState", origin); ZenModeConfig newConfig; synchronized (mConfigLock) { if (mConfig == null) return; @@ -819,6 +825,7 @@ public class ZenModeHelper { void setAutomaticZenRuleState(Uri ruleDefinition, Condition condition, @ConfigChangeOrigin int origin, int callingUid) { + requirePublicOrigin("setAutomaticZenRuleState", origin); ZenModeConfig newConfig; synchronized (mConfigLock) { if (mConfig == null) return; @@ -988,7 +995,7 @@ public class ZenModeHelper { return null; } - void populateZenRule(String pkg, AutomaticZenRule automaticZenRule, ZenRule rule, + private void populateZenRule(String pkg, AutomaticZenRule automaticZenRule, ZenRule rule, @ConfigChangeOrigin int origin, boolean isNew) { if (Flags.modesApi()) { // These values can always be edited by the app, so we apply changes immediately. @@ -1053,11 +1060,9 @@ public class ZenModeHelper { rule.zenMode = newZenMode; // Updates the bitmask and values for all policy fields, based on the origin. - rule.zenPolicy = updatePolicy(rule.zenPolicy, automaticZenRule.getZenPolicy(), - updateBitmask); + updatePolicy(rule, automaticZenRule.getZenPolicy(), updateBitmask); // Updates the bitmask and values for all device effect fields, based on the origin. - rule.zenDeviceEffects = updateZenDeviceEffects( - rule.zenDeviceEffects, automaticZenRule.getDeviceEffects(), + updateZenDeviceEffects(rule, automaticZenRule.getDeviceEffects(), origin == UPDATE_ORIGIN_APP, updateBitmask); } else { if (rule.enabled != automaticZenRule.isEnabled()) { @@ -1069,13 +1074,6 @@ public class ZenModeHelper { rule.enabled = automaticZenRule.isEnabled(); rule.modified = automaticZenRule.isModified(); rule.zenPolicy = automaticZenRule.getZenPolicy(); - if (Flags.modesApi()) { - rule.zenDeviceEffects = updateZenDeviceEffects( - rule.zenDeviceEffects, - automaticZenRule.getDeviceEffects(), - origin == UPDATE_ORIGIN_APP, - origin == UPDATE_ORIGIN_USER); - } rule.zenMode = NotificationManager.zenModeFromInterruptionFilter( automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF); rule.configurationActivity = automaticZenRule.getConfigurationActivity(); @@ -1099,28 +1097,28 @@ public class ZenModeHelper { } /** - * Modifies {@link ZenPolicy} that is being stored as part of a new or updated ZenRule. - * Returns a policy based on {@code oldPolicy}, but with fields updated to match - * {@code newPolicy} where they differ, and updating the internal user-modified bitmask to - * track these changes, if applicable based on {@code origin}. + * 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). */ - @Nullable - private ZenPolicy updatePolicy(@Nullable ZenPolicy oldPolicy, @Nullable ZenPolicy newPolicy, - boolean updateBitmask) { - // If the update is to make the policy null, we don't need to update the bitmask, - // because it won't be stored anywhere anyway. + private void updatePolicy(ZenRule zenRule, @Nullable ZenPolicy newPolicy, + boolean updateBitmask) { if (newPolicy == null) { - return null; + // TODO: b/319242206 - Treat as newPolicy == default policy and continue below. + zenRule.zenPolicy = null; + return; } // If oldPolicy is null, we compare against the default policy when determining which // fields in the bitmask should be marked as updated. - if (oldPolicy == null) { - oldPolicy = mDefaultConfig.toZenPolicy(); - } + ZenPolicy oldPolicy = + zenRule.zenPolicy != null ? zenRule.zenPolicy : mDefaultConfig.toZenPolicy(); + + zenRule.zenPolicy = newPolicy; - int userModifiedFields = oldPolicy.getUserModifiedFields(); if (updateBitmask) { + int userModifiedFields = zenRule.zenPolicyUserModifiedFields; if (oldPolicy.getPriorityMessageSenders() != newPolicy.getPriorityMessageSenders()) { userModifiedFields |= ZenPolicy.FIELD_MESSAGES; } @@ -1178,66 +1176,47 @@ public class ZenModeHelper { != newPolicy.getVisualEffectNotificationList()) { userModifiedFields |= ZenPolicy.FIELD_VISUAL_EFFECT_NOTIFICATION_LIST; } + zenRule.zenPolicyUserModifiedFields = userModifiedFields; } - - // After all bitmask changes have been made, sets the bitmask. - return new ZenPolicy.Builder(newPolicy).setUserModifiedFields(userModifiedFields).build(); } /** - * Modifies {@link ZenDeviceEffects} that are being stored as part of a new or updated ZenRule. - * Returns a {@link ZenDeviceEffects} based on {@code oldEffects}, but with fields updated to - * match {@code newEffects} where they differ, and updating the internal user-modified bitmask - * to track these changes, if applicable based on {@code origin}. - * <ul> - * <li> Apps cannot turn on hidden effects (those tagged as {@code @hide}) since they are - * intended for platform-specific rules (e.g. wearables). If it's a new rule, we blank them - * out; if it's an update, we preserve the previous values. - * </ul> + * Modifies the {@link ZenDeviceEffects} associated to a new or updated ZenRule. + * + * <p>The new value is {@code newEffects}, 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>Apps cannot turn on hidden effects (those tagged as {@code @hide}), so those fields are + * treated especially: for a new rule, they are blanked out; for an updated rule, previous + * values are preserved. */ - @Nullable - private static ZenDeviceEffects updateZenDeviceEffects(@Nullable ZenDeviceEffects oldEffects, - @Nullable ZenDeviceEffects newEffects, - boolean isFromApp, - boolean updateBitmask) { + private static void updateZenDeviceEffects(ZenRule zenRule, + @Nullable ZenDeviceEffects newEffects, boolean isFromApp, boolean updateBitmask) { if (newEffects == null) { - return null; + zenRule.zenDeviceEffects = null; + return; } - // Since newEffects is not null, we want to adopt all the new provided device effects. - ZenDeviceEffects.Builder builder = new ZenDeviceEffects.Builder(newEffects); + ZenDeviceEffects oldEffects = zenRule.zenDeviceEffects != null + ? zenRule.zenDeviceEffects + : new ZenDeviceEffects.Builder().build(); if (isFromApp) { - if (oldEffects != null) { - // We can do this because we know we don't need to update the bitmask FROM_APP. - return builder - .setShouldDisableAutoBrightness(oldEffects.shouldDisableAutoBrightness()) - .setShouldDisableTapToWake(oldEffects.shouldDisableTapToWake()) - .setShouldDisableTiltToWake(oldEffects.shouldDisableTiltToWake()) - .setShouldDisableTouch(oldEffects.shouldDisableTouch()) - .setShouldMinimizeRadioUsage(oldEffects.shouldMinimizeRadioUsage()) - .setShouldMaximizeDoze(oldEffects.shouldMaximizeDoze()) - .build(); - } else { - return builder - .setShouldDisableAutoBrightness(false) - .setShouldDisableTapToWake(false) - .setShouldDisableTiltToWake(false) - .setShouldDisableTouch(false) - .setShouldMinimizeRadioUsage(false) - .setShouldMaximizeDoze(false) - .build(); - } + // Don't allow apps to toggle hidden effects. + newEffects = new ZenDeviceEffects.Builder(newEffects) + .setShouldDisableAutoBrightness(oldEffects.shouldDisableAutoBrightness()) + .setShouldDisableTapToWake(oldEffects.shouldDisableTapToWake()) + .setShouldDisableTiltToWake(oldEffects.shouldDisableTiltToWake()) + .setShouldDisableTouch(oldEffects.shouldDisableTouch()) + .setShouldMinimizeRadioUsage(oldEffects.shouldMinimizeRadioUsage()) + .setShouldMaximizeDoze(oldEffects.shouldMaximizeDoze()) + .build(); } - // If oldEffects is null, we compare against the default device effects object when - // determining which fields in the bitmask should be marked as updated. - if (oldEffects == null) { - oldEffects = new ZenDeviceEffects.Builder().build(); - } + zenRule.zenDeviceEffects = newEffects; - int userModifiedFields = oldEffects.getUserModifiedFields(); if (updateBitmask) { + int userModifiedFields = zenRule.zenDeviceEffectsUserModifiedFields; if (oldEffects.shouldDisplayGrayscale() != newEffects.shouldDisplayGrayscale()) { userModifiedFields |= ZenDeviceEffects.FIELD_GRAYSCALE; } @@ -1270,11 +1249,8 @@ public class ZenModeHelper { if (oldEffects.shouldMaximizeDoze() != newEffects.shouldMaximizeDoze()) { userModifiedFields |= ZenDeviceEffects.FIELD_MAXIMIZE_DOZE; } + zenRule.zenDeviceEffectsUserModifiedFields = userModifiedFields; } - - // Since newEffects is not null, we want to adopt all the new provided device effects. - // Set the usermodifiedFields value separately, to reflect the updated bitmask. - return builder.setUserModifiedFields(userModifiedFields).build(); } private AutomaticZenRule zenRuleToAutomaticZenRule(ZenRule rule) { @@ -1293,7 +1269,6 @@ public class ZenModeHelper { .setOwner(rule.component) .setConfigurationActivity(rule.configurationActivity) .setTriggerDescription(rule.triggerDescription) - .setUserModifiedFields(rule.userModifiedFields) .build(); } else { azr = new AutomaticZenRule(rule.name, rule.component, @@ -2369,6 +2344,19 @@ public class ZenModeHelper { return null; } } + + /** Checks that the {@code origin} supplied to a ZenModeHelper "API" method makes sense. */ + private static void requirePublicOrigin(String method, @ConfigChangeOrigin int origin) { + if (!Flags.modesApi()) { + return; + } + checkArgument(origin == UPDATE_ORIGIN_APP || origin == UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI + || origin == UPDATE_ORIGIN_USER, + "Expected one of UPDATE_ORIGIN_APP, UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, or " + + "UPDATE_ORIGIN_USER for %s, but received '%s'.", + method, origin); + } + private final class Metrics extends Callback { private static final String COUNTER_MODE_PREFIX = "dnd_mode_"; private static final String COUNTER_TYPE_PREFIX = "dnd_type_"; diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenDeviceEffectsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenDeviceEffectsTest.java index 3d8ec2ec9277..f604f1e77cf4 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenDeviceEffectsTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenDeviceEffectsTest.java @@ -52,7 +52,6 @@ public class ZenDeviceEffectsTest extends UiServiceTestCase { .setShouldMaximizeDoze(true) .setShouldUseNightMode(false) .setShouldSuppressAmbientDisplay(false).setShouldSuppressAmbientDisplay(true) - .setUserModifiedFields(8) .build(); assertThat(deviceEffects.shouldDimWallpaper()).isTrue(); @@ -65,7 +64,6 @@ public class ZenDeviceEffectsTest extends UiServiceTestCase { assertThat(deviceEffects.shouldMinimizeRadioUsage()).isFalse(); assertThat(deviceEffects.shouldUseNightMode()).isFalse(); assertThat(deviceEffects.shouldSuppressAmbientDisplay()).isTrue(); - assertThat(deviceEffects.getUserModifiedFields()).isEqualTo(8); } @Test @@ -97,7 +95,6 @@ public class ZenDeviceEffectsTest extends UiServiceTestCase { .setShouldMinimizeRadioUsage(true) .setShouldUseNightMode(true) .setShouldSuppressAmbientDisplay(true) - .setUserModifiedFields(6) .build(); Parcel parcel = Parcel.obtain(); @@ -116,7 +113,6 @@ public class ZenDeviceEffectsTest extends UiServiceTestCase { assertThat(copy.shouldUseNightMode()).isTrue(); assertThat(copy.shouldSuppressAmbientDisplay()).isTrue(); assertThat(copy.shouldDisplayGrayscale()).isFalse(); - assertThat(copy.getUserModifiedFields()).isEqualTo(6); } @Test 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 db92719ecfd6..e523e79f6370 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java @@ -285,7 +285,6 @@ public class ZenModeConfigTest extends UiServiceTestCase { assertEquals(expected.getPriorityCallSenders(), actual.getPriorityCallSenders()); assertEquals(expected.getPriorityMessageSenders(), actual.getPriorityMessageSenders()); assertEquals(expected.getPriorityChannels(), actual.getPriorityChannels()); - assertEquals(expected.getUserModifiedFields(), actual.getUserModifiedFields()); } @Test @@ -342,45 +341,32 @@ public class ZenModeConfigTest extends UiServiceTestCase { ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); rule.zenPolicy = null; rule.zenDeviceEffects = null; - assertThat(rule.canBeUpdatedByApp()).isTrue(); rule.userModifiedFields = 1; + assertThat(rule.canBeUpdatedByApp()).isFalse(); } @Test public void testCanBeUpdatedByApp_policyModified() throws Exception { - ZenPolicy.Builder policyBuilder = new ZenPolicy.Builder().setUserModifiedFields(0); - ZenPolicy policy = policyBuilder.build(); - ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); - rule.zenPolicy = policy; - - assertThat(rule.userModifiedFields).isEqualTo(0); + rule.zenPolicy = new ZenPolicy(); assertThat(rule.canBeUpdatedByApp()).isTrue(); - policy = policyBuilder.setUserModifiedFields(1).build(); - assertThat(policy.getUserModifiedFields()).isEqualTo(1); - rule.zenPolicy = policy; + rule.zenPolicyUserModifiedFields = 1; + assertThat(rule.canBeUpdatedByApp()).isFalse(); } @Test public void testCanBeUpdatedByApp_deviceEffectsModified() throws Exception { - ZenDeviceEffects.Builder deviceEffectsBuilder = - new ZenDeviceEffects.Builder().setUserModifiedFields(0); - ZenDeviceEffects deviceEffects = deviceEffectsBuilder.build(); - ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); - rule.zenDeviceEffects = deviceEffects; - - assertThat(rule.userModifiedFields).isEqualTo(0); + rule.zenDeviceEffects = new ZenDeviceEffects.Builder().build(); assertThat(rule.canBeUpdatedByApp()).isTrue(); - deviceEffects = deviceEffectsBuilder.setUserModifiedFields(1).build(); - assertThat(deviceEffects.getUserModifiedFields()).isEqualTo(1); - rule.zenDeviceEffects = deviceEffects; + rule.zenDeviceEffectsUserModifiedFields = 1; + assertThat(rule.canBeUpdatedByApp()).isFalse(); } @@ -406,6 +392,8 @@ public class ZenModeConfigTest extends UiServiceTestCase { rule.allowManualInvocation = ALLOW_MANUAL; rule.type = TYPE; rule.userModifiedFields = 16; + rule.zenPolicyUserModifiedFields = 5; + rule.zenDeviceEffectsUserModifiedFields = 2; rule.iconResName = ICON_RES_NAME; rule.triggerDescription = TRIGGER_DESC; rule.deletionInstant = Instant.ofEpochMilli(1701790147000L); @@ -432,6 +420,9 @@ public class ZenModeConfigTest extends UiServiceTestCase { assertEquals(rule.iconResName, parceled.iconResName); assertEquals(rule.type, parceled.type); assertEquals(rule.userModifiedFields, parceled.userModifiedFields); + assertEquals(rule.zenPolicyUserModifiedFields, parceled.zenPolicyUserModifiedFields); + assertEquals(rule.zenDeviceEffectsUserModifiedFields, + parceled.zenDeviceEffectsUserModifiedFields); assertEquals(rule.triggerDescription, parceled.triggerDescription); assertEquals(rule.zenPolicy, parceled.zenPolicy); assertEquals(rule.deletionInstant, parceled.deletionInstant); @@ -511,6 +502,8 @@ public class ZenModeConfigTest extends UiServiceTestCase { rule.allowManualInvocation = ALLOW_MANUAL; rule.type = TYPE; rule.userModifiedFields = 4; + rule.zenPolicyUserModifiedFields = 5; + rule.zenDeviceEffectsUserModifiedFields = 2; rule.iconResName = ICON_RES_NAME; rule.triggerDescription = TRIGGER_DESC; rule.deletionInstant = Instant.ofEpochMilli(1701790147000L); @@ -541,6 +534,9 @@ public class ZenModeConfigTest extends UiServiceTestCase { assertEquals(rule.allowManualInvocation, fromXml.allowManualInvocation); assertEquals(rule.type, fromXml.type); assertEquals(rule.userModifiedFields, fromXml.userModifiedFields); + assertEquals(rule.zenPolicyUserModifiedFields, fromXml.zenPolicyUserModifiedFields); + assertEquals(rule.zenDeviceEffectsUserModifiedFields, + fromXml.zenDeviceEffectsUserModifiedFields); assertEquals(rule.triggerDescription, fromXml.triggerDescription); assertEquals(rule.iconResName, fromXml.iconResName); assertEquals(rule.deletionInstant, fromXml.deletionInstant); @@ -697,7 +693,6 @@ public class ZenModeConfigTest extends UiServiceTestCase { .allowPriorityChannels(false) .hideAllVisualEffects() .showVisualEffect(ZenPolicy.VISUAL_EFFECT_AMBIENT, true) - .setUserModifiedFields(4) .build(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -732,7 +727,6 @@ public class ZenModeConfigTest extends UiServiceTestCase { assertEquals(policy.getVisualEffectAmbient(), fromXml.getVisualEffectAmbient()); assertEquals(policy.getVisualEffectNotificationList(), fromXml.getVisualEffectNotificationList()); - assertEquals(policy.getUserModifiedFields(), fromXml.getUserModifiedFields()); } private ZenModeConfig getMutedRingerConfig() { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java index 9d7cf53e62db..2e64645ecade 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java @@ -73,13 +73,15 @@ 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, deletionInstant) are not compared. + // "Metadata" fields (userModifiedFields & co, deletionInstant) are not compared. private static final Set<String> ZEN_RULE_EXEMPT_FIELDS = android.app.Flags.modesApi() - ? Set.of("userModifiedFields", "deletionInstant") + ? Set.of("userModifiedFields", "zenPolicyUserModifiedFields", + "zenDeviceEffectsUserModifiedFields", "deletionInstant") : 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"); // allowPriorityChannels is flagged by android.app.modes_api 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 78fe41f31849..f71c8b41e219 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -2236,12 +2236,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { AutomaticZenRule savedRule = mZenModeHelper.getAutomaticZenRule(ruleId); - // savedRule.getDeviceEffects() is equal to zde, except for the userModifiedFields. - // So we clear before comparing. - ZenDeviceEffects savedEffects = new ZenDeviceEffects.Builder(savedRule.getDeviceEffects()) - .setUserModifiedFields(0).build(); - - assertThat(savedEffects).isEqualTo(zde); + assertThat(savedRule.getDeviceEffects()).isEqualTo(zde); } @Test @@ -2331,12 +2326,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { AutomaticZenRule savedRule = mZenModeHelper.getAutomaticZenRule(ruleId); - // savedRule.getDeviceEffects() is equal to updateFromUser, except for the - // userModifiedFields, so we clear before comparing. - ZenDeviceEffects savedEffects = new ZenDeviceEffects.Builder(savedRule.getDeviceEffects()) - .setUserModifiedFields(0).build(); - - assertThat(savedEffects).isEqualTo(updateFromUser); + assertThat(savedRule.getDeviceEffects()).isEqualTo(updateFromUser); } @Test @@ -3411,7 +3401,6 @@ public class ZenModeHelperTest extends UiServiceTestCase { rule.allowManualInvocation = ALLOW_MANUAL; rule.type = TYPE; - rule.userModifiedFields = AutomaticZenRule.FIELD_NAME; rule.iconResName = ICON_RES_NAME; rule.triggerDescription = TRIGGER_DESC; @@ -3426,7 +3415,6 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertEquals(POLICY, actual.getZenPolicy()); assertEquals(CONFIG_ACTIVITY, actual.getConfigurationActivity()); assertEquals(TYPE, actual.getType()); - assertEquals(AutomaticZenRule.FIELD_NAME, actual.getUserModifiedFields()); assertEquals(ALLOW_MANUAL, actual.isManualInvocationAllowed()); assertEquals(CREATION_TIME, actual.getCreationTime()); assertEquals(OWNER.getPackageName(), actual.getPackageName()); @@ -3453,29 +3441,31 @@ public class ZenModeHelperTest extends UiServiceTestCase { .setManualInvocationAllowed(ALLOW_MANUAL) .build(); - ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); - - mZenModeHelper.populateZenRule(OWNER.getPackageName(), azr, rule, UPDATE_ORIGIN_APP, true); - - assertEquals(NAME, rule.name); - assertEquals(OWNER, rule.component); - assertEquals(CONDITION_ID, rule.conditionId); - assertEquals(INTERRUPTION_FILTER_ZR, rule.zenMode); - assertEquals(ENABLED, rule.enabled); - assertEquals(POLICY, rule.zenPolicy); - assertEquals(CONFIG_ACTIVITY, rule.configurationActivity); - assertEquals(TYPE, rule.type); - assertEquals(ALLOW_MANUAL, rule.allowManualInvocation); - assertEquals(OWNER.getPackageName(), rule.getPkg()); - assertEquals(ICON_RES_NAME, rule.iconResName); + String ruleId = mZenModeHelper.addAutomaticZenRule(OWNER.getPackageName(), azr, + UPDATE_ORIGIN_APP, "add", CUSTOM_PKG_UID); + + ZenModeConfig.ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId); + + assertThat(storedRule).isNotNull(); + assertEquals(NAME, storedRule.name); + assertEquals(OWNER, storedRule.component); + assertEquals(CONDITION_ID, storedRule.conditionId); + assertEquals(INTERRUPTION_FILTER_ZR, storedRule.zenMode); + assertEquals(ENABLED, storedRule.enabled); + assertEquals(POLICY, storedRule.zenPolicy); + assertEquals(CONFIG_ACTIVITY, storedRule.configurationActivity); + assertEquals(TYPE, storedRule.type); + assertEquals(ALLOW_MANUAL, storedRule.allowManualInvocation); + assertEquals(OWNER.getPackageName(), storedRule.getPkg()); + assertEquals(ICON_RES_NAME, storedRule.iconResName); // Because the origin of the update is the app, we don't expect the bitmask to change. - assertEquals(0, rule.userModifiedFields); - assertEquals(TRIGGER_DESC, rule.triggerDescription); + assertEquals(0, storedRule.userModifiedFields); + assertEquals(TRIGGER_DESC, storedRule.triggerDescription); } @Test @EnableFlags(Flags.FLAG_MODES_API) - public void automaticZenRuleToZenRule_updatesNameUnlessUserModified() { + public void updateAutomaticZenRule_fromApp_updatesNameUnlessUserModified() { // Add a starting rule with the name OriginalName. AutomaticZenRule azrBase = new AutomaticZenRule.Builder("OriginalName", CONDITION_ID) .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) @@ -3492,7 +3482,6 @@ public class ZenModeHelperTest extends UiServiceTestCase { Process.SYSTEM_UID); rule = mZenModeHelper.getAutomaticZenRule(ruleId); assertThat(rule.getName()).isEqualTo("NewName"); - assertThat(rule.canUpdate()).isTrue(); // The user modifies some other field in the rule, which makes the rule as a whole not // app modifiable. @@ -3501,10 +3490,6 @@ public class ZenModeHelperTest extends UiServiceTestCase { .build(); mZenModeHelper.updateAutomaticZenRule(ruleId, azrUpdate, UPDATE_ORIGIN_USER, "reason", Process.SYSTEM_UID); - rule = mZenModeHelper.getAutomaticZenRule(ruleId); - assertThat(rule.getUserModifiedFields()) - .isEqualTo(AutomaticZenRule.FIELD_INTERRUPTION_FILTER); - assertThat(rule.canUpdate()).isFalse(); // ...but the app can still modify the name, because the name itself hasn't been modified // by the user. @@ -3524,8 +3509,6 @@ public class ZenModeHelperTest extends UiServiceTestCase { Process.SYSTEM_UID); rule = mZenModeHelper.getAutomaticZenRule(ruleId); assertThat(rule.getName()).isEqualTo("UserProvidedName"); - assertThat(rule.getUserModifiedFields()).isEqualTo(AutomaticZenRule.FIELD_NAME - | AutomaticZenRule.FIELD_INTERRUPTION_FILTER); // The app is no longer able to modify the name. azrUpdate = new AutomaticZenRule.Builder(rule) @@ -3539,7 +3522,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test @EnableFlags(Flags.FLAG_MODES_API) - public void automaticZenRuleToZenRule_updatesBitmaskAndValueForUserOrigin() { + public void updateAutomaticZenRule_fromUser_updatesBitmaskAndValue() { // Adds a starting rule with empty zen policies and device effects AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID) .setZenPolicy(new ZenPolicy.Builder().build()) @@ -3571,84 +3554,21 @@ 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.getUserModifiedFields()) - .isEqualTo(AutomaticZenRule.FIELD_INTERRUPTION_FILTER); - assertThat(rule.getZenPolicy().getUserModifiedFields()) - .isEqualTo(ZenPolicy.FIELD_ALLOW_CHANNELS); assertThat(rule.getZenPolicy().getPriorityChannels()).isEqualTo(ZenPolicy.STATE_ALLOW); - assertThat(rule.getDeviceEffects().getUserModifiedFields()) - .isEqualTo(ZenDeviceEffects.FIELD_GRAYSCALE); assertThat(rule.getDeviceEffects().shouldDisplayGrayscale()).isTrue(); - } - - @Test - @EnableFlags(Flags.FLAG_MODES_API) - public void automaticZenRuleToZenRule_doesNotUpdateValuesForInitUserOrigin() { - // Adds a starting rule with empty zen policies and device effects - AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID) - .setInterruptionFilter(INTERRUPTION_FILTER_ALL) // Already the default, no change - .setZenPolicy(new ZenPolicy.Builder() - .allowReminders(false) - .build()) - .setDeviceEffects(new ZenDeviceEffects.Builder() - .setShouldDisplayGrayscale(false) - .build()) - .build(); - // Adds the rule using the user, to set user-modified bits. - String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), - azrBase, UPDATE_ORIGIN_USER, "reason", Process.SYSTEM_UID); - AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId); - assertThat(rule.canUpdate()).isFalse(); - assertThat(rule.getUserModifiedFields()).isEqualTo(AutomaticZenRule.FIELD_NAME); - ZenPolicy policy = new ZenPolicy.Builder(rule.getZenPolicy()) - .allowReminders(true) - .build(); - ZenDeviceEffects deviceEffects = new ZenDeviceEffects.Builder(rule.getDeviceEffects()) - .setShouldDisplayGrayscale(true) - .build(); - AutomaticZenRule azrUpdate = new AutomaticZenRule.Builder(rule) - .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) - .setZenPolicy(policy) - .setDeviceEffects(deviceEffects) - .build(); - - // Attempts to update the rule with the AZR from origin init user. - mZenModeHelper.updateAutomaticZenRule(ruleId, azrUpdate, UPDATE_ORIGIN_INIT_USER, "reason", - Process.SYSTEM_UID); - AutomaticZenRule unchangedRule = mZenModeHelper.getAutomaticZenRule(ruleId); - - // UPDATE_ORIGIN_INIT_USER does not change the bitmask or values if rule is user modified. - // TODO: b/318506692 - Remove once we check that INIT origins can't call add/updateAZR. - assertThat(unchangedRule.getUserModifiedFields()).isEqualTo(rule.getUserModifiedFields()); - assertThat(unchangedRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALL); - assertThat(unchangedRule.getZenPolicy().getUserModifiedFields()).isEqualTo( - rule.getZenPolicy().getUserModifiedFields()); - assertThat(unchangedRule.getZenPolicy().getPriorityCategoryReminders()).isEqualTo( - ZenPolicy.STATE_DISALLOW); - assertThat(unchangedRule.getDeviceEffects().getUserModifiedFields()).isEqualTo( - rule.getDeviceEffects().getUserModifiedFields()); - assertThat(unchangedRule.getDeviceEffects().shouldDisplayGrayscale()).isFalse(); - - // Creates a new rule with the AZR from origin init user. - String newRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), - azrUpdate, UPDATE_ORIGIN_INIT_USER, "reason", Process.SYSTEM_UID); - AutomaticZenRule newRule = mZenModeHelper.getAutomaticZenRule(newRuleId); - - // UPDATE_ORIGIN_INIT_USER does change the values if the rule is new, - // but does not update the bitmask. - assertThat(newRule.getUserModifiedFields()).isEqualTo(0); - assertThat(newRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_PRIORITY); - assertThat(newRule.getZenPolicy().getUserModifiedFields()).isEqualTo(0); - assertThat(newRule.getZenPolicy().getPriorityCategoryReminders()) - .isEqualTo(ZenPolicy.STATE_ALLOW); - assertThat(newRule.getDeviceEffects().getUserModifiedFields()).isEqualTo(0); - assertThat(newRule.getDeviceEffects().shouldDisplayGrayscale()).isTrue(); + ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId); + assertThat(storedRule.userModifiedFields) + .isEqualTo(AutomaticZenRule.FIELD_INTERRUPTION_FILTER); + assertThat(storedRule.zenPolicyUserModifiedFields) + .isEqualTo(ZenPolicy.FIELD_ALLOW_CHANNELS); + assertThat(storedRule.zenDeviceEffectsUserModifiedFields) + .isEqualTo(ZenDeviceEffects.FIELD_GRAYSCALE); } @Test @EnableFlags(Flags.FLAG_MODES_API) - public void automaticZenRuleToZenRule_updatesValuesForSystemUiOrigin() { + public void updateAutomaticZenRule_fromSystemUi_updatesValues() { // Adds a starting rule with empty zen policies and device effects AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID) .setInterruptionFilter(INTERRUPTION_FILTER_ALL) @@ -3684,17 +3604,19 @@ public class ZenModeHelperTest extends UiServiceTestCase { rule = mZenModeHelper.getAutomaticZenRule(ruleId); // UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI should change the value but NOT update the bitmask. - assertThat(rule.getUserModifiedFields()).isEqualTo(0); - assertThat(rule.getZenPolicy().getUserModifiedFields()).isEqualTo(0); assertThat(rule.getZenPolicy().getPriorityCategoryReminders()) .isEqualTo(ZenPolicy.STATE_ALLOW); - assertThat(rule.getDeviceEffects().getUserModifiedFields()).isEqualTo(0); assertThat(rule.getDeviceEffects().shouldDisplayGrayscale()).isTrue(); + + ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId); + assertThat(storedRule.userModifiedFields).isEqualTo(0); + assertThat(storedRule.zenPolicyUserModifiedFields).isEqualTo(0); + assertThat(storedRule.zenDeviceEffectsUserModifiedFields).isEqualTo(0); } @Test @EnableFlags(Flags.FLAG_MODES_API) - public void automaticZenRuleToZenRule_updatesValuesIfRuleNotUserModified() { + public void updateAutomaticZenRule_fromApp_updatesValuesIfRuleNotUserModified() { // Adds a starting rule with empty zen policies and device effects AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID) .setInterruptionFilter(INTERRUPTION_FILTER_ALL) @@ -3709,7 +3631,6 @@ public class ZenModeHelperTest extends UiServiceTestCase { String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), azrBase, UPDATE_ORIGIN_APP, "reason", Process.SYSTEM_UID); AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId); - assertThat(rule.canUpdate()).isTrue(); ZenPolicy policy = new ZenPolicy.Builder() .allowReminders(true) @@ -3717,57 +3638,59 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenDeviceEffects deviceEffects = new ZenDeviceEffects.Builder() .setShouldDisplayGrayscale(true) .build(); - AutomaticZenRule azrUpdate = new AutomaticZenRule.Builder(rule) + AutomaticZenRule azrUpdate = new AutomaticZenRule.Builder(rule) .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS) .setZenPolicy(policy) .setDeviceEffects(deviceEffects) .build(); - // Since the rule is not already user modified, UPDATE_ORIGIN_UNKNOWN can modify the rule. + // Since the rule is not already user modified, UPDATE_ORIGIN_APP can modify the rule. // The bitmask is not modified. - mZenModeHelper.updateAutomaticZenRule(ruleId, azrUpdate, UPDATE_ORIGIN_UNKNOWN, "reason", + mZenModeHelper.updateAutomaticZenRule(ruleId, azrUpdate, UPDATE_ORIGIN_APP, "reason", Process.SYSTEM_UID); - AutomaticZenRule unchangedRule = mZenModeHelper.getAutomaticZenRule(ruleId); - assertThat(unchangedRule.getUserModifiedFields()).isEqualTo(rule.getUserModifiedFields()); - assertThat(unchangedRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALARMS); - assertThat(unchangedRule.getZenPolicy().getUserModifiedFields()).isEqualTo( - rule.getZenPolicy().getUserModifiedFields()); - assertThat(unchangedRule.getZenPolicy().getPriorityCategoryReminders()) + ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId); + assertThat(storedRule.userModifiedFields).isEqualTo(0); + + assertThat(storedRule.zenMode).isEqualTo(ZEN_MODE_ALARMS); + assertThat(storedRule.zenPolicy.getPriorityCategoryReminders()) .isEqualTo(ZenPolicy.STATE_ALLOW); - assertThat(unchangedRule.getDeviceEffects().getUserModifiedFields()).isEqualTo( - rule.getDeviceEffects().getUserModifiedFields()); - assertThat(unchangedRule.getDeviceEffects().shouldDisplayGrayscale()).isTrue(); + assertThat(storedRule.zenDeviceEffects.shouldDisplayGrayscale()).isTrue(); + assertThat(storedRule.userModifiedFields).isEqualTo(0); + assertThat(storedRule.zenPolicyUserModifiedFields).isEqualTo(0); + assertThat(storedRule.zenDeviceEffectsUserModifiedFields).isEqualTo(0); // Creates another rule, this time from user. This will have user modified bits set. String ruleIdUser = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), azrBase, UPDATE_ORIGIN_USER, "reason", Process.SYSTEM_UID); - AutomaticZenRule ruleUser = mZenModeHelper.getAutomaticZenRule(ruleIdUser); - assertThat(ruleUser.canUpdate()).isFalse(); + storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleIdUser); + int ruleModifiedFields = storedRule.userModifiedFields; + int rulePolicyModifiedFields = storedRule.zenPolicyUserModifiedFields; + int ruleDeviceEffectsModifiedFields = storedRule.zenDeviceEffectsUserModifiedFields; - // Zen rule update coming from unknown origin. This cannot fully update the rule, because + // Zen rule update coming from the app again. This cannot fully update the rule, because // the rule is already considered user modified. - mZenModeHelper.updateAutomaticZenRule(ruleIdUser, azrUpdate, UPDATE_ORIGIN_UNKNOWN, + mZenModeHelper.updateAutomaticZenRule(ruleIdUser, azrUpdate, UPDATE_ORIGIN_APP, "reason", Process.SYSTEM_UID); - ruleUser = mZenModeHelper.getAutomaticZenRule(ruleIdUser); + AutomaticZenRule ruleUser = mZenModeHelper.getAutomaticZenRule(ruleIdUser); - // UPDATE_ORIGIN_UNKNOWN can only change the value if the rule is not already user modified, + // The app can only change the value if the rule is not already user modified, // so the rule is not changed, and neither is the bitmask. assertThat(ruleUser.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALL); - // Interruption Filter All is the default value, so it's not included as a modified field. - assertThat(ruleUser.getUserModifiedFields() | AutomaticZenRule.FIELD_NAME).isGreaterThan(0); - assertThat(ruleUser.getZenPolicy().getUserModifiedFields() - | ZenPolicy.FIELD_PRIORITY_CATEGORY_REMINDERS).isGreaterThan(0); assertThat(ruleUser.getZenPolicy().getPriorityCategoryReminders()) .isEqualTo(ZenPolicy.STATE_DISALLOW); - assertThat(ruleUser.getDeviceEffects().getUserModifiedFields() - | ZenDeviceEffects.FIELD_GRAYSCALE).isGreaterThan(0); assertThat(ruleUser.getDeviceEffects().shouldDisplayGrayscale()).isFalse(); + + storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleIdUser); + assertThat(storedRule.userModifiedFields).isEqualTo(ruleModifiedFields); + assertThat(storedRule.zenPolicyUserModifiedFields).isEqualTo(rulePolicyModifiedFields); + assertThat(storedRule.zenDeviceEffectsUserModifiedFields).isEqualTo( + ruleDeviceEffectsModifiedFields); } @Test @EnableFlags(Flags.FLAG_MODES_API) - public void automaticZenRuleToZenRule_updatesValuesIfRuleNew() { + public void addAutomaticZenRule_updatesValues() { // Adds a starting rule with empty zen policies and device effects AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID) .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS) @@ -3778,21 +3701,22 @@ public class ZenModeHelperTest extends UiServiceTestCase { .setShouldDisplayGrayscale(true) .build()) .build(); - // Adds the rule using origin unknown, to show that a new rule is always allowed. String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), - azrBase, UPDATE_ORIGIN_UNKNOWN, "reason", Process.SYSTEM_UID); + azrBase, UPDATE_ORIGIN_APP, "reason", Process.SYSTEM_UID); AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId); // The values are modified but the bitmask is not. - assertThat(rule.canUpdate()).isTrue(); assertThat(rule.getZenPolicy().getPriorityCategoryReminders()) .isEqualTo(ZenPolicy.STATE_ALLOW); assertThat(rule.getDeviceEffects().shouldDisplayGrayscale()).isTrue(); + + ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId); + assertThat(storedRule.canBeUpdatedByApp()).isTrue(); } @Test @EnableFlags(Flags.FLAG_MODES_API) - public void automaticZenRuleToZenRule_nullDeviceEffectsUpdate() { + public void updateAutomaticZenRule_nullDeviceEffectsUpdate() { // Adds a starting rule with empty zen policies and device effects AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID) .setDeviceEffects(new ZenDeviceEffects.Builder().build()) @@ -3807,9 +3731,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { .setDeviceEffects(null) .build(); - // Zen rule update coming from unknown origin, but since the rule isn't already + // Zen rule update coming from app, but since the rule isn't already // user modified, it can be updated. - mZenModeHelper.updateAutomaticZenRule(ruleId, azr, UPDATE_ORIGIN_UNKNOWN, "reason", + mZenModeHelper.updateAutomaticZenRule(ruleId, azr, UPDATE_ORIGIN_APP, "reason", Process.SYSTEM_UID); rule = mZenModeHelper.getAutomaticZenRule(ruleId); @@ -3819,7 +3743,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test @EnableFlags(Flags.FLAG_MODES_API) - public void automaticZenRuleToZenRule_nullPolicyUpdate() { + public void updateAutomaticZenRule_nullPolicyUpdate() { // Adds a starting rule with empty zen policies and device effects AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID) .setZenPolicy(new ZenPolicy.Builder().build()) @@ -3828,16 +3752,15 @@ public class ZenModeHelperTest extends UiServiceTestCase { String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), azrBase, UPDATE_ORIGIN_APP, "reason", Process.SYSTEM_UID); AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId); - assertThat(rule.canUpdate()).isTrue(); AutomaticZenRule azr = new AutomaticZenRule.Builder(azrBase) // Set zen policy to null .setZenPolicy(null) .build(); - // Zen rule update coming from unknown origin, but since the rule isn't already + // Zen rule update coming from app, but since the rule isn't already // user modified, it can be updated. - mZenModeHelper.updateAutomaticZenRule(ruleId, azr, UPDATE_ORIGIN_UNKNOWN, "reason", + mZenModeHelper.updateAutomaticZenRule(ruleId, azr, UPDATE_ORIGIN_APP, "reason", Process.SYSTEM_UID); rule = mZenModeHelper.getAutomaticZenRule(ruleId); @@ -3859,7 +3782,6 @@ public class ZenModeHelperTest extends UiServiceTestCase { String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), azrBase, UPDATE_ORIGIN_APP, "reason", Process.SYSTEM_UID); AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId); - assertThat(rule.canUpdate()).isTrue(); // Create a fully populated ZenPolicy. ZenPolicy policy = new ZenPolicy.Builder() @@ -3894,8 +3816,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { // New ZenPolicy differs from the default config assertThat(rule.getZenPolicy()).isNotNull(); assertThat(rule.getZenPolicy().getPriorityChannels()).isEqualTo(ZenPolicy.STATE_DISALLOW); - assertThat(rule.canUpdate()).isFalse(); - assertThat(rule.getZenPolicy().getUserModifiedFields()).isEqualTo( + + ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId); + assertThat(storedRule.canBeUpdatedByApp()).isFalse(); + assertThat(storedRule.zenPolicyUserModifiedFields).isEqualTo( ZenPolicy.FIELD_ALLOW_CHANNELS | ZenPolicy.FIELD_PRIORITY_CATEGORY_REMINDERS | ZenPolicy.FIELD_PRIORITY_CATEGORY_EVENTS @@ -3918,7 +3842,6 @@ public class ZenModeHelperTest extends UiServiceTestCase { String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), azrBase, UPDATE_ORIGIN_APP, "reason", Process.SYSTEM_UID); AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId); - assertThat(rule.canUpdate()).isTrue(); ZenDeviceEffects deviceEffects = new ZenDeviceEffects.Builder() .setShouldDisplayGrayscale(true) @@ -3935,8 +3858,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { // New ZenDeviceEffects is used; all fields considered set, since previously were null. assertThat(rule.getDeviceEffects()).isNotNull(); assertThat(rule.getDeviceEffects().shouldDisplayGrayscale()).isTrue(); - assertThat(rule.canUpdate()).isFalse(); - assertThat(rule.getDeviceEffects().getUserModifiedFields()).isEqualTo( + + ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId); + assertThat(storedRule.canBeUpdatedByApp()).isFalse(); + assertThat(storedRule.zenDeviceEffectsUserModifiedFields).isEqualTo( ZenDeviceEffects.FIELD_GRAYSCALE); } @@ -4339,7 +4264,6 @@ public class ZenModeHelperTest extends UiServiceTestCase { String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule, UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID); assertThat(mZenModeHelper.getAutomaticZenRule(ruleId).getCreationTime()).isEqualTo(1000); - assertThat(mZenModeHelper.getAutomaticZenRule(ruleId).canUpdate()).isTrue(); // User customizes it. AutomaticZenRule userUpdate = new AutomaticZenRule.Builder(rule) @@ -4371,9 +4295,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertThat(finalRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALARMS); assertThat(finalRule.getZenPolicy().getPriorityCategoryRepeatCallers()).isEqualTo( ZenPolicy.STATE_ALLOW); - assertThat(finalRule.getUserModifiedFields()).isEqualTo( + + ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId); + assertThat(storedRule.userModifiedFields).isEqualTo( AutomaticZenRule.FIELD_INTERRUPTION_FILTER); - assertThat(finalRule.getZenPolicy().getUserModifiedFields()).isEqualTo( + assertThat(storedRule.zenPolicyUserModifiedFields).isEqualTo( ZenPolicy.FIELD_PRIORITY_CATEGORY_REPEAT_CALLERS); // Also, we discarded the "deleted rule" since we already used it for restoration. 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 7941eb4d2090..4ed55df7775c 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java @@ -645,38 +645,12 @@ public class ZenPolicyTest extends UiServiceTestCase { } @Test - public void testFromParcel() { - ZenPolicy.Builder builder = new ZenPolicy.Builder(); - builder.setUserModifiedFields(10); - - ZenPolicy policy = builder.build(); - assertThat(policy.getUserModifiedFields()).isEqualTo(10); - - Parcel parcel = Parcel.obtain(); - policy.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - - ZenPolicy fromParcel = ZenPolicy.CREATOR.createFromParcel(parcel); - assertThat(fromParcel.getUserModifiedFields()).isEqualTo(10); - } - - @Test - public void testPolicy_userModifiedFields() { - ZenPolicy.Builder builder = new ZenPolicy.Builder(); - builder.setUserModifiedFields(10); - assertThat(builder.build().getUserModifiedFields()).isEqualTo(10); - - builder.setUserModifiedFields(0); - assertThat(builder.build().getUserModifiedFields()).isEqualTo(0); - } - - @Test public void testPolicyBuilder_constructFromPolicy() { ZenPolicy.Builder builder = new ZenPolicy.Builder(); ZenPolicy policy = builder.allowRepeatCallers(true).allowAlarms(false) .showLights(true).showBadges(false) .allowPriorityChannels(true) - .setUserModifiedFields(20).build(); + .build(); ZenPolicy newPolicy = new ZenPolicy.Builder(policy).build(); @@ -689,7 +663,6 @@ public class ZenPolicyTest extends UiServiceTestCase { assertThat(newPolicy.getVisualEffectPeek()).isEqualTo(ZenPolicy.STATE_UNSET); assertThat(newPolicy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_ALLOW); - assertThat(newPolicy.getUserModifiedFields()).isEqualTo(20); } @Test |