From 86d5777e63a5bec1099a487c9ca63ef1dad50bb7 Mon Sep 17 00:00:00 2001 From: Suphon Thanakornpakapong Date: Mon, 25 Oct 2021 09:14:00 +0700 Subject: [PATCH] Override widget colors with accent --- lawnchair/res/values-v31/config.xml | 4 + .../app/lawnchair/AccentColorExtractor.java | 191 ++++++++++++++++++ .../src/app/lawnchair/theme/ThemeProvider.kt | 36 +++- 3 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 lawnchair/res/values-v31/config.xml create mode 100644 lawnchair/src/app/lawnchair/AccentColorExtractor.java diff --git a/lawnchair/res/values-v31/config.xml b/lawnchair/res/values-v31/config.xml new file mode 100644 index 0000000000..95efc64315 --- /dev/null +++ b/lawnchair/res/values-v31/config.xml @@ -0,0 +1,4 @@ + + + app.lawnchair.AccentColorExtractor + diff --git a/lawnchair/src/app/lawnchair/AccentColorExtractor.java b/lawnchair/src/app/lawnchair/AccentColorExtractor.java new file mode 100644 index 0000000000..6c19f36287 --- /dev/null +++ b/lawnchair/src/app/lawnchair/AccentColorExtractor.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2021 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 app.lawnchair; + +import android.app.WallpaperColors; +import android.content.Context; +import android.graphics.RectF; +import android.os.Build; +import android.util.SparseIntArray; +import android.widget.RemoteViews; + +import androidx.annotation.Keep; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; + +import com.android.launcher3.widget.LocalColorExtractor; + +import java.util.List; +import java.util.Map; + +import app.lawnchair.theme.ThemeProvider; +import dev.kdrag0n.colorkt.Color; +import dev.kdrag0n.colorkt.rgb.Srgb; +import dev.kdrag0n.monet.theme.ColorScheme; + +@RequiresApi(api = Build.VERSION_CODES.S) +public class AccentColorExtractor extends LocalColorExtractor implements ThemeProvider.ColorSchemeChangeListener { + + private final ThemeProvider mThemeProvider; + private final RectF mTmpRect = new RectF(); + private Listener mListener; + + @Keep + public AccentColorExtractor(Context context) { + mThemeProvider = ThemeProvider.INSTANCE.get(context); + } + + @Override + public void setListener(@Nullable Listener listener) { + mListener = listener; + notifyListener(mTmpRect, null); + } + + @Override + public void addLocation(List locations) { + mThemeProvider.addListener(this); + } + + @Override + public void removeLocations() { + mThemeProvider.removeListener(this); + } + + @Nullable + protected SparseIntArray generateColorsOverride(ColorScheme colorScheme) { + SparseIntArray colorRes = new SparseIntArray(5 * 13); + + addColorsToArray(colorScheme.getAccent1(), ACCENT1_RES, colorRes); + addColorsToArray(colorScheme.getAccent2(), ACCENT2_RES, colorRes); + addColorsToArray(colorScheme.getAccent3(), ACCENT3_RES, colorRes); + addColorsToArray(colorScheme.getNeutral1(), NEUTRAL1_RES, colorRes); + addColorsToArray(colorScheme.getNeutral2(), NEUTRAL2_RES, colorRes); + + return colorRes; + } + + @Override + public void applyColorsOverride(Context base, WallpaperColors colors) { + RemoteViews.ColorResources res = + RemoteViews.ColorResources.create(base, generateColorsOverride(colors)); + if (res != null) { + res.apply(base); + } + } + + @Override + public void onColorSchemeChanged() { + notifyListener(mTmpRect, null); + } + + protected void notifyListener(RectF area, WallpaperColors colors) { + if (mListener != null) { + mListener.onColorsChanged(area, generateColorsOverride(mThemeProvider.getColorScheme())); + } + } + + // Shade number -> color resource ID maps + private static final SparseIntArray ACCENT1_RES = new SparseIntArray(13); + private static final SparseIntArray ACCENT2_RES = new SparseIntArray(13); + private static final SparseIntArray ACCENT3_RES = new SparseIntArray(13); + private static final SparseIntArray NEUTRAL1_RES = new SparseIntArray(13); + private static final SparseIntArray NEUTRAL2_RES = new SparseIntArray(13); + + static { + ACCENT1_RES.put( 0, android.R.color.system_accent1_0); + ACCENT1_RES.put( 10, android.R.color.system_accent1_10); + ACCENT1_RES.put( 50, android.R.color.system_accent1_50); + ACCENT1_RES.put( 100, android.R.color.system_accent1_100); + ACCENT1_RES.put( 200, android.R.color.system_accent1_200); + ACCENT1_RES.put( 300, android.R.color.system_accent1_300); + ACCENT1_RES.put( 400, android.R.color.system_accent1_400); + ACCENT1_RES.put( 500, android.R.color.system_accent1_500); + ACCENT1_RES.put( 600, android.R.color.system_accent1_600); + ACCENT1_RES.put( 700, android.R.color.system_accent1_700); + ACCENT1_RES.put( 800, android.R.color.system_accent1_800); + ACCENT1_RES.put( 900, android.R.color.system_accent1_900); + ACCENT1_RES.put(1000, android.R.color.system_accent1_1000); + + ACCENT2_RES.put( 0, android.R.color.system_accent2_0); + ACCENT2_RES.put( 10, android.R.color.system_accent2_10); + ACCENT2_RES.put( 50, android.R.color.system_accent2_50); + ACCENT2_RES.put( 100, android.R.color.system_accent2_100); + ACCENT2_RES.put( 200, android.R.color.system_accent2_200); + ACCENT2_RES.put( 300, android.R.color.system_accent2_300); + ACCENT2_RES.put( 400, android.R.color.system_accent2_400); + ACCENT2_RES.put( 500, android.R.color.system_accent2_500); + ACCENT2_RES.put( 600, android.R.color.system_accent2_600); + ACCENT2_RES.put( 700, android.R.color.system_accent2_700); + ACCENT2_RES.put( 800, android.R.color.system_accent2_800); + ACCENT2_RES.put( 900, android.R.color.system_accent2_900); + ACCENT2_RES.put(1000, android.R.color.system_accent2_1000); + + ACCENT3_RES.put( 0, android.R.color.system_accent3_0); + ACCENT3_RES.put( 10, android.R.color.system_accent3_10); + ACCENT3_RES.put( 50, android.R.color.system_accent3_50); + ACCENT3_RES.put( 100, android.R.color.system_accent3_100); + ACCENT3_RES.put( 200, android.R.color.system_accent3_200); + ACCENT3_RES.put( 300, android.R.color.system_accent3_300); + ACCENT3_RES.put( 400, android.R.color.system_accent3_400); + ACCENT3_RES.put( 500, android.R.color.system_accent3_500); + ACCENT3_RES.put( 600, android.R.color.system_accent3_600); + ACCENT3_RES.put( 700, android.R.color.system_accent3_700); + ACCENT3_RES.put( 800, android.R.color.system_accent3_800); + ACCENT3_RES.put( 900, android.R.color.system_accent3_900); + ACCENT3_RES.put(1000, android.R.color.system_accent3_1000); + + NEUTRAL1_RES.put( 0, android.R.color.system_neutral1_0); + NEUTRAL1_RES.put( 10, android.R.color.system_neutral1_10); + NEUTRAL1_RES.put( 50, android.R.color.system_neutral1_50); + NEUTRAL1_RES.put( 100, android.R.color.system_neutral1_100); + NEUTRAL1_RES.put( 200, android.R.color.system_neutral1_200); + NEUTRAL1_RES.put( 300, android.R.color.system_neutral1_300); + NEUTRAL1_RES.put( 400, android.R.color.system_neutral1_400); + NEUTRAL1_RES.put( 500, android.R.color.system_neutral1_500); + NEUTRAL1_RES.put( 600, android.R.color.system_neutral1_600); + NEUTRAL1_RES.put( 700, android.R.color.system_neutral1_700); + NEUTRAL1_RES.put( 800, android.R.color.system_neutral1_800); + NEUTRAL1_RES.put( 900, android.R.color.system_neutral1_900); + NEUTRAL1_RES.put(1000, android.R.color.system_neutral1_1000); + + NEUTRAL2_RES.put( 0, android.R.color.system_neutral2_0); + NEUTRAL2_RES.put( 10, android.R.color.system_neutral2_10); + NEUTRAL2_RES.put( 50, android.R.color.system_neutral2_50); + NEUTRAL2_RES.put( 100, android.R.color.system_neutral2_100); + NEUTRAL2_RES.put( 200, android.R.color.system_neutral2_200); + NEUTRAL2_RES.put( 300, android.R.color.system_neutral2_300); + NEUTRAL2_RES.put( 400, android.R.color.system_neutral2_400); + NEUTRAL2_RES.put( 500, android.R.color.system_neutral2_500); + NEUTRAL2_RES.put( 600, android.R.color.system_neutral2_600); + NEUTRAL2_RES.put( 700, android.R.color.system_neutral2_700); + NEUTRAL2_RES.put( 800, android.R.color.system_neutral2_800); + NEUTRAL2_RES.put( 900, android.R.color.system_neutral2_900); + NEUTRAL2_RES.put(1000, android.R.color.system_neutral2_1000); + } + + private static void addColorsToArray(Map swatch, + SparseIntArray resMap, SparseIntArray array) { + for (Map.Entry entry : swatch.entrySet()) { + int shade = entry.getKey(); + int resId = resMap.get(shade, -1); + if (resId != -1) { + Srgb color = (Srgb) entry.getValue(); + array.put(resId, 0xff000000 | color.toRgb8()); + } + } + } +} diff --git a/lawnchair/src/app/lawnchair/theme/ThemeProvider.kt b/lawnchair/src/app/lawnchair/theme/ThemeProvider.kt index e273eaaa45..307a674255 100644 --- a/lawnchair/src/app/lawnchair/theme/ThemeProvider.kt +++ b/lawnchair/src/app/lawnchair/theme/ThemeProvider.kt @@ -9,6 +9,7 @@ import android.os.Looper import android.os.PatternMatcher import android.util.SparseArray import androidx.core.graphics.ColorUtils +import app.lawnchair.preferences.PreferenceChangeListener import app.lawnchair.preferences.PreferenceManager import app.lawnchair.theme.color.AndroidColor import app.lawnchair.theme.color.ColorOption @@ -32,17 +33,31 @@ import dev.kdrag0n.monet.theme.MaterialYouTargets class ThemeProvider(private val context: Context) { private val prefs = PreferenceManager.getInstance(context) + private val wallpaperManager = WallpaperManagerCompat.INSTANCE.get(context) private val accentColor by prefs.accentColor private val enableColorfulTheme by prefs.enableColorfulTheme private val targets = MaterialYouTargets(1.0, false, viewingCondition) private val colorSchemeMap = SparseArray() + private val listeners = mutableListOf() init { if (Utilities.ATLEAST_S) { colorSchemeMap.append(0, SystemColorScheme(context)) registerOverlayChangedListener() } + wallpaperManager.addOnChangeListener(object : WallpaperManagerCompat.OnColorsChangedListener { + override fun onColorsChanged() { + if (accentColor is ColorOption.WallpaperPrimary) { + notifyColorSchemeChanged() + } + } + }) + prefs.accentColor.addListener(object : PreferenceChangeListener { + override fun onPreferenceChange() { + notifyColorSchemeChanged() + } + }) } private fun registerOverlayChangedListener() { @@ -53,6 +68,9 @@ class ThemeProvider(private val context: Context) { object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { colorSchemeMap.append(0, SystemColorScheme(context)) + if (accentColor is ColorOption.SystemAccent) { + notifyColorSchemeChanged() + } } }, packageFilter, @@ -64,7 +82,6 @@ class ThemeProvider(private val context: Context) { val colorScheme get() = when (val accentColor = this.accentColor) { is ColorOption.SystemAccent -> systemColorScheme is ColorOption.WallpaperPrimary -> { - val wallpaperManager = WallpaperManagerCompat.INSTANCE.get(context) val wallpaperPrimary = wallpaperManager.wallpaperColors?.primaryColor getColorScheme(wallpaperPrimary ?: ColorOption.LawnchairBlue.color) } @@ -86,6 +103,19 @@ class ThemeProvider(private val context: Context) { return colorScheme } + fun addListener(listener: ColorSchemeChangeListener) { + listeners.add(listener) + } + + fun removeListener(listener: ColorSchemeChangeListener) { + listeners.remove(listener) + } + + private fun notifyColorSchemeChanged() { + ArrayList(listeners) + .forEach(ColorSchemeChangeListener::onColorSchemeChanged) + } + companion object { @JvmField val INSTANCE = MainThreadInitializedObject(::ThemeProvider) @@ -97,6 +127,10 @@ class ThemeProvider(private val context: Context) { Illuminants.D65.toAbs(CieXyzAbs.DEFAULT_SDR_WHITE_LUMINANCE) ) } + + interface ColorSchemeChangeListener { + fun onColorSchemeChanged() + } } fun Color.toAndroidColor(): Int {