Loading packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt +9 −8 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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()) Loading @@ -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, Loading @@ -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)), Loading Loading @@ -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 Loading Loading @@ -170,6 +170,7 @@ public class ColorScheme( " accent1: ${humanReadable(accent1)}\n" + " accent2: ${humanReadable(accent2)}\n" + " accent3: ${humanReadable(accent3)}\n" + " style: $style\n" + "}" } Loading packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java +2 −0 Original line number Diff line number Diff line Loading @@ -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"; Loading packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java +27 −39 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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 Loading @@ -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"; Loading Loading @@ -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); Loading @@ -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) { Loading @@ -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); Loading @@ -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 Loading Loading @@ -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); Loading @@ -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); } } packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java +47 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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() { Loading @@ -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; } }; Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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; } Loading Loading @@ -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))); Loading Loading
packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt +9 −8 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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()) Loading @@ -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, Loading @@ -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)), Loading Loading @@ -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 Loading Loading @@ -170,6 +170,7 @@ public class ColorScheme( " accent1: ${humanReadable(accent1)}\n" + " accent2: ${humanReadable(accent2)}\n" + " accent3: ${humanReadable(accent3)}\n" + " style: $style\n" + "}" } Loading
packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java +2 −0 Original line number Diff line number Diff line Loading @@ -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"; Loading
packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java +27 −39 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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 Loading @@ -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"; Loading Loading @@ -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); Loading @@ -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) { Loading @@ -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); Loading @@ -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 Loading Loading @@ -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); Loading @@ -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); } }
packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java +47 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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() { Loading @@ -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; } }; Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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; } Loading Loading @@ -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))); Loading