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

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

Add "extra effects" to ZenDeviceEffects

For usage by OEMs / System.

Bug: 324841997
Test: atest ZenModeHelperTest ZenModeConfigTest ZenDeviceEffectsTest
Change-Id: I578846308b5e51c2ef12a9cf27512cfb13f89548
parent 08dd4252
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -3047,6 +3047,14 @@ package android.service.notification {
    method @Deprecated public boolean isBound();
  }

  @FlaggedApi("android.app.modes_api") public final class ZenDeviceEffects implements android.os.Parcelable {
    method @NonNull public java.util.Set<java.lang.String> getExtraEffects();
  }

  @FlaggedApi("android.app.modes_api") public static final class ZenDeviceEffects.Builder {
    method @NonNull public android.service.notification.ZenDeviceEffects.Builder setExtraEffects(@NonNull java.util.Set<java.lang.String>);
  }

  public final class ZenPolicy implements android.os.Parcelable {
    method @FlaggedApi("android.app.modes_api") @NonNull public android.service.notification.ZenPolicy overwrittenWith(@Nullable android.service.notification.ZenPolicy);
  }
+3 −0
Original line number Diff line number Diff line
@@ -487,6 +487,9 @@ public final class AutomaticZenRule implements Parcelable {
    public void validate() {
        if (Flags.modesApi()) {
            checkValidType(mType);
            if (mDeviceEffects != null) {
                mDeviceEffects.validate();
            }
        }
    }

+109 −9
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ 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;
@@ -27,7 +28,10 @@ import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * Represents the set of device effects (affecting display and device behavior in general) that
@@ -51,6 +55,7 @@ public final class ZenDeviceEffects implements Parcelable {
            FIELD_DISABLE_TOUCH,
            FIELD_MINIMIZE_RADIO_USAGE,
            FIELD_MAXIMIZE_DOZE,
            FIELD_EXTRA_EFFECTS
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ModifiableField {}
@@ -95,6 +100,12 @@ public final class ZenDeviceEffects implements Parcelable {
     * @hide
     */
    public static final int FIELD_MAXIMIZE_DOZE = 1 << 9;
    /**
     * @hide
     */
    public static final int FIELD_EXTRA_EFFECTS = 1 << 10;

    private static final int MAX_EFFECTS_LENGTH = 2_000; // characters

    private final boolean mGrayscale;
    private final boolean mSuppressAmbientDisplay;
@@ -107,11 +118,12 @@ public final class ZenDeviceEffects implements Parcelable {
    private final boolean mDisableTouch;
    private final boolean mMinimizeRadioUsage;
    private final boolean mMaximizeDoze;
    private final Set<String> mExtraEffects;

    private ZenDeviceEffects(boolean grayscale, boolean suppressAmbientDisplay,
            boolean dimWallpaper, boolean nightMode, boolean disableAutoBrightness,
            boolean disableTapToWake, boolean disableTiltToWake, boolean disableTouch,
            boolean minimizeRadioUsage, boolean maximizeDoze) {
            boolean minimizeRadioUsage, boolean maximizeDoze, Set<String> extraEffects) {
        mGrayscale = grayscale;
        mSuppressAmbientDisplay = suppressAmbientDisplay;
        mDimWallpaper = dimWallpaper;
@@ -122,6 +134,21 @@ public final class ZenDeviceEffects implements Parcelable {
        mDisableTouch = disableTouch;
        mMinimizeRadioUsage = minimizeRadioUsage;
        mMaximizeDoze = maximizeDoze;
        mExtraEffects = Collections.unmodifiableSet(extraEffects);
    }

    /** @hide */
    @FlaggedApi(Flags.FLAG_MODES_API)
    public void validate() {
        int extraEffectsLength = 0;
        for (String extraEffect : mExtraEffects) {
            extraEffectsLength += extraEffect.length();
        }
        if (extraEffectsLength > MAX_EFFECTS_LENGTH) {
            throw new IllegalArgumentException(
                    "Total size of extra effects must be at most " + MAX_EFFECTS_LENGTH
                            + " characters");
        }
    }

    @Override
@@ -138,19 +165,20 @@ public final class ZenDeviceEffects implements Parcelable {
                && this.mDisableTiltToWake == that.mDisableTiltToWake
                && this.mDisableTouch == that.mDisableTouch
                && this.mMinimizeRadioUsage == that.mMinimizeRadioUsage
                && this.mMaximizeDoze == that.mMaximizeDoze;
                && this.mMaximizeDoze == that.mMaximizeDoze
                && Objects.equals(this.mExtraEffects, that.mExtraEffects);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mGrayscale, mSuppressAmbientDisplay, mDimWallpaper, mNightMode,
                mDisableAutoBrightness, mDisableTapToWake, mDisableTiltToWake, mDisableTouch,
                mMinimizeRadioUsage, mMaximizeDoze);
                mMinimizeRadioUsage, mMaximizeDoze, mExtraEffects);
    }

    @Override
    public String toString() {
        ArrayList<String> effects = new ArrayList<>(10);
        ArrayList<String> effects = new ArrayList<>(11);
        if (mGrayscale) effects.add("grayscale");
        if (mSuppressAmbientDisplay) effects.add("suppressAmbientDisplay");
        if (mDimWallpaper) effects.add("dimWallpaper");
@@ -161,6 +189,9 @@ public final class ZenDeviceEffects implements Parcelable {
        if (mDisableTouch) effects.add("disableTouch");
        if (mMinimizeRadioUsage) effects.add("minimizeRadioUsage");
        if (mMaximizeDoze) effects.add("maximizeDoze");
        if (mExtraEffects.size() > 0) {
            effects.add("extraEffects=[" + String.join(",", mExtraEffects) + "]");
        }
        return "[" + String.join(", ", effects) + "]";
    }

@@ -197,6 +228,9 @@ public final class ZenDeviceEffects implements Parcelable {
        if ((bitmask & FIELD_MAXIMIZE_DOZE) != 0) {
            modified.add("FIELD_MAXIMIZE_DOZE");
        }
        if ((bitmask & FIELD_EXTRA_EFFECTS) != 0) {
            modified.add("FIELD_EXTRA_EFFECTS");
        }
        return "{" + String.join(",", modified) + "}";
    }

@@ -270,7 +304,7 @@ public final class ZenDeviceEffects implements Parcelable {
    }

    /**
     * Whether Doze should be enhanced (e.g. with more aggresive activation, or less frequent
     * Whether Doze should be enhanced (e.g. with more aggressive activation, or less frequent
     * maintenance windows) while the rule is active.
     * @hide
     */
@@ -278,6 +312,18 @@ public final class ZenDeviceEffects implements Parcelable {
        return mMaximizeDoze;
    }

    /**
     * (Immutable) set of extra effects to be applied while the rule is active. Extra effects are
     * not used in AOSP, but OEMs may add support for them by providing a custom
     * {@link DeviceEffectsApplier}.
     * @hide
     */
    @TestApi
    @NonNull
    public Set<String> getExtraEffects() {
        return mExtraEffects;
    }

    /**
     * Whether any of the effects are set up.
     * @hide
@@ -285,7 +331,8 @@ public final class ZenDeviceEffects implements Parcelable {
    public boolean hasEffects() {
        return mGrayscale || mSuppressAmbientDisplay || mDimWallpaper || mNightMode
                || mDisableAutoBrightness || mDisableTapToWake || mDisableTiltToWake
                || mDisableTouch || mMinimizeRadioUsage || mMaximizeDoze;
                || mDisableTouch || mMinimizeRadioUsage || mMaximizeDoze
                || mExtraEffects.size() > 0;
    }

    /** {@link Parcelable.Creator} that instantiates {@link ZenDeviceEffects} objects. */
@@ -296,7 +343,8 @@ 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.readBoolean(),
                    Set.of(in.readArray(String.class.getClassLoader(), String.class)));
        }

        @Override
@@ -322,6 +370,7 @@ public final class ZenDeviceEffects implements Parcelable {
        dest.writeBoolean(mDisableTouch);
        dest.writeBoolean(mMinimizeRadioUsage);
        dest.writeBoolean(mMaximizeDoze);
        dest.writeArray(mExtraEffects.toArray(new String[0]));
    }

    /** Builder class for {@link ZenDeviceEffects} objects. */
@@ -338,6 +387,7 @@ public final class ZenDeviceEffects implements Parcelable {
        private boolean mDisableTouch;
        private boolean mMinimizeRadioUsage;
        private boolean mMaximizeDoze;
        private final HashSet<String> mExtraEffects = new HashSet<>();

        /**
         * Instantiates a new {@link ZenPolicy.Builder} with all effects set to default (disabled).
@@ -360,6 +410,7 @@ public final class ZenDeviceEffects implements Parcelable {
            mDisableTouch = zenDeviceEffects.shouldDisableTouch();
            mMinimizeRadioUsage = zenDeviceEffects.shouldMinimizeRadioUsage();
            mMaximizeDoze = zenDeviceEffects.shouldMaximizeDoze();
            mExtraEffects.addAll(zenDeviceEffects.getExtraEffects());
        }

        /**
@@ -450,7 +501,7 @@ public final class ZenDeviceEffects implements Parcelable {
        }

        /**
         * Sets whether Doze should be enhanced (e.g. with more aggresive activation, or less
         * Sets whether Doze should be enhanced (e.g. with more aggressive activation, or less
         * frequent maintenance windows) while the rule is active.
         * @hide
         */
@@ -460,6 +511,54 @@ public final class ZenDeviceEffects implements Parcelable {
            return this;
        }

        /**
         * Sets the extra effects to be applied while the rule is active. Extra effects are not
         * used in AOSP, but OEMs may add support for them by providing a custom
         * {@link DeviceEffectsApplier}.
         *
         * @apiNote The total size of the extra effects (concatenation of strings) is limited.
         *
         * @hide
         */
        @TestApi
        @NonNull
        public Builder setExtraEffects(@NonNull Set<String> extraEffects) {
            Objects.requireNonNull(extraEffects);
            mExtraEffects.clear();
            mExtraEffects.addAll(extraEffects);
            return this;
        }

        /**
         * Adds the supplied extra effects to the set to be applied while the rule is active.
         * Extra effects are not used in AOSP, but OEMs may add support for them by providing a
         * custom {@link DeviceEffectsApplier}.
         *
         * @apiNote The total size of the extra effects (concatenation of strings) is limited.
         *
         * @hide
         */
        @NonNull
        public Builder addExtraEffects(@NonNull Set<String> extraEffects) {
            mExtraEffects.addAll(Objects.requireNonNull(extraEffects));
            return this;
        }

        /**
         * Adds the supplied extra effect to the set to be applied while the rule is active.
         * Extra effects are not used in AOSP, but OEMs may add support for them by providing a
         * custom {@link DeviceEffectsApplier}.
         *
         * @apiNote The total size of the extra effects (concatenation of strings) is limited.
         *
         * @hide
         */
        @NonNull
        public Builder addExtraEffect(@NonNull String extraEffect) {
            mExtraEffects.add(Objects.requireNonNull(extraEffect));
            return this;
        }

        /**
         * Applies the effects that are {@code true} on the supplied {@link ZenDeviceEffects} to
         * this builder (essentially logically-ORing the effect set).
@@ -478,6 +577,7 @@ public final class ZenDeviceEffects implements Parcelable {
            if (effects.shouldDisableTouch()) setShouldDisableTouch(true);
            if (effects.shouldMinimizeRadioUsage()) setShouldMinimizeRadioUsage(true);
            if (effects.shouldMaximizeDoze()) setShouldMaximizeDoze(true);
            addExtraEffects(effects.getExtraEffects());
            return this;
        }

@@ -487,7 +587,7 @@ public final class ZenDeviceEffects implements Parcelable {
            return new ZenDeviceEffects(mGrayscale,
                    mSuppressAmbientDisplay, mDimWallpaper, mNightMode, mDisableAutoBrightness,
                    mDisableTapToWake, mDisableTiltToWake, mDisableTouch, mMinimizeRadioUsage,
                    mMaximizeDoze);
                    mMaximizeDoze, mExtraEffects);
        }
    }
}
+52 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OF

import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AlarmManager;
@@ -65,17 +66,21 @@ import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import java.util.regex.Pattern;

/**
 * Persisted configuration for zen mode.
@@ -272,8 +277,13 @@ public class ZenModeConfig implements Parcelable {
    private static final String DEVICE_EFFECT_DISABLE_TOUCH = "zdeDisableTouch";
    private static final String DEVICE_EFFECT_MINIMIZE_RADIO_USAGE = "zdeMinimizeRadioUsage";
    private static final String DEVICE_EFFECT_MAXIMIZE_DOZE = "zdeMaximizeDoze";
    private static final String DEVICE_EFFECT_EXTRAS = "zdeExtraEffects";
    private static final String DEVICE_EFFECT_USER_MODIFIED_FIELDS = "zdeUserModifiedFields";

    private static final String ITEM_SEPARATOR = ",";
    private static final String ITEM_SEPARATOR_ESCAPE = "\\";
    private static final Pattern ITEM_SPLITTER_REGEX = Pattern.compile("(?<!\\\\),");

    @UnsupportedAppUsage
    public boolean allowAlarms = DEFAULT_ALLOW_ALARMS;
    public boolean allowMedia = DEFAULT_ALLOW_MEDIA;
@@ -1099,6 +1109,7 @@ public class ZenModeConfig implements Parcelable {
                .setShouldMinimizeRadioUsage(
                        safeBoolean(parser, DEVICE_EFFECT_MINIMIZE_RADIO_USAGE, false))
                .setShouldMaximizeDoze(safeBoolean(parser, DEVICE_EFFECT_MAXIMIZE_DOZE, false))
                .setExtraEffects(safeStringSet(parser, DEVICE_EFFECT_EXTRAS))
                .build();

        return deviceEffects.hasEffects() ? deviceEffects : null;
@@ -1123,6 +1134,7 @@ public class ZenModeConfig implements Parcelable {
        writeBooleanIfTrue(out, DEVICE_EFFECT_MINIMIZE_RADIO_USAGE,
                deviceEffects.shouldMinimizeRadioUsage());
        writeBooleanIfTrue(out, DEVICE_EFFECT_MAXIMIZE_DOZE, deviceEffects.shouldMaximizeDoze());
        writeStringSet(out, DEVICE_EFFECT_EXTRAS, deviceEffects.getExtraEffects());
    }

    private static void writeBooleanIfTrue(TypedXmlSerializer out, String att, boolean value)
@@ -1132,6 +1144,26 @@ public class ZenModeConfig implements Parcelable {
        }
    }

    private static void writeStringSet(TypedXmlSerializer out, String att, Set<String> values)
            throws IOException {
        if (values.isEmpty()) {
            return;
        }
        // We escape each item  by replacing "\" by "\\" and "," by "\,". Then we concatenate with
        // "," as separator. Reading performs the same operations in the opposite order.
        List<String> escapedItems = new ArrayList<>();
        for (String item : values) {
            escapedItems.add(
                    item
                            .replace(ITEM_SEPARATOR_ESCAPE,
                                    ITEM_SEPARATOR_ESCAPE + ITEM_SEPARATOR_ESCAPE)
                            .replace(ITEM_SEPARATOR,
                                    ITEM_SEPARATOR_ESCAPE + ITEM_SEPARATOR));
        }
        String serialized = String.join(ITEM_SEPARATOR, escapedItems);
        out.attribute(null, att, serialized);
    }

    public static boolean isValidHour(int val) {
        return val >= 0 && val < 24;
    }
@@ -1182,6 +1214,26 @@ public class ZenModeConfig implements Parcelable {
        return tryParseLong(val, defValue);
    }

    @NonNull
    private static Set<String> safeStringSet(TypedXmlPullParser parser, String att) {
        Set<String> values = new HashSet<>();

        String serialized = parser.getAttributeValue(null, att);
        if (!TextUtils.isEmpty(serialized)) {
            // We split on every "," that is *not preceded* by the escape character "\".
            // Then we reverse the escaping done on each individual item.
            String[] escapedItems = ITEM_SPLITTER_REGEX.split(serialized);
            for (String escapedItem : escapedItems) {
                values.add(escapedItem
                        .replace(ITEM_SEPARATOR_ESCAPE + ITEM_SEPARATOR_ESCAPE,
                                ITEM_SEPARATOR_ESCAPE)
                        .replace(ITEM_SEPARATOR_ESCAPE + ITEM_SEPARATOR,
                                ITEM_SEPARATOR));
            }
        }
        return values;
    }

    @Override
    public int describeContents() {
        return 0;
+5 −1
Original line number Diff line number Diff line
@@ -1264,7 +1264,7 @@ public class ZenModeHelper {
                : new ZenDeviceEffects.Builder().build();

        if (isFromApp) {
            // Don't allow apps to toggle hidden effects.
            // Don't allow apps to toggle hidden (non-public-API) effects.
            newEffects = new ZenDeviceEffects.Builder(newEffects)
                    .setShouldDisableAutoBrightness(oldEffects.shouldDisableAutoBrightness())
                    .setShouldDisableTapToWake(oldEffects.shouldDisableTapToWake())
@@ -1272,6 +1272,7 @@ public class ZenModeHelper {
                    .setShouldDisableTouch(oldEffects.shouldDisableTouch())
                    .setShouldMinimizeRadioUsage(oldEffects.shouldMinimizeRadioUsage())
                    .setShouldMaximizeDoze(oldEffects.shouldMaximizeDoze())
                    .setExtraEffects(oldEffects.getExtraEffects())
                    .build();
        }

@@ -1311,6 +1312,9 @@ public class ZenModeHelper {
            if (oldEffects.shouldMaximizeDoze() != newEffects.shouldMaximizeDoze()) {
                userModifiedFields |= ZenDeviceEffects.FIELD_MAXIMIZE_DOZE;
            }
            if (!Objects.equals(oldEffects.getExtraEffects(), newEffects.getExtraEffects())) {
                userModifiedFields |= ZenDeviceEffects.FIELD_EXTRA_EFFECTS;
            }
            zenRule.zenDeviceEffectsUserModifiedFields = userModifiedFields;
        }
    }
Loading