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

Commit 73dc595f authored by Alexander Roederer's avatar Alexander Roederer Committed by Android (Google) Code Review
Browse files

Merge "Adds source to Notification Condition" into main

parents 4d3be9b7 3e655086
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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
@@ -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;
  }
+97 −7
Original line number Diff line number Diff line
@@ -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;
@@ -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;

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

@@ -129,6 +193,7 @@ public final class Condition implements Parcelable {
                source.readString(),
                source.readInt(),
                source.readInt(),
                Flags.modesApi() ? source.readInt() : SOURCE_UNKNOWN,
                source.readInt());
    }

@@ -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 */
@@ -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);
@@ -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;
@@ -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);
    }

+10 −1
Original line number Diff line number Diff line
@@ -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";
@@ -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;
@@ -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);
    }

+98 −2
Original line number Diff line number Diff line
@@ -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;

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

@@ -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",
@@ -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);
    }
}