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

Commit 63282b49 authored by Lucas Dupin's avatar Lucas Dupin Committed by Android (Google) Code Review
Browse files

Merge "Hook up new styles to customization setting"

parents 0ceba2c3 7719202d
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)));