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

Commit 173fcdf9 authored by Alexander Roederer's avatar Alexander Roederer
Browse files

Add ZenDeviceEffects to ZenModeDiff

Adds class to diff ZenDeviceEffects objects, and associated tests.

Unlike other objects diffed in ZenModeDiff, ZenDeviceEffects uses
private final fields and a builder, so for testing purposes we need to
modify the reflective field aggregator in the test file to consider
final fields (rather than skipping them).

Bug: 319241807
Test: atest ZenModeDiffTest
Flag: android.app.modes_ui
Change-Id: I8a59ce6711a401a87b1a1e72f7e0f05fe56a5d72
parent b7bb6931
Loading
Loading
Loading
Loading
+138 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.service.notification;

import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.Flags;
@@ -663,4 +664,141 @@ public class ZenModeDiff {
            return mActiveDiff != null && !mActiveDiff.to();
        }
    }

    /**
     * Diff class representing a change between two
     * {@link android.service.notification.ZenDeviceEffects}.
     */
    @FlaggedApi(Flags.FLAG_MODES_API)
    public static class DeviceEffectsDiff extends BaseDiff {
        public static final String FIELD_GRAYSCALE = "mGrayscale";
        public static final String FIELD_SUPPRESS_AMBIENT_DISPLAY = "mSuppressAmbientDisplay";
        public static final String FIELD_DIM_WALLPAPER = "mDimWallpaper";
        public static final String FIELD_NIGHT_MODE = "mNightMode";
        public static final String FIELD_DISABLE_AUTO_BRIGHTNESS = "mDisableAutoBrightness";
        public static final String FIELD_DISABLE_TAP_TO_WAKE = "mDisableTapToWake";
        public static final String FIELD_DISABLE_TILT_TO_WAKE = "mDisableTiltToWake";
        public static final String FIELD_DISABLE_TOUCH = "mDisableTouch";
        public static final String FIELD_MINIMIZE_RADIO_USAGE = "mMinimizeRadioUsage";
        public static final String FIELD_MAXIMIZE_DOZE = "mMaximizeDoze";
        public static final String FIELD_EXTRA_EFFECTS = "mExtraEffects";
        // NOTE: new field strings must match the variable names in ZenDeviceEffects

        /**
         * Create a DeviceEffectsDiff representing the difference between two ZenDeviceEffects
         * objects.
         * @param from previous ZenDeviceEffects
         * @param to new ZenDeviceEffects
         * @return The diff between the two given ZenDeviceEffects
         */
        public DeviceEffectsDiff(ZenDeviceEffects from, ZenDeviceEffects to) {
            super(from, to);
            // Short-circuit the both-null case
            if (from == null && to == null) {
                return;
            }
            if (hasExistenceChange()) {
                // either added or removed; return here. otherwise (they're not both null) there's
                // field diffs.
                return;
            }

            // Compare all fields, knowing there's some diff and that neither is null.
            if (from.shouldDisplayGrayscale() != to.shouldDisplayGrayscale()) {
                addField(FIELD_GRAYSCALE, new FieldDiff<>(from.shouldDisplayGrayscale(),
                        to.shouldDisplayGrayscale()));
            }
            if (from.shouldSuppressAmbientDisplay() != to.shouldSuppressAmbientDisplay()) {
                addField(FIELD_SUPPRESS_AMBIENT_DISPLAY,
                        new FieldDiff<>(from.shouldSuppressAmbientDisplay(),
                                to.shouldSuppressAmbientDisplay()));
            }
            if (from.shouldDimWallpaper() != to.shouldDimWallpaper()) {
                addField(FIELD_DIM_WALLPAPER, new FieldDiff<>(from.shouldDimWallpaper(),
                        to.shouldDimWallpaper()));
            }
            if (from.shouldUseNightMode() != to.shouldUseNightMode()) {
                addField(FIELD_NIGHT_MODE, new FieldDiff<>(from.shouldUseNightMode(),
                        to.shouldUseNightMode()));
            }
            if (from.shouldDisableAutoBrightness() != to.shouldDisableAutoBrightness()) {
                addField(FIELD_DISABLE_AUTO_BRIGHTNESS,
                        new FieldDiff<>(from.shouldDisableAutoBrightness(),
                                to.shouldDisableAutoBrightness()));
            }
            if (from.shouldDisableTapToWake() != to.shouldDisableTapToWake()) {
                addField(FIELD_DISABLE_TAP_TO_WAKE, new FieldDiff<>(from.shouldDisableTapToWake(),
                        to.shouldDisableTapToWake()));
            }
            if (from.shouldDisableTiltToWake() != to.shouldDisableTiltToWake()) {
                addField(FIELD_DISABLE_TILT_TO_WAKE,
                        new FieldDiff<>(from.shouldDisableTiltToWake(),
                                to.shouldDisableTiltToWake()));
            }
            if (from.shouldDisableTouch() != to.shouldDisableTouch()) {
                addField(FIELD_DISABLE_TOUCH, new FieldDiff<>(from.shouldDisableTouch(),
                        to.shouldDisableTouch()));
            }
            if (from.shouldMinimizeRadioUsage() != to.shouldMinimizeRadioUsage()) {
                addField(FIELD_MINIMIZE_RADIO_USAGE,
                        new FieldDiff<>(from.shouldMinimizeRadioUsage(),
                                to.shouldMinimizeRadioUsage()));
            }
            if (from.shouldMaximizeDoze() != to.shouldMaximizeDoze()) {
                addField(FIELD_MAXIMIZE_DOZE, new FieldDiff<>(from.shouldMaximizeDoze(),
                        to.shouldMaximizeDoze()));
            }
            if (!Objects.equals(from.getExtraEffects(), to.getExtraEffects())) {
                addField(FIELD_EXTRA_EFFECTS, new FieldDiff<>(from.getExtraEffects(),
                        to.getExtraEffects()));
            }
        }

        /**
         * Returns whether this object represents an actual diff.
         */
        @Override
        public boolean hasDiff() {
            return hasExistenceChange() || hasFieldDiffs();
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder("ZenDeviceEffectsDiff{");
            if (!hasDiff()) {
                sb.append("no changes");
            }

            // If added or deleted, we just append that.
            if (hasExistenceChange()) {
                if (wasAdded()) {
                    sb.append("added");
                } else if (wasRemoved()) {
                    sb.append("removed");
                }
            }

            // Append all of the individual field diffs
            boolean first = true;
            for (String key : fieldNamesWithDiff()) {
                FieldDiff diff = getDiffForField(key);
                if (diff == null) {
                    // The diff should not have null diffs added, but we add this to be defensive.
                    continue;
                }
                if (first) {
                    first = false;
                } else {
                    sb.append(", ");
                }

                sb.append(key);
                sb.append(":");
                sb.append(diff);
            }

            return sb.append("}").toString();
        }
    }

}
+93 −7
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
@@ -127,7 +128,7 @@ public class ZenModeDiffTest extends UiServiceTestCase {
        ArrayMap<String, Object> expectedFrom = new ArrayMap<>();
        ArrayMap<String, Object> expectedTo = new ArrayMap<>();
        List<Field> fieldsForDiff = getFieldsForDiffCheck(
                ZenModeConfig.ZenRule.class, getZenRuleExemptFields());
                ZenModeConfig.ZenRule.class, getZenRuleExemptFields(), false);
        generateFieldDiffs(r1, r2, fieldsForDiff, expectedFrom, expectedTo);

        ZenModeDiff.RuleDiff d = new ZenModeDiff.RuleDiff(r1, r2);
@@ -145,6 +146,85 @@ public class ZenModeDiffTest extends UiServiceTestCase {
        }
    }

    @Test
    public void testDeviceEffectsDiff_addRemoveSame() {
        // Test add, remove, and both sides same
        ZenDeviceEffects effects = new ZenDeviceEffects.Builder().build();

        // Both sides same rule
        ZenModeDiff.DeviceEffectsDiff dSame = new ZenModeDiff.DeviceEffectsDiff(effects, effects);
        assertFalse(dSame.hasDiff());

        // from existent rule to null: expect deleted
        ZenModeDiff.DeviceEffectsDiff deleted = new ZenModeDiff.DeviceEffectsDiff(effects, null);
        assertTrue(deleted.hasDiff());
        assertTrue(deleted.wasRemoved());

        // from null to new rule: expect added
        ZenModeDiff.DeviceEffectsDiff added = new ZenModeDiff.DeviceEffectsDiff(null, effects);
        assertTrue(added.hasDiff());
        assertTrue(added.wasAdded());
    }

    @Test
    public void testDeviceEffectsDiff_fieldDiffs() throws Exception {
        // Start these the same
        ZenDeviceEffects effects1 = new ZenDeviceEffects.Builder().build();
        ZenDeviceEffects effects2 = new ZenDeviceEffects.Builder().build();

        // maps mapping field name -> expected output value as we set diffs
        ArrayMap<String, Object> expectedFrom = new ArrayMap<>();
        ArrayMap<String, Object> expectedTo = new ArrayMap<>();
        List<Field> fieldsForDiff = getFieldsForDiffCheck(
                ZenDeviceEffects.class, Collections.emptySet() /*no exempt fields*/, true);
        generateFieldDiffs(effects1, effects2, fieldsForDiff, expectedFrom, expectedTo);

        ZenModeDiff.DeviceEffectsDiff d = new ZenModeDiff.DeviceEffectsDiff(effects1, effects2);
        assertTrue(d.hasDiff());

        // Now diff them and check that each of the fields has a diff
        for (Field f : fieldsForDiff) {
            String name = f.getName();
            assertNotNull("diff not found for field: " + name, d.getDiffForField(name));
            assertTrue(d.getDiffForField(name).hasDiff());
            assertTrue("unexpected field: " + name, expectedFrom.containsKey(name));
            assertTrue("unexpected field: " + name, expectedTo.containsKey(name));
            assertEquals(expectedFrom.get(name), d.getDiffForField(name).from());
            assertEquals(expectedTo.get(name), d.getDiffForField(name).to());
        }
    }

    @Test
    public void testDeviceEffectsDiff_toString() throws Exception {
        // Ensure device effects toString is readable.
        ZenDeviceEffects effects1 = new ZenDeviceEffects.Builder().build();
        ZenDeviceEffects effects2 = new ZenDeviceEffects.Builder().build();

        ZenModeDiff.DeviceEffectsDiff d = new ZenModeDiff.DeviceEffectsDiff(effects1, effects2);
        assertThat(d.toString()).isEqualTo("ZenDeviceEffectsDiff{no changes}");

        d = new ZenModeDiff.DeviceEffectsDiff(effects1, null);
        assertThat(d.toString()).isEqualTo("ZenDeviceEffectsDiff{removed}");

        d = new ZenModeDiff.DeviceEffectsDiff(null, effects2);
        assertThat(d.toString()).isEqualTo("ZenDeviceEffectsDiff{added}");

        ArrayMap<String, Object> expectedFrom = new ArrayMap<>();
        ArrayMap<String, Object> expectedTo = new ArrayMap<>();
        List<Field> fieldsForDiff = getFieldsForDiffCheck(
                ZenDeviceEffects.class, Collections.emptySet() /*no exempt fields*/, true);
        generateFieldDiffs(effects1, effects2, fieldsForDiff, expectedFrom, expectedTo);

        d = new ZenModeDiff.DeviceEffectsDiff(effects1, effects2);
        assertThat(d.toString()).isEqualTo("ZenDeviceEffectsDiff{mNightMode:true->false, "
                + "mDisableTapToWake:true->false, mDisableAutoBrightness:true->false, "
                + "mSuppressAmbientDisplay:true->false, mDisableTiltToWake:true->false, "
                + "mGrayscale:true->false, mDisableTouch:true->false, mMaximizeDoze:true->false, "
                + "mMinimizeRadioUsage:true->false, mExtraEffects:null->[], "
                + "mDimWallpaper:true->false}");
    }


    private static Set<String> getZenRuleExemptFields() {
        // "Metadata" fields are never compared.
        Set<String> exemptFields = new LinkedHashSet<>(
@@ -194,7 +274,7 @@ public class ZenModeDiffTest extends UiServiceTestCase {
        ArrayMap<String, Object> expectedFrom = new ArrayMap<>();
        ArrayMap<String, Object> expectedTo = new ArrayMap<>();
        List<Field> fieldsForDiff = getFieldsForDiffCheck(
                ZenModeConfig.class, getConfigExemptAndFlaggedFields());
                ZenModeConfig.class, getConfigExemptAndFlaggedFields(), false);
        generateFieldDiffs(c1, c2, fieldsForDiff, expectedFrom, expectedTo);

        ZenModeDiff.ConfigDiff d = new ZenModeDiff.ConfigDiff(c1, c2);
@@ -223,7 +303,7 @@ public class ZenModeDiffTest extends UiServiceTestCase {
        ArrayMap<String, Object> expectedFrom = new ArrayMap<>();
        ArrayMap<String, Object> expectedTo = new ArrayMap<>();
        List<Field> fieldsForDiff = getFieldsForDiffCheck(
                ZenModeConfig.class, ZEN_MODE_CONFIG_EXEMPT_FIELDS);
                ZenModeConfig.class, ZEN_MODE_CONFIG_EXEMPT_FIELDS, false);
        generateFieldDiffs(c1, c2, fieldsForDiff, expectedFrom, expectedTo);

        ZenModeDiff.ConfigDiff d = new ZenModeDiff.ConfigDiff(c1, c2);
@@ -359,17 +439,23 @@ public class ZenModeDiffTest extends UiServiceTestCase {

    // Get the fields on which we would want to check a diff. The requirements are: not final or/
    // static (as these should/can never change), and not in a specific list that's exempted.
    private List<Field> getFieldsForDiffCheck(Class<?> c, Set<String> exemptNames)
    private List<Field> getFieldsForDiffCheck(Class<?> c, Set<String> exemptNames,
                                              boolean includeFinal)
            throws SecurityException {
        Field[] fields = c.getDeclaredFields();
        ArrayList<Field> out = new ArrayList<>();

        for (Field field : fields) {
            // Check for exempt reasons
            // Anything in provided exemptNames is skipped.
            if (exemptNames.contains(field.getName())) {
                continue;
            }
            int m = field.getModifiers();
            if (Modifier.isFinal(m)
                    || Modifier.isStatic(m)
                    || exemptNames.contains(field.getName())) {
            if (Modifier.isStatic(m)) {
                continue;
            }
            if (!includeFinal && Modifier.isFinal(m)) {
                continue;
            }
            out.add(field);