Loading core/api/current.txt +8 −0 Original line number Diff line number Diff line Loading @@ -40545,19 +40545,26 @@ package android.service.notification { public final class Condition implements android.os.Parcelable { ctor public Condition(android.net.Uri, String, int); ctor @FlaggedApi("android.app.modes_api") public Condition(@Nullable android.net.Uri, @Nullable String, int, int); ctor public Condition(android.net.Uri, String, String, String, int, int, int); ctor @FlaggedApi("android.app.modes_api") public Condition(@Nullable android.net.Uri, @Nullable String, @Nullable String, @Nullable String, int, int, int, int); ctor public Condition(android.os.Parcel); method public android.service.notification.Condition copy(); method public int describeContents(); method public static boolean isValidId(android.net.Uri, String); method public static android.net.Uri.Builder newId(android.content.Context); method public static String relevanceToString(int); method @FlaggedApi("android.app.modes_api") @NonNull public static String sourceToString(int); method public static String stateToString(int); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.Condition> CREATOR; field public static final int FLAG_RELEVANT_ALWAYS = 2; // 0x2 field public static final int FLAG_RELEVANT_NOW = 1; // 0x1 field public static final String SCHEME = "condition"; field @FlaggedApi("android.app.modes_api") public static final int SOURCE_CONTEXT = 3; // 0x3 field @FlaggedApi("android.app.modes_api") public static final int SOURCE_SCHEDULE = 2; // 0x2 field @FlaggedApi("android.app.modes_api") public static final int SOURCE_UNKNOWN = 0; // 0x0 field @FlaggedApi("android.app.modes_api") public static final int SOURCE_USER_ACTION = 1; // 0x1 field public static final int STATE_ERROR = 3; // 0x3 field public static final int STATE_FALSE = 0; // 0x0 field public static final int STATE_TRUE = 1; // 0x1 Loading @@ -40567,6 +40574,7 @@ package android.service.notification { field public final android.net.Uri id; field public final String line1; field public final String line2; field @FlaggedApi("android.app.modes_api") public final int source; field public final int state; field public final String summary; } core/java/android/service/notification/Condition.java +97 −7 Original line number Diff line number Diff line Loading @@ -16,8 +16,11 @@ package android.service.notification; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Flags; import android.content.Context; import android.net.Uri; import android.os.Parcel; Loading Loading @@ -57,7 +60,6 @@ public final class Condition implements Parcelable { * Indicates that Do Not Disturb should be turned on. */ public static final int STATE_TRUE = 1; public static final int STATE_UNKNOWN = 2; public static final int STATE_ERROR = 3; Loading Loading @@ -90,6 +92,33 @@ public final class Condition implements Parcelable { public final int flags; public final int icon; /** @hide */ @IntDef(prefix = { "SOURCE_" }, value = { SOURCE_UNKNOWN, SOURCE_USER_ACTION, SOURCE_SCHEDULE, SOURCE_CONTEXT }) @Retention(RetentionPolicy.SOURCE) public @interface Source {} /** The state is changing due to an unknown reason. */ @FlaggedApi(Flags.FLAG_MODES_API) public static final int SOURCE_UNKNOWN = 0; /** The state is changing due to an explicit user action. */ @FlaggedApi(Flags.FLAG_MODES_API) public static final int SOURCE_USER_ACTION = 1; /** The state is changing due to an automatic schedule (alarm, set time, etc). */ @FlaggedApi(Flags.FLAG_MODES_API) public static final int SOURCE_SCHEDULE = 2; /** The state is changing due to a change in context (such as detected driving or sleeping). */ @FlaggedApi(Flags.FLAG_MODES_API) public static final int SOURCE_CONTEXT = 3; /** The source of, or reason for, the state change represented by this Condition. **/ @FlaggedApi(Flags.FLAG_MODES_API) public final @Source int source; /** * The maximum string length for any string contained in this condition. * @hide Loading @@ -99,14 +128,48 @@ public final class Condition implements Parcelable { /** * An object representing the current state of a {@link android.app.AutomaticZenRule}. * @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule * @param summary a user visible description of the rule state. * @param summary a user visible description of the rule state * @param state whether the mode should be activated or deactivated */ // TODO: b/310208502 - Deprecate this in favor of constructor which specifies source. public Condition(Uri id, String summary, int state) { this(id, summary, "", "", -1, state, FLAG_RELEVANT_ALWAYS); this(id, summary, "", "", -1, state, SOURCE_UNKNOWN, FLAG_RELEVANT_ALWAYS); } /** * An object representing the current state of a {@link android.app.AutomaticZenRule}. * @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule * @param summary a user visible description of the rule state * @param state whether the mode should be activated or deactivated * @param source the source of, or reason for, the state change represented by this Condition */ @FlaggedApi(Flags.FLAG_MODES_API) public Condition(@Nullable Uri id, @Nullable String summary, @State int state, @Source int source) { this(id, summary, "", "", -1, state, source, FLAG_RELEVANT_ALWAYS); } // TODO: b/310208502 - Deprecate this in favor of constructor which specifies source. public Condition(Uri id, String summary, String line1, String line2, int icon, int state, int flags) { this(id, summary, line1, line2, icon, state, SOURCE_UNKNOWN, flags); } /** * An object representing the current state of a {@link android.app.AutomaticZenRule}. * @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule * @param summary a user visible description of the rule state * @param line1 a user-visible description of when the rule will end * @param line2 a continuation of the user-visible description of when the rule will end * @param icon an icon representing this condition * @param state whether the mode should be activated or deactivated * @param source the source of, or reason for, the state change represented by this Condition * @param flags flags on this condition */ @FlaggedApi(Flags.FLAG_MODES_API) public Condition(@Nullable Uri id, @Nullable String summary, @Nullable String line1, @Nullable String line2, int icon, @State int state, @Source int source, int flags) { if (id == null) throw new IllegalArgumentException("id is required"); if (summary == null) throw new IllegalArgumentException("summary is required"); if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state); Loading @@ -116,6 +179,7 @@ public final class Condition implements Parcelable { this.line2 = getTrimmedString(line2); this.icon = icon; this.state = state; this.source = source; this.flags = flags; } Loading @@ -129,6 +193,7 @@ public final class Condition implements Parcelable { source.readString(), source.readInt(), source.readInt(), Flags.modesApi() ? source.readInt() : SOURCE_UNKNOWN, source.readInt()); } Loading @@ -144,20 +209,27 @@ public final class Condition implements Parcelable { dest.writeString(line2); dest.writeInt(icon); dest.writeInt(state); if (Flags.modesApi()) { dest.writeInt(this.source); } dest.writeInt(this.flags); } @Override public String toString() { return new StringBuilder(Condition.class.getSimpleName()).append('[') StringBuilder sb = new StringBuilder(Condition.class.getSimpleName()).append('[') .append("state=").append(stateToString(state)) .append(",id=").append(id) .append(",summary=").append(summary) .append(",line1=").append(line1) .append(",line2=").append(line2) .append(",icon=").append(icon) .append(",flags=").append(flags) .append(",icon=").append(icon); if (Flags.modesApi()) { sb.append(",source=").append(sourceToString(source)); } return sb.append(",flags=").append(flags) .append(']').toString(); } /** @hide */ Loading @@ -171,6 +243,7 @@ public final class Condition implements Parcelable { proto.write(ConditionProto.LINE_2, line2); proto.write(ConditionProto.ICON, icon); proto.write(ConditionProto.STATE, state); // TODO: b/310644464 - Add source to dump. proto.write(ConditionProto.FLAGS, flags); proto.end(token); Loading @@ -184,6 +257,16 @@ public final class Condition implements Parcelable { throw new IllegalArgumentException("state is invalid: " + state); } /** Provides a human-readable string version of the Source enum. */ @FlaggedApi(Flags.FLAG_MODES_API) public static @NonNull String sourceToString(@Source int source) { if (source == SOURCE_UNKNOWN) return "SOURCE_UNKNOWN"; if (source == SOURCE_USER_ACTION) return "SOURCE_USER_ACTION"; if (source == SOURCE_SCHEDULE) return "SOURCE_SCHEDULE"; if (source == SOURCE_CONTEXT) return "SOURCE_CONTEXT"; throw new IllegalArgumentException("source is invalid: " + source); } public static String relevanceToString(int flags) { final boolean now = (flags & FLAG_RELEVANT_NOW) != 0; final boolean always = (flags & FLAG_RELEVANT_ALWAYS) != 0; Loading @@ -197,17 +280,24 @@ public final class Condition implements Parcelable { if (!(o instanceof Condition)) return false; if (o == this) return true; final Condition other = (Condition) o; return Objects.equals(other.id, id) boolean finalEquals = Objects.equals(other.id, id) && Objects.equals(other.summary, summary) && Objects.equals(other.line1, line1) && Objects.equals(other.line2, line2) && other.icon == icon && other.state == state && other.flags == flags; if (Flags.modesApi()) { return finalEquals && other.source == source; } return finalEquals; } @Override public int hashCode() { if (Flags.modesApi()) { return Objects.hash(id, summary, line1, line2, icon, state, source, flags); } return Objects.hash(id, summary, line1, line2, icon, state, flags); } Loading core/java/android/service/notification/ZenModeConfig.java +10 −1 Original line number Diff line number Diff line Loading @@ -160,6 +160,7 @@ public class ZenModeConfig implements Parcelable { private static final String CONDITION_ATT_LINE2 = "line2"; private static final String CONDITION_ATT_ICON = "icon"; private static final String CONDITION_ATT_STATE = "state"; 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"; Loading Loading @@ -687,7 +688,12 @@ public class ZenModeConfig implements Parcelable { final int state = safeInt(parser, CONDITION_ATT_STATE, -1); final int flags = safeInt(parser, CONDITION_ATT_FLAGS, -1); try { if (Flags.modesApi()) { final int source = safeInt(parser, CONDITION_ATT_SOURCE, Condition.SOURCE_UNKNOWN); return new Condition(id, summary, line1, line2, icon, state, source, flags); } else { return new Condition(id, summary, line1, line2, icon, state, flags); } } catch (IllegalArgumentException e) { Slog.w(TAG, "Unable to read condition xml", e); return null; Loading @@ -701,6 +707,9 @@ public class ZenModeConfig implements Parcelable { out.attribute(null, CONDITION_ATT_LINE2, c.line2); out.attributeInt(null, CONDITION_ATT_ICON, c.icon); out.attributeInt(null, CONDITION_ATT_STATE, c.state); if (Flags.modesApi()) { out.attributeInt(null, CONDITION_ATT_SOURCE, c.source); } out.attributeInt(null, CONDITION_ATT_FLAGS, c.flags); } Loading core/tests/coretests/src/android/service/notification/ConditionTest.java +98 −2 Original line number Diff line number Diff line Loading @@ -16,17 +16,22 @@ package android.service.notification; import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.fail; import android.app.Flags; import android.net.Uri; import android.os.Parcel; import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.google.common.base.Strings; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -37,8 +42,11 @@ import java.lang.reflect.Field; public class ConditionTest { private static final String CLASS = "android.service.notification.Condition"; @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @Test public void testLongFields_inConstructors() { public void testLongFields_inConstructors_classic() { String longString = Strings.repeat("A", 65536); Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530)); Loading @@ -59,7 +67,7 @@ public class ConditionTest { } @Test public void testLongFields_viaParcel() { public void testLongFields_viaParcel_classic() { // Set fields via reflection to force them to be long, then parcel and unparcel to make sure // it gets truncated upon unparcelling. Condition cond = new Condition(Uri.parse("uri://placeholder"), "placeholder", Loading Loading @@ -98,4 +106,92 @@ public class ConditionTest { assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.line1.length()); assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.line2.length()); } @Test public void testLongFields_inConstructors() { mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API); String longString = Strings.repeat("A", 65536); Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530)); // Confirm strings are truncated via short constructor Condition cond1 = new Condition(longUri, longString, Condition.STATE_TRUE, Condition.SOURCE_CONTEXT); assertThat(cond1.id.toString()).hasLength(Condition.MAX_STRING_LENGTH); assertThat(cond1.summary).hasLength(Condition.MAX_STRING_LENGTH); // Confirm strings are truncated via long constructor Condition cond2 = new Condition(longUri, longString, longString, longString, -1, Condition.STATE_TRUE, Condition.SOURCE_CONTEXT, Condition.FLAG_RELEVANT_ALWAYS); assertThat(cond2.id.toString()).hasLength(Condition.MAX_STRING_LENGTH); assertThat(cond2.summary).hasLength(Condition.MAX_STRING_LENGTH); assertThat(cond2.line1).hasLength(Condition.MAX_STRING_LENGTH); assertThat(cond2.line2).hasLength(Condition.MAX_STRING_LENGTH); } @Test public void testLongFields_viaParcel() throws Exception { mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API); // Set fields via reflection to force them to be long, then parcel and unparcel to make sure // it gets truncated upon unparcelling. Condition cond = new Condition(Uri.parse("uri://placeholder"), "placeholder", Condition.STATE_TRUE, Condition.SOURCE_CONTEXT); String longString = Strings.repeat("A", 65536); Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530)); Field id = Class.forName(CLASS).getDeclaredField("id"); id.setAccessible(true); id.set(cond, longUri); Field summary = Class.forName(CLASS).getDeclaredField("summary"); summary.setAccessible(true); summary.set(cond, longString); Field line1 = Class.forName(CLASS).getDeclaredField("line1"); line1.setAccessible(true); line1.set(cond, longString); Field line2 = Class.forName(CLASS).getDeclaredField("line2"); line2.setAccessible(true); line2.set(cond, longString); Parcel parcel = Parcel.obtain(); cond.writeToParcel(parcel, 0); parcel.setDataPosition(0); Condition fromParcel = new Condition(parcel); assertThat(fromParcel.id.toString()).hasLength(Condition.MAX_STRING_LENGTH); assertThat(fromParcel.summary).hasLength(Condition.MAX_STRING_LENGTH); assertThat(fromParcel.line1).hasLength(Condition.MAX_STRING_LENGTH); assertThat(fromParcel.line2).hasLength(Condition.MAX_STRING_LENGTH); } @Test public void testEquals() { mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API); Condition cond1 = new Condition(Uri.parse("uri://placeholder"), "placeholder", Condition.STATE_TRUE, Condition.SOURCE_USER_ACTION); Condition cond2 = new Condition(Uri.parse("uri://placeholder"), "placeholder", "", "", -1, Condition.STATE_TRUE, Condition.SOURCE_SCHEDULE, Condition.FLAG_RELEVANT_ALWAYS); assertThat(cond1).isNotEqualTo(cond2); Condition cond3 = new Condition(Uri.parse("uri://placeholder"), "placeholder", Condition.STATE_TRUE, Condition.SOURCE_SCHEDULE); assertThat(cond3).isEqualTo(cond2); } @Test public void testParcelConstructor() { mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API); Condition cond = new Condition(Uri.parse("uri://placeholder"), "placeholder", Condition.STATE_TRUE, Condition.SOURCE_USER_ACTION); Parcel parcel = Parcel.obtain(); cond.writeToParcel(parcel, 0); parcel.setDataPosition(0); Condition fromParcel = new Condition(parcel); assertThat(fromParcel).isEqualTo(cond); } } Loading
core/api/current.txt +8 −0 Original line number Diff line number Diff line Loading @@ -40545,19 +40545,26 @@ package android.service.notification { public final class Condition implements android.os.Parcelable { ctor public Condition(android.net.Uri, String, int); ctor @FlaggedApi("android.app.modes_api") public Condition(@Nullable android.net.Uri, @Nullable String, int, int); ctor public Condition(android.net.Uri, String, String, String, int, int, int); ctor @FlaggedApi("android.app.modes_api") public Condition(@Nullable android.net.Uri, @Nullable String, @Nullable String, @Nullable String, int, int, int, int); ctor public Condition(android.os.Parcel); method public android.service.notification.Condition copy(); method public int describeContents(); method public static boolean isValidId(android.net.Uri, String); method public static android.net.Uri.Builder newId(android.content.Context); method public static String relevanceToString(int); method @FlaggedApi("android.app.modes_api") @NonNull public static String sourceToString(int); method public static String stateToString(int); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.Condition> CREATOR; field public static final int FLAG_RELEVANT_ALWAYS = 2; // 0x2 field public static final int FLAG_RELEVANT_NOW = 1; // 0x1 field public static final String SCHEME = "condition"; field @FlaggedApi("android.app.modes_api") public static final int SOURCE_CONTEXT = 3; // 0x3 field @FlaggedApi("android.app.modes_api") public static final int SOURCE_SCHEDULE = 2; // 0x2 field @FlaggedApi("android.app.modes_api") public static final int SOURCE_UNKNOWN = 0; // 0x0 field @FlaggedApi("android.app.modes_api") public static final int SOURCE_USER_ACTION = 1; // 0x1 field public static final int STATE_ERROR = 3; // 0x3 field public static final int STATE_FALSE = 0; // 0x0 field public static final int STATE_TRUE = 1; // 0x1 Loading @@ -40567,6 +40574,7 @@ package android.service.notification { field public final android.net.Uri id; field public final String line1; field public final String line2; field @FlaggedApi("android.app.modes_api") public final int source; field public final int state; field public final String summary; }
core/java/android/service/notification/Condition.java +97 −7 Original line number Diff line number Diff line Loading @@ -16,8 +16,11 @@ package android.service.notification; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Flags; import android.content.Context; import android.net.Uri; import android.os.Parcel; Loading Loading @@ -57,7 +60,6 @@ public final class Condition implements Parcelable { * Indicates that Do Not Disturb should be turned on. */ public static final int STATE_TRUE = 1; public static final int STATE_UNKNOWN = 2; public static final int STATE_ERROR = 3; Loading Loading @@ -90,6 +92,33 @@ public final class Condition implements Parcelable { public final int flags; public final int icon; /** @hide */ @IntDef(prefix = { "SOURCE_" }, value = { SOURCE_UNKNOWN, SOURCE_USER_ACTION, SOURCE_SCHEDULE, SOURCE_CONTEXT }) @Retention(RetentionPolicy.SOURCE) public @interface Source {} /** The state is changing due to an unknown reason. */ @FlaggedApi(Flags.FLAG_MODES_API) public static final int SOURCE_UNKNOWN = 0; /** The state is changing due to an explicit user action. */ @FlaggedApi(Flags.FLAG_MODES_API) public static final int SOURCE_USER_ACTION = 1; /** The state is changing due to an automatic schedule (alarm, set time, etc). */ @FlaggedApi(Flags.FLAG_MODES_API) public static final int SOURCE_SCHEDULE = 2; /** The state is changing due to a change in context (such as detected driving or sleeping). */ @FlaggedApi(Flags.FLAG_MODES_API) public static final int SOURCE_CONTEXT = 3; /** The source of, or reason for, the state change represented by this Condition. **/ @FlaggedApi(Flags.FLAG_MODES_API) public final @Source int source; /** * The maximum string length for any string contained in this condition. * @hide Loading @@ -99,14 +128,48 @@ public final class Condition implements Parcelable { /** * An object representing the current state of a {@link android.app.AutomaticZenRule}. * @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule * @param summary a user visible description of the rule state. * @param summary a user visible description of the rule state * @param state whether the mode should be activated or deactivated */ // TODO: b/310208502 - Deprecate this in favor of constructor which specifies source. public Condition(Uri id, String summary, int state) { this(id, summary, "", "", -1, state, FLAG_RELEVANT_ALWAYS); this(id, summary, "", "", -1, state, SOURCE_UNKNOWN, FLAG_RELEVANT_ALWAYS); } /** * An object representing the current state of a {@link android.app.AutomaticZenRule}. * @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule * @param summary a user visible description of the rule state * @param state whether the mode should be activated or deactivated * @param source the source of, or reason for, the state change represented by this Condition */ @FlaggedApi(Flags.FLAG_MODES_API) public Condition(@Nullable Uri id, @Nullable String summary, @State int state, @Source int source) { this(id, summary, "", "", -1, state, source, FLAG_RELEVANT_ALWAYS); } // TODO: b/310208502 - Deprecate this in favor of constructor which specifies source. public Condition(Uri id, String summary, String line1, String line2, int icon, int state, int flags) { this(id, summary, line1, line2, icon, state, SOURCE_UNKNOWN, flags); } /** * An object representing the current state of a {@link android.app.AutomaticZenRule}. * @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule * @param summary a user visible description of the rule state * @param line1 a user-visible description of when the rule will end * @param line2 a continuation of the user-visible description of when the rule will end * @param icon an icon representing this condition * @param state whether the mode should be activated or deactivated * @param source the source of, or reason for, the state change represented by this Condition * @param flags flags on this condition */ @FlaggedApi(Flags.FLAG_MODES_API) public Condition(@Nullable Uri id, @Nullable String summary, @Nullable String line1, @Nullable String line2, int icon, @State int state, @Source int source, int flags) { if (id == null) throw new IllegalArgumentException("id is required"); if (summary == null) throw new IllegalArgumentException("summary is required"); if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state); Loading @@ -116,6 +179,7 @@ public final class Condition implements Parcelable { this.line2 = getTrimmedString(line2); this.icon = icon; this.state = state; this.source = source; this.flags = flags; } Loading @@ -129,6 +193,7 @@ public final class Condition implements Parcelable { source.readString(), source.readInt(), source.readInt(), Flags.modesApi() ? source.readInt() : SOURCE_UNKNOWN, source.readInt()); } Loading @@ -144,20 +209,27 @@ public final class Condition implements Parcelable { dest.writeString(line2); dest.writeInt(icon); dest.writeInt(state); if (Flags.modesApi()) { dest.writeInt(this.source); } dest.writeInt(this.flags); } @Override public String toString() { return new StringBuilder(Condition.class.getSimpleName()).append('[') StringBuilder sb = new StringBuilder(Condition.class.getSimpleName()).append('[') .append("state=").append(stateToString(state)) .append(",id=").append(id) .append(",summary=").append(summary) .append(",line1=").append(line1) .append(",line2=").append(line2) .append(",icon=").append(icon) .append(",flags=").append(flags) .append(",icon=").append(icon); if (Flags.modesApi()) { sb.append(",source=").append(sourceToString(source)); } return sb.append(",flags=").append(flags) .append(']').toString(); } /** @hide */ Loading @@ -171,6 +243,7 @@ public final class Condition implements Parcelable { proto.write(ConditionProto.LINE_2, line2); proto.write(ConditionProto.ICON, icon); proto.write(ConditionProto.STATE, state); // TODO: b/310644464 - Add source to dump. proto.write(ConditionProto.FLAGS, flags); proto.end(token); Loading @@ -184,6 +257,16 @@ public final class Condition implements Parcelable { throw new IllegalArgumentException("state is invalid: " + state); } /** Provides a human-readable string version of the Source enum. */ @FlaggedApi(Flags.FLAG_MODES_API) public static @NonNull String sourceToString(@Source int source) { if (source == SOURCE_UNKNOWN) return "SOURCE_UNKNOWN"; if (source == SOURCE_USER_ACTION) return "SOURCE_USER_ACTION"; if (source == SOURCE_SCHEDULE) return "SOURCE_SCHEDULE"; if (source == SOURCE_CONTEXT) return "SOURCE_CONTEXT"; throw new IllegalArgumentException("source is invalid: " + source); } public static String relevanceToString(int flags) { final boolean now = (flags & FLAG_RELEVANT_NOW) != 0; final boolean always = (flags & FLAG_RELEVANT_ALWAYS) != 0; Loading @@ -197,17 +280,24 @@ public final class Condition implements Parcelable { if (!(o instanceof Condition)) return false; if (o == this) return true; final Condition other = (Condition) o; return Objects.equals(other.id, id) boolean finalEquals = Objects.equals(other.id, id) && Objects.equals(other.summary, summary) && Objects.equals(other.line1, line1) && Objects.equals(other.line2, line2) && other.icon == icon && other.state == state && other.flags == flags; if (Flags.modesApi()) { return finalEquals && other.source == source; } return finalEquals; } @Override public int hashCode() { if (Flags.modesApi()) { return Objects.hash(id, summary, line1, line2, icon, state, source, flags); } return Objects.hash(id, summary, line1, line2, icon, state, flags); } Loading
core/java/android/service/notification/ZenModeConfig.java +10 −1 Original line number Diff line number Diff line Loading @@ -160,6 +160,7 @@ public class ZenModeConfig implements Parcelable { private static final String CONDITION_ATT_LINE2 = "line2"; private static final String CONDITION_ATT_ICON = "icon"; private static final String CONDITION_ATT_STATE = "state"; 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"; Loading Loading @@ -687,7 +688,12 @@ public class ZenModeConfig implements Parcelable { final int state = safeInt(parser, CONDITION_ATT_STATE, -1); final int flags = safeInt(parser, CONDITION_ATT_FLAGS, -1); try { if (Flags.modesApi()) { final int source = safeInt(parser, CONDITION_ATT_SOURCE, Condition.SOURCE_UNKNOWN); return new Condition(id, summary, line1, line2, icon, state, source, flags); } else { return new Condition(id, summary, line1, line2, icon, state, flags); } } catch (IllegalArgumentException e) { Slog.w(TAG, "Unable to read condition xml", e); return null; Loading @@ -701,6 +707,9 @@ public class ZenModeConfig implements Parcelable { out.attribute(null, CONDITION_ATT_LINE2, c.line2); out.attributeInt(null, CONDITION_ATT_ICON, c.icon); out.attributeInt(null, CONDITION_ATT_STATE, c.state); if (Flags.modesApi()) { out.attributeInt(null, CONDITION_ATT_SOURCE, c.source); } out.attributeInt(null, CONDITION_ATT_FLAGS, c.flags); } Loading
core/tests/coretests/src/android/service/notification/ConditionTest.java +98 −2 Original line number Diff line number Diff line Loading @@ -16,17 +16,22 @@ package android.service.notification; import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.fail; import android.app.Flags; import android.net.Uri; import android.os.Parcel; import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.google.common.base.Strings; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -37,8 +42,11 @@ import java.lang.reflect.Field; public class ConditionTest { private static final String CLASS = "android.service.notification.Condition"; @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @Test public void testLongFields_inConstructors() { public void testLongFields_inConstructors_classic() { String longString = Strings.repeat("A", 65536); Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530)); Loading @@ -59,7 +67,7 @@ public class ConditionTest { } @Test public void testLongFields_viaParcel() { public void testLongFields_viaParcel_classic() { // Set fields via reflection to force them to be long, then parcel and unparcel to make sure // it gets truncated upon unparcelling. Condition cond = new Condition(Uri.parse("uri://placeholder"), "placeholder", Loading Loading @@ -98,4 +106,92 @@ public class ConditionTest { assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.line1.length()); assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.line2.length()); } @Test public void testLongFields_inConstructors() { mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API); String longString = Strings.repeat("A", 65536); Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530)); // Confirm strings are truncated via short constructor Condition cond1 = new Condition(longUri, longString, Condition.STATE_TRUE, Condition.SOURCE_CONTEXT); assertThat(cond1.id.toString()).hasLength(Condition.MAX_STRING_LENGTH); assertThat(cond1.summary).hasLength(Condition.MAX_STRING_LENGTH); // Confirm strings are truncated via long constructor Condition cond2 = new Condition(longUri, longString, longString, longString, -1, Condition.STATE_TRUE, Condition.SOURCE_CONTEXT, Condition.FLAG_RELEVANT_ALWAYS); assertThat(cond2.id.toString()).hasLength(Condition.MAX_STRING_LENGTH); assertThat(cond2.summary).hasLength(Condition.MAX_STRING_LENGTH); assertThat(cond2.line1).hasLength(Condition.MAX_STRING_LENGTH); assertThat(cond2.line2).hasLength(Condition.MAX_STRING_LENGTH); } @Test public void testLongFields_viaParcel() throws Exception { mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API); // Set fields via reflection to force them to be long, then parcel and unparcel to make sure // it gets truncated upon unparcelling. Condition cond = new Condition(Uri.parse("uri://placeholder"), "placeholder", Condition.STATE_TRUE, Condition.SOURCE_CONTEXT); String longString = Strings.repeat("A", 65536); Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530)); Field id = Class.forName(CLASS).getDeclaredField("id"); id.setAccessible(true); id.set(cond, longUri); Field summary = Class.forName(CLASS).getDeclaredField("summary"); summary.setAccessible(true); summary.set(cond, longString); Field line1 = Class.forName(CLASS).getDeclaredField("line1"); line1.setAccessible(true); line1.set(cond, longString); Field line2 = Class.forName(CLASS).getDeclaredField("line2"); line2.setAccessible(true); line2.set(cond, longString); Parcel parcel = Parcel.obtain(); cond.writeToParcel(parcel, 0); parcel.setDataPosition(0); Condition fromParcel = new Condition(parcel); assertThat(fromParcel.id.toString()).hasLength(Condition.MAX_STRING_LENGTH); assertThat(fromParcel.summary).hasLength(Condition.MAX_STRING_LENGTH); assertThat(fromParcel.line1).hasLength(Condition.MAX_STRING_LENGTH); assertThat(fromParcel.line2).hasLength(Condition.MAX_STRING_LENGTH); } @Test public void testEquals() { mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API); Condition cond1 = new Condition(Uri.parse("uri://placeholder"), "placeholder", Condition.STATE_TRUE, Condition.SOURCE_USER_ACTION); Condition cond2 = new Condition(Uri.parse("uri://placeholder"), "placeholder", "", "", -1, Condition.STATE_TRUE, Condition.SOURCE_SCHEDULE, Condition.FLAG_RELEVANT_ALWAYS); assertThat(cond1).isNotEqualTo(cond2); Condition cond3 = new Condition(Uri.parse("uri://placeholder"), "placeholder", Condition.STATE_TRUE, Condition.SOURCE_SCHEDULE); assertThat(cond3).isEqualTo(cond2); } @Test public void testParcelConstructor() { mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API); Condition cond = new Condition(Uri.parse("uri://placeholder"), "placeholder", Condition.STATE_TRUE, Condition.SOURCE_USER_ACTION); Parcel parcel = Parcel.obtain(); cond.writeToParcel(parcel, 0); parcel.setDataPosition(0); Condition fromParcel = new Condition(parcel); assertThat(fromParcel).isEqualTo(cond); } }