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

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

Support "in-memory" ZenMode

For the "add a mode" flow we need to create and edit a ZenMode instance without writing it to the backend until the user confirms. Therefore, we now support:
* parceling a ZenMode (so it can be restored in onSaveInstanceState/onCreate).
* creating a custom_manual ZenMode instance without interacting with NMS/ZenModeBackend.

Bug: 326442408
Test: atest com.android.settingslib.notification.modes.ZenModeTest
Flag: android.app.modes_ui
Change-Id: Ie502175a91c5148ef156a7236feb6120d42d220d
parent 799bf765
Loading
Loading
Loading
Loading
+55 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.service.notification.SystemZenRules.getTriggerDescriptionF
import static android.service.notification.ZenModeConfig.tryParseEventConditionId;
import static android.service.notification.ZenModeConfig.tryParseScheduleConditionId;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import static java.util.Objects.requireNonNull;
@@ -33,12 +34,15 @@ import android.app.NotificationManager;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.notification.SystemZenRules;
import android.service.notification.ZenDeviceEffects;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenPolicy;
import android.util.Log;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

@@ -56,11 +60,12 @@ import java.util.Objects;
 * <p>It also adapts other rule features that we don't want to expose in the UI, such as
 * interruption filters other than {@code PRIORITY}, rules without specific icons, etc.
 */
public class ZenMode {
public class ZenMode implements Parcelable {

    private static final String TAG = "ZenMode";

    static final String MANUAL_DND_MODE_ID = "manual_dnd";
    static final String TEMP_NEW_MODE_ID = "temp_new_mode";

    // Must match com.android.server.notification.ZenModeHelper#applyCustomPolicy.
    private static final ZenPolicy POLICY_INTERRUPTION_FILTER_ALARMS =
@@ -125,6 +130,25 @@ public class ZenMode {
                isActive ? Status.ENABLED_AND_ACTIVE : Status.ENABLED, true);
    }

    /**
     * Returns a new {@link ZenMode} instance that can represent a custom_manual mode that is in the
     * process of being created (and not yet saved).
     *
     * @param name mode name
     * @param iconResId resource id of the chosen icon, {code 0} if none.
     */
    public static ZenMode newCustomManual(String name, @DrawableRes int iconResId) {
        AutomaticZenRule rule = new AutomaticZenRule.Builder(name,
                ZenModeConfig.toCustomManualConditionId())
                .setPackage(ZenModeConfig.getCustomManualConditionProvider().getPackageName())
                .setType(AutomaticZenRule.TYPE_OTHER)
                .setOwner(ZenModeConfig.getCustomManualConditionProvider())
                .setIconResId(iconResId)
                .setManualInvocationAllowed(true)
                .build();
        return new ZenMode(TEMP_NEW_MODE_ID, rule, Status.ENABLED, false);
    }

    private ZenMode(String id, @NonNull AutomaticZenRule rule, Status status, boolean isManualDnd) {
        mId = id;
        mRule = rule;
@@ -304,4 +328,34 @@ public class ZenMode {
    public String toString() {
        return mId + " (" + mStatus + ") -> " + mRule;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeString(mId);
        dest.writeParcelable(mRule, 0);
        dest.writeString(mStatus.name());
        dest.writeBoolean(mIsManualDnd);
    }

    public static final Creator<ZenMode> CREATOR = new Creator<ZenMode>() {
        @Override
        public ZenMode createFromParcel(Parcel in) {
            return new ZenMode(
                    in.readString(),
                    checkNotNull(in.readParcelable(AutomaticZenRule.class.getClassLoader(),
                            AutomaticZenRule.class)),
                    Status.valueOf(in.readString()),
                    in.readBoolean());
        }

        @Override
        public ZenMode[] newArray(int size) {
            return new ZenMode[size];
        }
    };
}
+1 −9
Original line number Diff line number Diff line
@@ -192,15 +192,7 @@ public class ZenModesBackend {
     */
    @Nullable
    public ZenMode addCustomManualMode(String name, @DrawableRes int iconResId) {
        AutomaticZenRule rule = new AutomaticZenRule.Builder(name,
                ZenModeConfig.toCustomManualConditionId())
                .setPackage(ZenModeConfig.getCustomManualConditionProvider().getPackageName())
                .setType(AutomaticZenRule.TYPE_OTHER)
                .setOwner(ZenModeConfig.getCustomManualConditionProvider())
                .setIconResId(iconResId)
                .setManualInvocationAllowed(true)
                .build();

        AutomaticZenRule rule = ZenMode.newCustomManual(name, iconResId).getRule();
        String ruleId = mNotificationManager.addAutomaticZenRule(rule);
        return getMode(ruleId);
    }
+28 −0
Original line number Diff line number Diff line
@@ -21,13 +21,17 @@ import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE;
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;

import android.app.AutomaticZenRule;
import android.net.Uri;
import android.os.Parcel;
import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenPolicy;

import com.android.internal.R;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@@ -161,6 +165,30 @@ public class ZenModeTest {
        assertThat(zenMode.getRule().getZenPolicy()).isEqualTo(ZEN_POLICY);
    }

    @Test
    public void writeToParcel_equals() {
        assertUnparceledIsEqualToOriginal("example",
                new ZenMode("id", ZEN_RULE, zenConfigRuleFor(ZEN_RULE, false)));

        assertUnparceledIsEqualToOriginal("dnd", ZenMode.manualDndMode(ZEN_RULE, true));

        assertUnparceledIsEqualToOriginal("custom_manual",
                ZenMode.newCustomManual("New mode", R.drawable.ic_zen_mode_type_immersive));
    }

    private static void assertUnparceledIsEqualToOriginal(String type, ZenMode original) {
        Parcel parcel = Parcel.obtain();
        try {
            original.writeToParcel(parcel, 0);
            parcel.setDataPosition(0);
            ZenMode unparceled = ZenMode.CREATOR.createFromParcel(parcel);

            assertWithMessage("Comparing " + type).that(unparceled).isEqualTo(original);
        } finally {
            parcel.recycle();
        }
    }

    private static ZenModeConfig.ZenRule zenConfigRuleFor(AutomaticZenRule azr, boolean isActive) {
        ZenModeConfig.ZenRule zenRule = new ZenModeConfig.ZenRule();
        zenRule.pkg = azr.getPackageName();