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

Commit 7719202d authored by Lucas Dupin's avatar Lucas Dupin
Browse files

Hook up new styles to customization setting

The new styles:
- spritz
- expressive
- vibrant

Are now correctly hooked up to the customization setting, allowing for
picker integration.

Bug: 195969565
Test: atest ThemeOverlayControllerTest
Test: adb shell settings put secure theme_customization_overlay_packages '''\{\"android.theme.customization.system_palette\":\"B1611C\",\"android.theme.customization.theme_style\":\"SPRITZ\"}'''
Change-Id: I106f05b7f0aade470b8216b47e14ca4aa6db0970
parent a94b1660
Loading
Loading
Loading
Loading
+9 −8
Original line number Diff line number Diff line
@@ -31,15 +31,15 @@ const val ACCENT1_CHROMA = 48.0f
const val GOOGLE_BLUE = 0xFF1b6ef3.toInt()
const val MIN_CHROMA = 5

enum class ChromaStrategy {
internal enum class ChromaStrategy {
    EQ, GTE
}

enum class HueStrategy {
internal enum class HueStrategy {
    SOURCE, ADD, SUBTRACT
}

class Chroma(val strategy: ChromaStrategy, val value: Double) {
internal class Chroma(val strategy: ChromaStrategy, val value: Double) {
    fun get(sourceChroma: Double): Double {
        return when (strategy) {
            ChromaStrategy.EQ -> value
@@ -48,7 +48,7 @@ class Chroma(val strategy: ChromaStrategy, val value: Double) {
    }
}

class Hue(val strategy: HueStrategy = HueStrategy.SOURCE, val value: Double = 0.0) {
internal class Hue(val strategy: HueStrategy = HueStrategy.SOURCE, val value: Double = 0.0) {
    fun get(sourceHue: Double): Double {
        return when (strategy) {
            HueStrategy.SOURCE -> sourceHue
@@ -58,7 +58,7 @@ class Hue(val strategy: HueStrategy = HueStrategy.SOURCE, val value: Double = 0.
    }
}

class TonalSpec(val hue: Hue = Hue(), val chroma: Chroma) {
internal class TonalSpec(val hue: Hue = Hue(), val chroma: Chroma) {
    fun shades(sourceColor: Cam): List<Int> {
        val hue = hue.get(sourceColor.hue.toDouble())
        val chroma = chroma.get(sourceColor.chroma.toDouble())
@@ -66,7 +66,7 @@ class TonalSpec(val hue: Hue = Hue(), val chroma: Chroma) {
    }
}

class CoreSpec(
internal class CoreSpec(
    val a1: TonalSpec,
    val a2: TonalSpec,
    val a3: TonalSpec,
@@ -74,7 +74,7 @@ class CoreSpec(
    val n2: TonalSpec
)

enum class Style(val coreSpec: CoreSpec) {
enum class Style(internal val coreSpec: CoreSpec) {
    SPRITZ(CoreSpec(
            a1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 4.0)),
            a2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 4.0)),
@@ -105,7 +105,7 @@ enum class Style(val coreSpec: CoreSpec) {
    )),
}

public class ColorScheme(
class ColorScheme(
    @ColorInt seed: Int,
    val darkTheme: Boolean,
    val style: Style = Style.TONAL_SPOT
@@ -170,6 +170,7 @@ public class ColorScheme(
                "  accent1: ${humanReadable(accent1)}\n" +
                "  accent2: ${humanReadable(accent2)}\n" +
                "  accent3: ${humanReadable(accent3)}\n" +
                "  style: $style\n" +
                "}"
    }

+2 −0
Original line number Diff line number Diff line
@@ -66,6 +66,8 @@ public class ThemeOverlayApplier implements Dumpable {
            "android.theme.customization.accent_color";
    static final String OVERLAY_CATEGORY_SYSTEM_PALETTE =
            "android.theme.customization.system_palette";
    static final String OVERLAY_CATEGORY_THEME_STYLE =
            "android.theme.customization.theme_style";

    static final String OVERLAY_COLOR_SOURCE = "android.theme.customization.color_source";

+27 −39
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.monet.ColorScheme;
import com.android.systemui.monet.Style;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
@@ -121,8 +122,8 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable {
    private boolean mNeedsOverlayCreation;
    // Dominant color extracted from wallpaper, NOT the color used on the overlay
    protected int mMainWallpaperColor = Color.TRANSPARENT;
    // Accent color extracted from wallpaper, NOT the color used on the overlay
    protected int mWallpaperAccentColor = Color.TRANSPARENT;
    // Theme variant: Vibrant, Tonal, Expressive, etc
    private Style mThemeStyle = Style.TONAL_SPOT;
    // Accent colors overlay
    private FabricatedOverlay mSecondaryOverlay;
    // Neutral system colors overlay
@@ -453,26 +454,20 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable {
    private void reevaluateSystemTheme(boolean forceReload) {
        final WallpaperColors currentColors = mCurrentColors.get(mUserTracker.getUserId());
        final int mainColor;
        final int accentCandidate;
        if (currentColors == null) {
            mainColor = Color.TRANSPARENT;
            accentCandidate = Color.TRANSPARENT;
        } else {
            mainColor = getNeutralColor(currentColors);
            accentCandidate = getAccentColor(currentColors);
        }

        if (mMainWallpaperColor == mainColor && mWallpaperAccentColor == accentCandidate
                && !forceReload) {
        if (mMainWallpaperColor == mainColor && !forceReload) {
            return;
        }

        mMainWallpaperColor = mainColor;
        mWallpaperAccentColor = accentCandidate;

        if (mIsMonetEnabled) {
            mSecondaryOverlay = getOverlay(mWallpaperAccentColor, ACCENT);
            mNeutralOverlay = getOverlay(mMainWallpaperColor, NEUTRAL);
            mSecondaryOverlay = getOverlay(mMainWallpaperColor, ACCENT, mThemeStyle);
            mNeutralOverlay = getOverlay(mMainWallpaperColor, NEUTRAL, mThemeStyle);
            mNeedsOverlayCreation = true;
            if (DEBUG) {
                Log.d(TAG, "fetched overlays. accent: " + mSecondaryOverlay
@@ -497,11 +492,11 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable {
    /**
     * Given a color candidate, return an overlay definition.
     */
    protected @Nullable FabricatedOverlay getOverlay(int color, int type) {
    protected @Nullable FabricatedOverlay getOverlay(int color, int type, Style style) {
        boolean nightMode = (mContext.getResources().getConfiguration().uiMode
                & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;

        mColorScheme = new ColorScheme(color, nightMode);
        mColorScheme = new ColorScheme(color, nightMode, style);
        List<Integer> colorShades = type == ACCENT
                ? mColorScheme.getAllAccentColors() : mColorScheme.getAllNeutralColors();
        String name = type == ACCENT ? "accent" : "neutral";
@@ -537,6 +532,7 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable {
                currentUser);
        if (DEBUG) Log.d(TAG, "updateThemeOverlays. Setting: " + overlayPackageJson);
        final Map<String, OverlayIdentifier> categoryToPackage = new ArrayMap<>();
        Style newStyle = mThemeStyle;
        if (!TextUtils.isEmpty(overlayPackageJson)) {
            try {
                JSONObject object = new JSONObject(overlayPackageJson);
@@ -547,11 +543,25 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable {
                        categoryToPackage.put(category, identifier);
                    }
                }

                try {
                    newStyle = Style.valueOf(
                            object.getString(ThemeOverlayApplier.OVERLAY_CATEGORY_THEME_STYLE));
                } catch (IllegalArgumentException e) {
                    newStyle = Style.TONAL_SPOT;
                }
            } catch (JSONException e) {
                Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e);
            }
        }

        if (mIsMonetEnabled && newStyle != mThemeStyle) {
            mThemeStyle = newStyle;
            mNeutralOverlay = getOverlay(mMainWallpaperColor, NEUTRAL, mThemeStyle);
            mSecondaryOverlay = getOverlay(mMainWallpaperColor, ACCENT, mThemeStyle);
            mNeedsOverlayCreation = true;
        }

        // Let's generate system overlay if the style picker decided to override it.
        OverlayIdentifier systemPalette = categoryToPackage.get(OVERLAY_CATEGORY_SYSTEM_PALETTE);
        if (mIsMonetEnabled && systemPalette != null && systemPalette.getPackageName() != null) {
@@ -561,9 +571,11 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable {
                    colorString = "#" + colorString;
                }
                int color = Color.parseColor(colorString);
                mNeutralOverlay = getOverlay(color, NEUTRAL);
                mNeutralOverlay = getOverlay(color, NEUTRAL, mThemeStyle);
                mSecondaryOverlay = getOverlay(color, ACCENT, mThemeStyle);
                mNeedsOverlayCreation = true;
                categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE);
                categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR);
            } catch (Exception e) {
                // Color.parseColor doesn't catch any exceptions from the calls it makes
                Log.w(TAG, "Invalid color definition: " + systemPalette.getPackageName(), e);
@@ -574,30 +586,6 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable {
                // setting. We need to sanitize the input, otherwise the overlay transaction will
                // fail.
                categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE);
            } catch (NumberFormatException e) {
                // This is a package name. All good, let's continue
            }
        }

        // Same for accent color.
        OverlayIdentifier accentPalette = categoryToPackage.get(OVERLAY_CATEGORY_ACCENT_COLOR);
        if (mIsMonetEnabled && accentPalette != null && accentPalette.getPackageName() != null) {
            try {
                String colorString =  accentPalette.getPackageName().toLowerCase();
                if (!colorString.startsWith("#")) {
                    colorString = "#" + colorString;
                }
                int color = Color.parseColor(colorString);
                mSecondaryOverlay = getOverlay(color, ACCENT);
                mNeedsOverlayCreation = true;
                categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR);
            } catch (Exception e) {
                // Color.parseColor doesn't catch any exceptions from the calls it makes
                Log.w(TAG, "Invalid color definition: " + accentPalette.getPackageName(), e);
            }
        } else if (!mIsMonetEnabled && accentPalette != null) {
            try {
                Integer.parseInt(accentPalette.getPackageName().toLowerCase(), 16);
                categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR);
            } catch (NumberFormatException e) {
                // This is a package name. All good, let's continue
@@ -642,7 +630,6 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable {
    public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
        pw.println("mSystemColors=" + mCurrentColors);
        pw.println("mMainWallpaperColor=" + Integer.toHexString(mMainWallpaperColor));
        pw.println("mWallpaperAccentColor=" + Integer.toHexString(mWallpaperAccentColor));
        pw.println("mSecondaryOverlay=" + mSecondaryOverlay);
        pw.println("mNeutralOverlay=" + mNeutralOverlay);
        pw.println("mIsMonetEnabled=" + mIsMonetEnabled);
@@ -650,5 +637,6 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable {
        pw.println("mNeedsOverlayCreation=" + mNeedsOverlayCreation);
        pw.println("mAcceptColorEvents=" + mAcceptColorEvents);
        pw.println("mDeferredThemeEvaluation=" + mDeferredThemeEvaluation);
        pw.println("mThemeStyle=" + mThemeStyle);
    }
}
+47 −4
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.om.FabricatedOverlay;
import android.content.om.OverlayIdentifier;
import android.database.ContentObserver;
import android.graphics.Color;
import android.os.Handler;
import android.os.UserHandle;
@@ -55,6 +56,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.monet.Style;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
@@ -117,6 +119,9 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
    private ArgumentCaptor<WakefulnessLifecycle.Observer> mWakefulnessLifecycleObserver;
    @Captor
    private ArgumentCaptor<UserTracker.Callback> mUserTrackerCallback;
    @Captor
    private ArgumentCaptor<ContentObserver> mSettingsObserver;
    private Style mCurrentStyle;

    @Before
    public void setup() {
@@ -130,10 +135,11 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
                mUserTracker, mDumpManager, mFeatureFlags, mWakefulnessLifecycle) {
            @Nullable
            @Override
            protected FabricatedOverlay getOverlay(int color, int type) {
            protected FabricatedOverlay getOverlay(int color, int type, Style style) {
                FabricatedOverlay overlay = mock(FabricatedOverlay.class);
                when(overlay.getIdentifier())
                        .thenReturn(new OverlayIdentifier(Integer.toHexString(color | 0xff000000)));
                mCurrentStyle = style;
                return overlay;
            }
        };
@@ -148,6 +154,10 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
        verify(mWakefulnessLifecycle).addObserver(mWakefulnessLifecycleObserver.capture());
        verify(mDumpManager).registerDumpable(any(), any());
        verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture());
        verify(mSecureSettings).registerContentObserverForUser(
                eq(Settings.Secure.getUriFor(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES)),
                eq(false), mSettingsObserver.capture(), eq(UserHandle.USER_ALL)
        );
    }

    @Test
@@ -321,6 +331,40 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
    }

    @Test
    public void onSettingChanged_honorThemeStyle() {
        when(mDeviceProvisionedController.isUserSetup(anyInt())).thenReturn(true);
        for (Style style : Style.values()) {
            reset(mSecureSettings);

            String jsonString = "{\"android.theme.customization.system_palette\":\"A16B00\","
                    + "\"android.theme.customization.theme_style\":\"" + style.name() + "\"}";

            when(mSecureSettings.getStringForUser(
                    eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
                    .thenReturn(jsonString);

            mSettingsObserver.getValue().onChange(true, null, 0, mUserTracker.getUserId());

            assertThat(mCurrentStyle).isEqualTo(style);
        }
    }

    @Test
    public void onSettingChanged_invalidStyle() {
        when(mDeviceProvisionedController.isUserSetup(anyInt())).thenReturn(true);
        String jsonString = "{\"android.theme.customization.system_palette\":\"A16B00\","
                + "\"android.theme.customization.theme_style\":\"some_invalid_name\"}";

        when(mSecureSettings.getStringForUser(
                eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
                .thenReturn(jsonString);

        mSettingsObserver.getValue().onChange(true, null, 0, mUserTracker.getUserId());

        assertThat(mCurrentStyle).isEqualTo(Style.TONAL_SPOT);
    }

    @Test
    public void onWallpaperColorsChanged_ResetThemeWithNewHomeAndLockWallpaper() {
        // Should ask for a new theme when wallpaper colors change
@@ -611,11 +655,10 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
                mUserTracker, mDumpManager, mFeatureFlags, mWakefulnessLifecycle) {
            @Nullable
            @Override
            protected FabricatedOverlay getOverlay(int color, int type) {
            protected FabricatedOverlay getOverlay(int color, int type, Style style) {
                FabricatedOverlay overlay = mock(FabricatedOverlay.class);
                when(overlay.getIdentifier())
                        .thenReturn(new OverlayIdentifier("com.thebest.livewallpaperapp.ever"));

                return overlay;
            }

@@ -648,7 +691,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
                mUserTracker, mDumpManager, mFeatureFlags, mWakefulnessLifecycle) {
            @Nullable
            @Override
            protected FabricatedOverlay getOverlay(int color, int type) {
            protected FabricatedOverlay getOverlay(int color, int type, Style style) {
                FabricatedOverlay overlay = mock(FabricatedOverlay.class);
                when(overlay.getIdentifier())
                        .thenReturn(new OverlayIdentifier(Integer.toHexString(color | 0xff000000)));