diff --git a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt new file mode 100644 index 0000000000000..c1f0c58e56441 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2023 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 com.android.systemui.theme + +import android.util.Pair +import com.android.systemui.monet.dynamiccolor.DynamicColor +import com.android.systemui.monet.dynamiccolor.MaterialDynamicColors as MDC + +class DynamicColors { + companion object { + @JvmField + val ALL_DYNAMIC_COLORS_MAPPED: List> = + arrayListOf( + Pair.create("primary_container", MDC.primaryContainer), + Pair.create("on_primary_container", MDC.onPrimaryContainer), + Pair.create("primary", MDC.primary), + Pair.create("on_primary", MDC.onPrimary), + Pair.create("secondary_container", MDC.secondaryContainer), + Pair.create("on_secondary_container", MDC.onSecondaryContainer), + Pair.create("secondary", MDC.secondary), + Pair.create("on_secondary", MDC.onSecondary), + Pair.create("tertiary_container", MDC.tertiaryContainer), + Pair.create("on_tertiary_container", MDC.onTertiaryContainer), + Pair.create("tertiary", MDC.tertiary), + Pair.create("on_tertiary", MDC.onTertiary), + Pair.create("background", MDC.background), + Pair.create("on_background", MDC.onBackground), + Pair.create("surface", MDC.surface), + Pair.create("on_surface", MDC.onSurface), + Pair.create("surface_container_low", MDC.surfaceContainerLow), + Pair.create("surface_container_lowest", MDC.surfaceContainerLowest), + Pair.create("surface_container", MDC.surfaceContainer), + Pair.create("surface_container_high", MDC.surfaceContainerHigh), + Pair.create("surface_container_highest", MDC.surfaceContainerHighest), + Pair.create("surface_bright", MDC.surfaceBright), + Pair.create("surface_dim", MDC.surfaceDim), + Pair.create("surface_variant", MDC.surfaceVariant), + Pair.create("on_surface_variant", MDC.onSurfaceVariant), + Pair.create("outline", MDC.outline), + Pair.create("error", MDC.error), + Pair.create("on_error", MDC.onError), + Pair.create("error_container", MDC.errorContainer), + Pair.create("on_error_container", MDC.onErrorContainer), + Pair.create("primary_fixed", MDC.primaryFixed), + Pair.create("primary_fixed_darker", MDC.primaryFixedDarker), + Pair.create("on_primary_fixed", MDC.onPrimaryFixed), + Pair.create("on_primary_fixed_variant", MDC.onPrimaryFixedVariant), + Pair.create("secondary_fixed", MDC.secondaryFixed), + Pair.create("secondary_fixed_darker", MDC.secondaryFixedDarker), + Pair.create("on_secondary_fixed", MDC.onSecondaryFixed), + Pair.create("on_secondary_fixed_variant", MDC.onSecondaryFixedVariant), + Pair.create("tertiary_fixed", MDC.tertiaryFixed), + Pair.create("tertiary_fixed_darker", MDC.tertiaryFixedDarker), + Pair.create("on_tertiary_fixed", MDC.onTertiaryFixed), + Pair.create("on_tertiary_fixed_variant", MDC.onTertiaryFixedVariant), + Pair.create("control_activated", MDC.controlActivated), + Pair.create("control_normal", MDC.controlNormal), + Pair.create("control_highlight", MDC.controlHighlight), + Pair.create("text_primary_inverse", MDC.textPrimaryInverse), + Pair.create( + "text_secondary_and_tertiary_inverse", + MDC.textSecondaryAndTertiaryInverse + ), + Pair.create("text_primary_inverse_disable_only", MDC.textPrimaryInverseDisableOnly), + Pair.create( + "text_secondary_and_tertiary_inverse_disabled", + MDC.textSecondaryAndTertiaryInverseDisabled + ), + Pair.create("text_hint_inverse", MDC.textHintInverse), + Pair.create("palette_key_color_primary", MDC.primaryPaletteKeyColor), + Pair.create("palette_key_color_secondary", MDC.secondaryPaletteKeyColor), + Pair.create("palette_key_color_tertiary", MDC.tertiaryPaletteKeyColor), + Pair.create("palette_key_color_neutral", MDC.neutralPaletteKeyColor), + Pair.create("palette_key_color_neutral_variant", MDC.neutralVariantPaletteKeyColor) + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java index ba39367e290e4..3376e232e0359 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java @@ -65,6 +65,8 @@ public class ThemeOverlayApplier implements Dumpable { @VisibleForTesting static final String SYSUI_PACKAGE = "com.android.systemui"; + static final String OVERLAY_CATEGORY_DYNAMIC_COLOR = + "android.theme.customization.dynamic_color"; static final String OVERLAY_CATEGORY_ACCENT_COLOR = "android.theme.customization.accent_color"; static final String OVERLAY_CATEGORY_SYSTEM_PALETTE = @@ -117,6 +119,7 @@ public class ThemeOverlayApplier implements Dumpable { OVERLAY_CATEGORY_SHAPE, OVERLAY_CATEGORY_FONT, OVERLAY_CATEGORY_ACCENT_COLOR, + OVERLAY_CATEGORY_DYNAMIC_COLOR, OVERLAY_CATEGORY_ICON_ANDROID, OVERLAY_CATEGORY_ICON_SYSUI, OVERLAY_CATEGORY_ICON_SETTINGS, @@ -127,6 +130,7 @@ public class ThemeOverlayApplier implements Dumpable { static final Set SYSTEM_USER_CATEGORIES = Sets.newHashSet( OVERLAY_CATEGORY_SYSTEM_PALETTE, OVERLAY_CATEGORY_ACCENT_COLOR, + OVERLAY_CATEGORY_DYNAMIC_COLOR, OVERLAY_CATEGORY_FONT, OVERLAY_CATEGORY_SHAPE, OVERLAY_CATEGORY_ICON_ANDROID, @@ -153,6 +157,7 @@ public class ThemeOverlayApplier implements Dumpable { mThemePickerPackage = themePickerPackage; mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet( OVERLAY_CATEGORY_SYSTEM_PALETTE, OVERLAY_CATEGORY_ACCENT_COLOR, + OVERLAY_CATEGORY_DYNAMIC_COLOR, OVERLAY_CATEGORY_FONT, OVERLAY_CATEGORY_SHAPE, OVERLAY_CATEGORY_ICON_ANDROID)); mTargetPackageToCategories.put(SYSUI_PACKAGE, @@ -164,6 +169,7 @@ public class ThemeOverlayApplier implements Dumpable { mTargetPackageToCategories.put(mThemePickerPackage, Sets.newHashSet(OVERLAY_CATEGORY_ICON_THEME_PICKER)); mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, ANDROID_PACKAGE); + mCategoryToTargetPackage.put(OVERLAY_CATEGORY_DYNAMIC_COLOR, ANDROID_PACKAGE); mCategoryToTargetPackage.put(OVERLAY_CATEGORY_FONT, ANDROID_PACKAGE); mCategoryToTargetPackage.put(OVERLAY_CATEGORY_SHAPE, ANDROID_PACKAGE); mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_ANDROID, ANDROID_PACKAGE); diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java index 6b507ba9d9e60..2ad3558fdb163 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java @@ -15,11 +15,14 @@ */ package com.android.systemui.theme; +import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8; + import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP; import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_HOME; import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_LOCK; import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_PRESET; import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR; +import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_DYNAMIC_COLOR; import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE; import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_COLOR_BOTH; import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_COLOR_INDEX; @@ -51,7 +54,7 @@ import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; -import android.util.TypedValue; +import android.view.accessibility.AccessibilityManager; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; @@ -70,6 +73,16 @@ import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.monet.ColorScheme; import com.android.systemui.monet.Style; import com.android.systemui.monet.TonalPalette; +import com.android.systemui.monet.dynamiccolor.MaterialDynamicColors; +import com.android.systemui.monet.hct.Hct; +import com.android.systemui.monet.scheme.DynamicScheme; +import com.android.systemui.monet.scheme.SchemeExpressive; +import com.android.systemui.monet.scheme.SchemeFruitSalad; +import com.android.systemui.monet.scheme.SchemeMonochrome; +import com.android.systemui.monet.scheme.SchemeNeutral; +import com.android.systemui.monet.scheme.SchemeRainbow; +import com.android.systemui.monet.scheme.SchemeTonalSpot; +import com.android.systemui.monet.scheme.SchemeVibrant; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; @@ -105,9 +118,6 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { protected static final String TAG = "ThemeOverlayController"; private static final boolean DEBUG = true; - protected static final int NEUTRAL = 0; - protected static final int ACCENT = 1; - private final ThemeOverlayApplier mThemeManager; private final UserManager mUserManager; private final BroadcastDispatcher mBroadcastDispatcher; @@ -130,12 +140,17 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { private boolean mNeedsOverlayCreation; // Dominant color extracted from wallpaper, NOT the color used on the overlay protected int mMainWallpaperColor = Color.TRANSPARENT; + // UI contrast as reported by AccessibilityManager + private float mUiContrast = 0; // Theme variant: Vibrant, Tonal, Expressive, etc - private Style mThemeStyle = Style.TONAL_SPOT; + @VisibleForTesting + protected Style mThemeStyle = Style.TONAL_SPOT; // Accent colors overlay private FabricatedOverlay mSecondaryOverlay; // Neutral system colors overlay private FabricatedOverlay mNeutralOverlay; + // Dynamic colors overlay + private FabricatedOverlay mDynamicOverlay; // If wallpaper color event will be accepted and change the UI colors. private boolean mAcceptColorEvents = true; // If non-null (per user), colors that were sent to the framework, and processing was deferred @@ -143,6 +158,9 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { private final SparseArray mDeferredWallpaperColors = new SparseArray<>(); private final SparseIntArray mDeferredWallpaperColorsFlags = new SparseIntArray(); private final WakefulnessLifecycle mWakefulnessLifecycle; + private final AccessibilityManager mAccessibilityManager; + private DynamicScheme mDynamicSchemeDark; + private DynamicScheme mDynamicSchemeLight; // Defers changing themes until Setup Wizard is done. private boolean mDeferredThemeEvaluation; @@ -304,6 +322,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { mSkipSettingChange = true; if (jsonObject.has(OVERLAY_CATEGORY_ACCENT_COLOR) || jsonObject.has( OVERLAY_CATEGORY_SYSTEM_PALETTE)) { + jsonObject.remove(OVERLAY_CATEGORY_DYNAMIC_COLOR); jsonObject.remove(OVERLAY_CATEGORY_ACCENT_COLOR); jsonObject.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE); jsonObject.remove(OVERLAY_COLOR_INDEX); @@ -372,7 +391,8 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { DumpManager dumpManager, FeatureFlags featureFlags, @Main Resources resources, - WakefulnessLifecycle wakefulnessLifecycle) { + WakefulnessLifecycle wakefulnessLifecycle, + AccessibilityManager accessibilityManager) { mContext = context; mIsMonochromaticEnabled = featureFlags.isEnabled(Flags.MONOCHROMATIC_THEME); mIsMonetEnabled = featureFlags.isEnabled(Flags.MONET); @@ -388,6 +408,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { mUserTracker = userTracker; mResources = resources; mWakefulnessLifecycle = wakefulnessLifecycle; + mAccessibilityManager = accessibilityManager; dumpManager.registerDumpable(TAG, this); } @@ -424,6 +445,12 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { } }, UserHandle.USER_ALL); + mUiContrast = mAccessibilityManager.getUiContrast(); + mAccessibilityManager.addUiContrastChangeListener(mMainExecutor, uiContrast -> { + mUiContrast = uiContrast; + // Force reload so that we update even when the main color has not changed + reevaluateSystemTheme(true /* forceReload */); + }); if (!mIsMonetEnabled) { return; @@ -496,12 +523,11 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { if (mIsMonetEnabled) { mThemeStyle = fetchThemeStyleFromSetting(); - mSecondaryOverlay = getOverlay(mMainWallpaperColor, ACCENT, mThemeStyle); - mNeutralOverlay = getOverlay(mMainWallpaperColor, NEUTRAL, mThemeStyle); + createOverlays(mMainWallpaperColor); mNeedsOverlayCreation = true; if (DEBUG) { Log.d(TAG, "fetched overlays. accent: " + mSecondaryOverlay - + " neutral: " + mNeutralOverlay); + + " neutral: " + mNeutralOverlay + " dynamic: " + mDynamicOverlay); } } @@ -519,42 +545,95 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { return ColorScheme.getSeedColor(wallpaperColors); } - /** - * Given a color candidate, return an overlay definition. - */ - protected FabricatedOverlay getOverlay(int color, int type, Style style) { - boolean nightMode = (mResources.getConfiguration().uiMode - & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; - - mColorScheme = new ColorScheme(color, nightMode, style); - String name = type == ACCENT ? "accent" : "neutral"; - - FabricatedOverlay.Builder overlay = - new FabricatedOverlay.Builder("com.android.systemui", name, "android"); - - if (type == ACCENT) { - assignTonalPaletteToOverlay("accent1", overlay, mColorScheme.getAccent1()); - assignTonalPaletteToOverlay("accent2", overlay, mColorScheme.getAccent2()); - assignTonalPaletteToOverlay("accent3", overlay, mColorScheme.getAccent3()); - } else { - assignTonalPaletteToOverlay("neutral1", overlay, mColorScheme.getNeutral1()); - assignTonalPaletteToOverlay("neutral2", overlay, mColorScheme.getNeutral2()); + private static DynamicScheme dynamicSchemeFromStyle(Style style, int color, + boolean isDark, double contrastLevel) { + Hct sourceColorHct = Hct.fromInt(color); + switch (style) { + case EXPRESSIVE: + return new SchemeExpressive(sourceColorHct, isDark, contrastLevel); + case SPRITZ: + return new SchemeNeutral(sourceColorHct, isDark, contrastLevel); + case TONAL_SPOT: + return new SchemeTonalSpot(sourceColorHct, isDark, contrastLevel); + case FRUIT_SALAD: + return new SchemeFruitSalad(sourceColorHct, isDark, contrastLevel); + case RAINBOW: + return new SchemeRainbow(sourceColorHct, isDark, contrastLevel); + case VIBRANT: + return new SchemeVibrant(sourceColorHct, isDark, contrastLevel); + case MONOCHROMATIC: + return new SchemeMonochrome(sourceColorHct, isDark, contrastLevel); + default: + return null; } - - return overlay.build(); } - private void assignTonalPaletteToOverlay(String name, - FabricatedOverlay.Builder overlay, TonalPalette tonalPalette) { + @VisibleForTesting + protected boolean isNightMode() { + return (mResources.getConfiguration().uiMode + & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; + } + @VisibleForTesting + protected FabricatedOverlay newFabricatedOverlay(String name) { + return new FabricatedOverlay.Builder("com.android.systemui", name, "android").build(); + } + + private void createOverlays(int color) { + boolean nightMode = isNightMode(); + mColorScheme = new ColorScheme(color, nightMode, mThemeStyle); + mNeutralOverlay = createNeutralOverlay(); + mSecondaryOverlay = createAccentOverlay(); + + mDynamicSchemeDark = dynamicSchemeFromStyle( + mThemeStyle, color, true /* isDark */, mUiContrast); + mDynamicSchemeLight = dynamicSchemeFromStyle( + mThemeStyle, color, false /* isDark */, mUiContrast); + mDynamicOverlay = createDynamicOverlay(); + } + + protected FabricatedOverlay createNeutralOverlay() { + FabricatedOverlay overlay = newFabricatedOverlay("neutral"); + assignTonalPaletteToOverlay("neutral1", overlay, mColorScheme.getNeutral1()); + assignTonalPaletteToOverlay("neutral2", overlay, mColorScheme.getNeutral2()); + return overlay; + } + + protected FabricatedOverlay createAccentOverlay() { + FabricatedOverlay overlay = newFabricatedOverlay("accent"); + assignTonalPaletteToOverlay("accent1", overlay, mColorScheme.getAccent1()); + assignTonalPaletteToOverlay("accent2", overlay, mColorScheme.getAccent2()); + assignTonalPaletteToOverlay("accent3", overlay, mColorScheme.getAccent3()); + return overlay; + } + + private void assignTonalPaletteToOverlay(String name, FabricatedOverlay overlay, + TonalPalette tonalPalette) { String resourcePrefix = "android:color/system_" + name; - int colorDataType = TypedValue.TYPE_INT_COLOR_ARGB8; tonalPalette.getAllShadesMapped().forEach((key, value) -> { String resourceName = resourcePrefix + "_" + key; int colorValue = ColorUtils.setAlphaComponent(value, 0xFF); - overlay.setResourceValue(resourceName, colorDataType, - colorValue); + overlay.setResourceValue(resourceName, TYPE_INT_COLOR_ARGB8, colorValue, + null /* configuration */); + }); + } + + protected FabricatedOverlay createDynamicOverlay() { + FabricatedOverlay overlay = newFabricatedOverlay("dynamic"); + assignDynamicPaletteToOverlay(overlay, true /* isDark */); + assignDynamicPaletteToOverlay(overlay, false /* isDark */); + return overlay; + } + + private void assignDynamicPaletteToOverlay(FabricatedOverlay overlay, boolean isDark) { + String suffix = isDark ? "dark" : "light"; + DynamicScheme scheme = isDark ? mDynamicSchemeDark : mDynamicSchemeLight; + DynamicColors.ALL_DYNAMIC_COLORS_MAPPED.forEach(p -> { + String resourceName = "android:color/system_" + p.first + "_" + suffix; + int colorValue = p.second.getArgb(scheme); + overlay.setResourceValue(resourceName, TYPE_INT_COLOR_ARGB8, colorValue, + null /* configuration */); }); } @@ -568,16 +647,21 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { for (UserHandle userHandle : allProfiles) { Resources res = userHandle.isSystem() ? mResources : mContext.createContextAsUser(userHandle, 0).getResources(); - if (!(res.getColor(android.R.color.system_accent1_500, mContext.getTheme()) + Resources.Theme theme = mContext.getTheme(); + if (!(res.getColor(android.R.color.system_accent1_500, theme) == mColorScheme.getAccent1().getS500() - && res.getColor(android.R.color.system_accent2_500, mContext.getTheme()) + && res.getColor(android.R.color.system_accent2_500, theme) == mColorScheme.getAccent2().getS500() - && res.getColor(android.R.color.system_accent3_500, mContext.getTheme()) + && res.getColor(android.R.color.system_accent3_500, theme) == mColorScheme.getAccent3().getS500() - && res.getColor(android.R.color.system_neutral1_500, mContext.getTheme()) + && res.getColor(android.R.color.system_neutral1_500, theme) == mColorScheme.getNeutral1().getS500() - && res.getColor(android.R.color.system_neutral2_500, mContext.getTheme()) - == mColorScheme.getNeutral2().getS500())) { + && res.getColor(android.R.color.system_neutral2_500, theme) + == mColorScheme.getNeutral2().getS500() + && res.getColor(android.R.color.system_primary_container_dark, theme) + == MaterialDynamicColors.primaryContainer.getArgb(mDynamicSchemeDark) + && res.getColor(android.R.color.system_primary_container_light, theme) + == MaterialDynamicColors.primaryContainer.getArgb(mDynamicSchemeLight))) { return false; } } @@ -614,12 +698,11 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { if (!colorString.startsWith("#")) { colorString = "#" + colorString; } - int color = Color.parseColor(colorString); - mNeutralOverlay = getOverlay(color, NEUTRAL, mThemeStyle); - mSecondaryOverlay = getOverlay(color, ACCENT, mThemeStyle); + createOverlays(Color.parseColor(colorString)); mNeedsOverlayCreation = true; categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE); categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR); + categoryToPackage.remove(OVERLAY_CATEGORY_DYNAMIC_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); @@ -631,6 +714,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { // fail. categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE); categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR); + categoryToPackage.remove(OVERLAY_CATEGORY_DYNAMIC_COLOR); } catch (NumberFormatException e) { // This is a package name. All good, let's continue } @@ -647,6 +731,10 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { && mSecondaryOverlay != null) { categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, mSecondaryOverlay.getIdentifier()); } + if (!categoryToPackage.containsKey(OVERLAY_CATEGORY_DYNAMIC_COLOR) + && mDynamicOverlay != null) { + categoryToPackage.put(OVERLAY_CATEGORY_DYNAMIC_COLOR, mDynamicOverlay.getIdentifier()); + } Set managedProfiles = new HashSet<>(); for (UserInfo userInfo : mUserManager.getEnabledProfiles(currentUser)) { @@ -668,7 +756,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { if (mNeedsOverlayCreation) { mNeedsOverlayCreation = false; mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[]{ - mSecondaryOverlay, mNeutralOverlay + mSecondaryOverlay, mNeutralOverlay, mDynamicOverlay }, currentUser, managedProfiles); } else { mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, currentUser, @@ -710,6 +798,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { pw.println("mMainWallpaperColor=" + Integer.toHexString(mMainWallpaperColor)); pw.println("mSecondaryOverlay=" + mSecondaryOverlay); pw.println("mNeutralOverlay=" + mNeutralOverlay); + pw.println("mDynamicOverlay=" + mDynamicOverlay); pw.println("mIsMonetEnabled=" + mIsMonetEnabled); pw.println("mColorScheme=" + mColorScheme); pw.println("mNeedsOverlayCreation=" + mNeedsOverlayCreation); diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java index 3032ff1fe61f1..83439f0fc60d5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java @@ -17,6 +17,7 @@ package com.android.systemui.theme; import static com.android.systemui.theme.ThemeOverlayApplier.ANDROID_PACKAGE; import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR; +import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_DYNAMIC_COLOR; import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_FONT; import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_ANDROID; import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_LAUNCHER; @@ -113,6 +114,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { }; when(mOverlayManager.getOverlayInfosForTarget(ANDROID_PACKAGE, UserHandle.SYSTEM)) .thenReturn(Lists.newArrayList( + createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_DYNAMIC_COLOR, + ANDROID_PACKAGE, OVERLAY_CATEGORY_DYNAMIC_COLOR, false), createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ACCENT_COLOR, ANDROID_PACKAGE, OVERLAY_CATEGORY_ACCENT_COLOR, false), createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_SYSTEM_PALETTE, @@ -123,6 +126,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { ANDROID_PACKAGE, OVERLAY_CATEGORY_SHAPE, false), createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ICON_ANDROID, ANDROID_PACKAGE, OVERLAY_CATEGORY_ICON_ANDROID, false), + createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_DYNAMIC_COLOR, + ANDROID_PACKAGE, OVERLAY_CATEGORY_DYNAMIC_COLOR, true), createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ACCENT_COLOR, ANDROID_PACKAGE, OVERLAY_CATEGORY_ACCENT_COLOR, true), createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_SYSTEM_PALETTE, diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java index 1710709aa8514..f9b5767bf53c6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java @@ -47,8 +47,9 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.testing.AndroidTestingRunner; +import android.view.accessibility.AccessibilityManager; -import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; @@ -57,7 +58,6 @@ 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.ColorScheme; import com.android.systemui.monet.Style; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -115,6 +115,8 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { private Resources mResources; @Mock private WakefulnessLifecycle mWakefulnessLifecycle; + @Mock + private AccessibilityManager mAccessibilityManager; @Captor private ArgumentCaptor mBroadcastReceiver; @Captor @@ -127,13 +129,13 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { private ArgumentCaptor mUserTrackerCallback; @Captor private ArgumentCaptor mSettingsObserver; - private Style mCurrentStyle; @Before public void setup() { MockitoAnnotations.initMocks(this); when(mFeatureFlags.isEnabled(Flags.MONET)).thenReturn(true); when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE); + when(mAccessibilityManager.getUiContrast()).thenReturn(0.5f); when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true); when(mResources.getColor(eq(android.R.color.system_accent1_500), any())) .thenReturn(Color.RED); @@ -148,15 +150,19 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mThemeOverlayController = new ThemeOverlayController(mContext, mBroadcastDispatcher, mBgHandler, mMainExecutor, mBgExecutor, mThemeOverlayApplier, mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController, - mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle) { - @Nullable - @Override - protected FabricatedOverlay getOverlay(int color, int type, Style style) { + mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle, + mAccessibilityManager) { + @VisibleForTesting + protected boolean isNightMode() { + return false; + } + + @VisibleForTesting + protected FabricatedOverlay newFabricatedOverlay(String name) { FabricatedOverlay overlay = mock(FabricatedOverlay.class); when(overlay.getIdentifier()) - .thenReturn(new OverlayIdentifier(Integer.toHexString(color | 0xff000000))); - mCurrentStyle = style; - mColorScheme = new ColorScheme(color, false /* nightMode */, style); + .thenReturn(new OverlayIdentifier( + Integer.toHexString(mColorScheme.getSeed() | 0xff000000))); return overlay; } }; @@ -416,7 +422,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mSettingsObserver.getValue().onChange(true, null, 0, mUserTracker.getUserId()); - assertThat(mCurrentStyle).isEqualTo(style); + assertThat(mThemeOverlayController.mThemeStyle).isEqualTo(style); } } @@ -432,7 +438,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mSettingsObserver.getValue().onChange(true, null, 0, mUserTracker.getUserId()); - assertThat(mCurrentStyle).isEqualTo(Style.TONAL_SPOT); + assertThat(mThemeOverlayController.mThemeStyle).isEqualTo(Style.TONAL_SPOT); } @Test @@ -726,17 +732,20 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mThemeOverlayController = new ThemeOverlayController(mContext, mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier, mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController, - mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle) { - @Nullable - @Override - protected FabricatedOverlay getOverlay(int color, int type, Style style) { + mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle, + mAccessibilityManager) { + @VisibleForTesting + protected boolean isNightMode() { + return false; + } + + @VisibleForTesting + protected FabricatedOverlay newFabricatedOverlay(String name) { FabricatedOverlay overlay = mock(FabricatedOverlay.class); when(overlay.getIdentifier()) .thenReturn(new OverlayIdentifier("com.thebest.livewallpaperapp.ever")); - mColorScheme = new ColorScheme(color, false /* nightMode */, style); return overlay; } - }; mThemeOverlayController.start(); @@ -763,14 +772,19 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mThemeOverlayController = new ThemeOverlayController(mContext, mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier, mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController, - mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle) { - @Nullable - @Override - protected FabricatedOverlay getOverlay(int color, int type, Style style) { + mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle, + mAccessibilityManager) { + @VisibleForTesting + protected boolean isNightMode() { + return false; + } + + @VisibleForTesting + protected FabricatedOverlay newFabricatedOverlay(String name) { FabricatedOverlay overlay = mock(FabricatedOverlay.class); when(overlay.getIdentifier()) - .thenReturn(new OverlayIdentifier(Integer.toHexString(color | 0xff000000))); - mColorScheme = new ColorScheme(color, false /* nightMode */, style); + .thenReturn(new OverlayIdentifier( + Integer.toHexString(mColorScheme.getSeed() | 0xff000000))); return overlay; } };