| /* |
| * Copyright (C) 2023 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.service.notification; |
| |
| 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; |
| |
| 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 |
| * are applied whenever an {@link android.app.AutomaticZenRule} is active. |
| */ |
| @FlaggedApi(Flags.FLAG_MODES_API) |
| public final class ZenDeviceEffects implements Parcelable { |
| |
| /** |
| * Enum for the user-modifiable fields in this object. |
| * @hide |
| */ |
| @IntDef(flag = true, prefix = { "FIELD_" }, value = { |
| FIELD_GRAYSCALE, |
| FIELD_SUPPRESS_AMBIENT_DISPLAY, |
| FIELD_DIM_WALLPAPER, |
| FIELD_NIGHT_MODE, |
| FIELD_DISABLE_AUTO_BRIGHTNESS, |
| FIELD_DISABLE_TAP_TO_WAKE, |
| FIELD_DISABLE_TILT_TO_WAKE, |
| FIELD_DISABLE_TOUCH, |
| FIELD_MINIMIZE_RADIO_USAGE, |
| FIELD_MAXIMIZE_DOZE, |
| FIELD_EXTRA_EFFECTS |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface ModifiableField {} |
| |
| /** |
| * @hide |
| */ |
| public static final int FIELD_GRAYSCALE = 1 << 0; |
| /** |
| * @hide |
| */ |
| public static final int FIELD_SUPPRESS_AMBIENT_DISPLAY = 1 << 1; |
| /** |
| * @hide |
| */ |
| public static final int FIELD_DIM_WALLPAPER = 1 << 2; |
| /** |
| * @hide |
| */ |
| public static final int FIELD_NIGHT_MODE = 1 << 3; |
| /** |
| * @hide |
| */ |
| public static final int FIELD_DISABLE_AUTO_BRIGHTNESS = 1 << 4; |
| /** |
| * @hide |
| */ |
| public static final int FIELD_DISABLE_TAP_TO_WAKE = 1 << 5; |
| /** |
| * @hide |
| */ |
| public static final int FIELD_DISABLE_TILT_TO_WAKE = 1 << 6; |
| /** |
| * @hide |
| */ |
| public static final int FIELD_DISABLE_TOUCH = 1 << 7; |
| /** |
| * @hide |
| */ |
| public static final int FIELD_MINIMIZE_RADIO_USAGE = 1 << 8; |
| /** |
| * @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; |
| private final boolean mDimWallpaper; |
| private final boolean mNightMode; |
| |
| private final boolean mDisableAutoBrightness; |
| private final boolean mDisableTapToWake; |
| private final boolean mDisableTiltToWake; |
| 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, Set<String> extraEffects) { |
| mGrayscale = grayscale; |
| mSuppressAmbientDisplay = suppressAmbientDisplay; |
| mDimWallpaper = dimWallpaper; |
| mNightMode = nightMode; |
| mDisableAutoBrightness = disableAutoBrightness; |
| mDisableTapToWake = disableTapToWake; |
| mDisableTiltToWake = disableTiltToWake; |
| 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 |
| public boolean equals(Object obj) { |
| if (!(obj instanceof final ZenDeviceEffects that)) return false; |
| if (obj == this) return true; |
| |
| return this.mGrayscale == that.mGrayscale |
| && this.mSuppressAmbientDisplay == that.mSuppressAmbientDisplay |
| && this.mDimWallpaper == that.mDimWallpaper |
| && this.mNightMode == that.mNightMode |
| && this.mDisableAutoBrightness == that.mDisableAutoBrightness |
| && this.mDisableTapToWake == that.mDisableTapToWake |
| && this.mDisableTiltToWake == that.mDisableTiltToWake |
| && this.mDisableTouch == that.mDisableTouch |
| && this.mMinimizeRadioUsage == that.mMinimizeRadioUsage |
| && 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, mExtraEffects); |
| } |
| |
| @Override |
| public String toString() { |
| ArrayList<String> effects = new ArrayList<>(11); |
| if (mGrayscale) effects.add("grayscale"); |
| if (mSuppressAmbientDisplay) effects.add("suppressAmbientDisplay"); |
| if (mDimWallpaper) effects.add("dimWallpaper"); |
| if (mNightMode) effects.add("nightMode"); |
| if (mDisableAutoBrightness) effects.add("disableAutoBrightness"); |
| if (mDisableTapToWake) effects.add("disableTapToWake"); |
| if (mDisableTiltToWake) effects.add("disableTiltToWake"); |
| 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) + "]"; |
| } |
| |
| /** @hide */ |
| public static String fieldsToString(@ModifiableField int bitmask) { |
| ArrayList<String> modified = new ArrayList<>(); |
| if ((bitmask & FIELD_GRAYSCALE) != 0) { |
| modified.add("FIELD_GRAYSCALE"); |
| } |
| if ((bitmask & FIELD_SUPPRESS_AMBIENT_DISPLAY) != 0) { |
| modified.add("FIELD_SUPPRESS_AMBIENT_DISPLAY"); |
| } |
| if ((bitmask & FIELD_DIM_WALLPAPER) != 0) { |
| modified.add("FIELD_DIM_WALLPAPER"); |
| } |
| if ((bitmask & FIELD_NIGHT_MODE) != 0) { |
| modified.add("FIELD_NIGHT_MODE"); |
| } |
| if ((bitmask & FIELD_DISABLE_AUTO_BRIGHTNESS) != 0) { |
| modified.add("FIELD_DISABLE_AUTO_BRIGHTNESS"); |
| } |
| if ((bitmask & FIELD_DISABLE_TAP_TO_WAKE) != 0) { |
| modified.add("FIELD_DISABLE_TAP_TO_WAKE"); |
| } |
| if ((bitmask & FIELD_DISABLE_TILT_TO_WAKE) != 0) { |
| modified.add("FIELD_DISABLE_TILT_TO_WAKE"); |
| } |
| if ((bitmask & FIELD_DISABLE_TOUCH) != 0) { |
| modified.add("FIELD_DISABLE_TOUCH"); |
| } |
| if ((bitmask & FIELD_MINIMIZE_RADIO_USAGE) != 0) { |
| modified.add("FIELD_MINIMIZE_RADIO_USAGE"); |
| } |
| 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) + "}"; |
| } |
| |
| /** |
| * Whether the level of color saturation of the display should be set to minimum, effectively |
| * switching it to grayscale, while the rule is active. |
| */ |
| public boolean shouldDisplayGrayscale() { |
| return mGrayscale; |
| } |
| |
| /** |
| * Whether the ambient (always-on) display feature should be disabled while the rule is active. |
| * This will have no effect if the device doesn't support always-on display or if it's not |
| * generally enabled. |
| */ |
| public boolean shouldSuppressAmbientDisplay() { |
| return mSuppressAmbientDisplay; |
| } |
| |
| /** Whether the wallpaper should be dimmed while the rule is active. */ |
| public boolean shouldDimWallpaper() { |
| return mDimWallpaper; |
| } |
| |
| /** Whether night mode (aka dark theme) should be applied while the rule is active. */ |
| public boolean shouldUseNightMode() { |
| return mNightMode; |
| } |
| |
| /** |
| * Whether the display's automatic brightness adjustment should be disabled while the rule is |
| * active. |
| * @hide |
| */ |
| public boolean shouldDisableAutoBrightness() { |
| return mDisableAutoBrightness; |
| } |
| |
| /** |
| * Whether "tap to wake" should be disabled while the rule is active. |
| * @hide |
| */ |
| public boolean shouldDisableTapToWake() { |
| return mDisableTapToWake; |
| } |
| |
| /** |
| * Whether "tilt to wake" should be disabled while the rule is active. |
| * @hide |
| */ |
| public boolean shouldDisableTiltToWake() { |
| return mDisableTiltToWake; |
| } |
| |
| /** |
| * Whether touch interactions should be disabled while the rule is active. |
| * @hide |
| */ |
| public boolean shouldDisableTouch() { |
| return mDisableTouch; |
| } |
| |
| /** |
| * Whether radio (wi-fi, LTE, etc) traffic, and its attendant battery consumption, should be |
| * minimized while the rule is active. |
| * @hide |
| */ |
| public boolean shouldMinimizeRadioUsage() { |
| return mMinimizeRadioUsage; |
| } |
| |
| /** |
| * Whether Doze should be enhanced (e.g. with more aggressive activation, or less frequent |
| * maintenance windows) while the rule is active. |
| * @hide |
| */ |
| public boolean shouldMaximizeDoze() { |
| 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 |
| */ |
| public boolean hasEffects() { |
| return mGrayscale || mSuppressAmbientDisplay || mDimWallpaper || mNightMode |
| || mDisableAutoBrightness || mDisableTapToWake || mDisableTiltToWake |
| || mDisableTouch || mMinimizeRadioUsage || mMaximizeDoze |
| || mExtraEffects.size() > 0; |
| } |
| |
| /** {@link Parcelable.Creator} that instantiates {@link ZenDeviceEffects} objects. */ |
| @NonNull |
| public static final Creator<ZenDeviceEffects> CREATOR = new Creator<ZenDeviceEffects>() { |
| @Override |
| public ZenDeviceEffects createFromParcel(Parcel in) { |
| return new ZenDeviceEffects(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 |
| public ZenDeviceEffects[] newArray(int size) { |
| return new ZenDeviceEffects[size]; |
| } |
| }; |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(@NonNull Parcel dest, int flags) { |
| dest.writeBoolean(mGrayscale); |
| dest.writeBoolean(mSuppressAmbientDisplay); |
| dest.writeBoolean(mDimWallpaper); |
| dest.writeBoolean(mNightMode); |
| dest.writeBoolean(mDisableAutoBrightness); |
| dest.writeBoolean(mDisableTapToWake); |
| dest.writeBoolean(mDisableTiltToWake); |
| dest.writeBoolean(mDisableTouch); |
| dest.writeBoolean(mMinimizeRadioUsage); |
| dest.writeBoolean(mMaximizeDoze); |
| dest.writeArray(mExtraEffects.toArray(new String[0])); |
| } |
| |
| /** Builder class for {@link ZenDeviceEffects} objects. */ |
| @FlaggedApi(Flags.FLAG_MODES_API) |
| public static final class Builder { |
| |
| private boolean mGrayscale; |
| private boolean mSuppressAmbientDisplay; |
| private boolean mDimWallpaper; |
| private boolean mNightMode; |
| private boolean mDisableAutoBrightness; |
| private boolean mDisableTapToWake; |
| private boolean mDisableTiltToWake; |
| 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). |
| */ |
| public Builder() { |
| } |
| |
| /** |
| * Instantiates a new {@link ZenPolicy.Builder} with all effects set to their corresponding |
| * values in the supplied {@link ZenDeviceEffects}. |
| */ |
| public Builder(@NonNull ZenDeviceEffects zenDeviceEffects) { |
| mGrayscale = zenDeviceEffects.shouldDisplayGrayscale(); |
| mSuppressAmbientDisplay = zenDeviceEffects.shouldSuppressAmbientDisplay(); |
| mDimWallpaper = zenDeviceEffects.shouldDimWallpaper(); |
| mNightMode = zenDeviceEffects.shouldUseNightMode(); |
| mDisableAutoBrightness = zenDeviceEffects.shouldDisableAutoBrightness(); |
| mDisableTapToWake = zenDeviceEffects.shouldDisableTapToWake(); |
| mDisableTiltToWake = zenDeviceEffects.shouldDisableTiltToWake(); |
| mDisableTouch = zenDeviceEffects.shouldDisableTouch(); |
| mMinimizeRadioUsage = zenDeviceEffects.shouldMinimizeRadioUsage(); |
| mMaximizeDoze = zenDeviceEffects.shouldMaximizeDoze(); |
| mExtraEffects.addAll(zenDeviceEffects.getExtraEffects()); |
| } |
| |
| /** |
| * Sets whether the level of color saturation of the display should be set to minimum, |
| * effectively switching it to grayscale, while the rule is active. |
| */ |
| @NonNull |
| public Builder setShouldDisplayGrayscale(boolean grayscale) { |
| mGrayscale = grayscale; |
| return this; |
| } |
| |
| /** |
| * Sets whether the ambient (always-on) display feature should be disabled while the rule |
| * is active. This will have no effect if the device doesn't support always-on display or if |
| * it's not generally enabled. |
| */ |
| @NonNull |
| public Builder setShouldSuppressAmbientDisplay(boolean suppressAmbientDisplay) { |
| mSuppressAmbientDisplay = suppressAmbientDisplay; |
| return this; |
| } |
| |
| /** Sets whether the wallpaper should be dimmed while the rule is active. */ |
| @NonNull |
| public Builder setShouldDimWallpaper(boolean dimWallpaper) { |
| mDimWallpaper = dimWallpaper; |
| return this; |
| } |
| |
| /** Sets whether night mode (aka dark theme) should be applied while the rule is active. */ |
| @NonNull |
| public Builder setShouldUseNightMode(boolean nightMode) { |
| mNightMode = nightMode; |
| return this; |
| } |
| |
| /** |
| * Sets whether the display's automatic brightness adjustment should be disabled while the |
| * rule is active. |
| * @hide |
| */ |
| @NonNull |
| public Builder setShouldDisableAutoBrightness(boolean disableAutoBrightness) { |
| mDisableAutoBrightness = disableAutoBrightness; |
| return this; |
| } |
| |
| /** |
| * Sets whether "tap to wake" should be disabled while the rule is active. |
| * @hide |
| */ |
| @NonNull |
| public Builder setShouldDisableTapToWake(boolean disableTapToWake) { |
| mDisableTapToWake = disableTapToWake; |
| return this; |
| } |
| |
| /** |
| * Sets whether "tilt to wake" should be disabled while the rule is active. |
| * @hide |
| */ |
| @NonNull |
| public Builder setShouldDisableTiltToWake(boolean disableTiltToWake) { |
| mDisableTiltToWake = disableTiltToWake; |
| return this; |
| } |
| |
| /** |
| * Sets whether touch interactions should be disabled while the rule is active. |
| * @hide |
| */ |
| @NonNull |
| public Builder setShouldDisableTouch(boolean disableTouch) { |
| mDisableTouch = disableTouch; |
| return this; |
| } |
| |
| /** |
| * Sets whether radio (wi-fi, LTE, etc) traffic, and its attendant battery consumption, |
| * should be minimized while the rule is active. |
| * @hide |
| */ |
| @NonNull |
| public Builder setShouldMinimizeRadioUsage(boolean minimizeRadioUsage) { |
| mMinimizeRadioUsage = minimizeRadioUsage; |
| return this; |
| } |
| |
| /** |
| * Sets whether Doze should be enhanced (e.g. with more aggressive activation, or less |
| * frequent maintenance windows) while the rule is active. |
| * @hide |
| */ |
| @NonNull |
| public Builder setShouldMaximizeDoze(boolean maximizeDoze) { |
| mMaximizeDoze = maximizeDoze; |
| 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). |
| * @hide |
| */ |
| @NonNull |
| public Builder add(@Nullable ZenDeviceEffects effects) { |
| if (effects == null) return this; |
| if (effects.shouldDisplayGrayscale()) setShouldDisplayGrayscale(true); |
| if (effects.shouldSuppressAmbientDisplay()) setShouldSuppressAmbientDisplay(true); |
| if (effects.shouldDimWallpaper()) setShouldDimWallpaper(true); |
| if (effects.shouldUseNightMode()) setShouldUseNightMode(true); |
| if (effects.shouldDisableAutoBrightness()) setShouldDisableAutoBrightness(true); |
| if (effects.shouldDisableTapToWake()) setShouldDisableTapToWake(true); |
| if (effects.shouldDisableTiltToWake()) setShouldDisableTiltToWake(true); |
| if (effects.shouldDisableTouch()) setShouldDisableTouch(true); |
| if (effects.shouldMinimizeRadioUsage()) setShouldMinimizeRadioUsage(true); |
| if (effects.shouldMaximizeDoze()) setShouldMaximizeDoze(true); |
| addExtraEffects(effects.getExtraEffects()); |
| 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, mExtraEffects); |
| } |
| } |
| } |