Loading packages/SystemUI/res/values/flags.xml +1 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ <bool name="flag_notif_updates">false</bool> <bool name="flag_shade_is_opaque">false</bool> <bool name="flag_monet">false</bool> <!-- b/171917882 --> <bool name="flag_notification_twocolumn">false</bool> Loading packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java +4 −0 Original line number Diff line number Diff line Loading @@ -78,4 +78,8 @@ public class FeatureFlags { public boolean isToastStyleEnabled() { return mFlagReader.isEnabled(R.bool.flag_toast_style); } public boolean isMonetEnabled() { return mFlagReader.isEnabled(R.bool.flag_monet); } } packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java +13 −74 Original line number Diff line number Diff line Loading @@ -15,11 +15,11 @@ */ package com.android.systemui.theme; import android.content.om.FabricatedOverlay; import android.content.om.OverlayIdentifier; import android.content.om.OverlayInfo; import android.content.om.OverlayManager; import android.content.om.OverlayManagerTransaction; import android.os.SystemProperties; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; Loading Loading @@ -53,13 +53,6 @@ import java.util.stream.Collectors; public class ThemeOverlayApplier implements Dumpable { private static final String TAG = "ThemeOverlayApplier"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final boolean MONET_ENABLED = SystemProperties .getBoolean("persist.sysui.monet", false); @VisibleForTesting static final String MONET_ACCENT_COLOR_PACKAGE = "com.android.theme.accentcolor.color"; @VisibleForTesting static final String MONET_SYSTEM_PALETTE_PACKAGE = "com.android.theme.systemcolors.color"; @VisibleForTesting static final String ANDROID_PACKAGE = "android"; Loading @@ -68,10 +61,8 @@ public class ThemeOverlayApplier implements Dumpable { @VisibleForTesting static final String SYSUI_PACKAGE = "com.android.systemui"; @VisibleForTesting static final String OVERLAY_CATEGORY_ACCENT_COLOR = "android.theme.customization.accent_color"; @VisibleForTesting static final String OVERLAY_CATEGORY_SYSTEM_PALETTE = "android.theme.customization.system_palette"; @VisibleForTesting Loading Loading @@ -120,16 +111,6 @@ public class ThemeOverlayApplier implements Dumpable { OVERLAY_CATEGORY_ICON_ANDROID, OVERLAY_CATEGORY_ICON_SYSUI); /** * List of main colors of Monet themes. These are extracted from overlays installed * on the system. */ private final ArrayList<Integer> mMainSystemColors = new ArrayList<>(); /** * Same as above, but providing accent colors instead of a system palette. */ private final ArrayList<Integer> mAccentColors = new ArrayList<>(); /* Allowed overlay categories for each target package. */ private final Map<String, Set<String>> mTargetPackageToCategories = new ArrayMap<>(); /* Target package for each overlay category. */ Loading Loading @@ -165,64 +146,17 @@ public class ThemeOverlayApplier implements Dumpable { mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_LAUNCHER, mLauncherPackage); mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_THEME_PICKER, mThemePickerPackage); collectMonetSystemOverlays(); dumpManager.registerDumpable(TAG, this); } /** * List of accent colors available as Monet overlays. */ List<Integer> getAvailableAccentColors() { return mAccentColors; } /** * List of main system colors available as Monet overlays. */ List<Integer> getAvailableSystemColors() { return mMainSystemColors; } private void collectMonetSystemOverlays() { if (!MONET_ENABLED) { return; } List<OverlayInfo> androidOverlays = mOverlayManager .getOverlayInfosForTarget(ANDROID_PACKAGE, UserHandle.SYSTEM); for (OverlayInfo overlayInfo : androidOverlays) { String packageName = overlayInfo.packageName; if (DEBUG) { Log.d(TAG, "Processing overlay " + packageName); } if (OVERLAY_CATEGORY_SYSTEM_PALETTE.equals(overlayInfo.category) && packageName.startsWith(MONET_SYSTEM_PALETTE_PACKAGE)) { try { String color = packageName.replace(MONET_SYSTEM_PALETTE_PACKAGE, ""); mMainSystemColors.add(Integer.parseInt(color, 16)); } catch (NumberFormatException e) { Log.w(TAG, "Invalid package name for overlay " + packageName, e); } } else if (OVERLAY_CATEGORY_ACCENT_COLOR.equals(overlayInfo.category) && packageName.startsWith(MONET_ACCENT_COLOR_PACKAGE)) { try { String color = packageName.replace(MONET_ACCENT_COLOR_PACKAGE, ""); mAccentColors.add(Integer.parseInt(color, 16)); } catch (NumberFormatException e) { Log.w(TAG, "Invalid package name for overlay " + packageName, e); } } else if (DEBUG) { Log.d(TAG, "Unknown overlay: " + packageName + " category: " + overlayInfo.category); } } } /** * Apply the set of overlay packages to the set of {@code UserHandle}s provided. Overlays that * affect sysui will also be applied to the system user. */ void applyCurrentUserOverlays( Map<String, String> categoryToPackage, Set<UserHandle> userHandles) { Map<String, OverlayIdentifier> categoryToPackage, FabricatedOverlay[] pendingCreation, Set<UserHandle> userHandles) { // Disable all overlays that have not been specified in the user setting. final Set<String> overlayCategoriesToDisable = new HashSet<>(THEME_CATEGORIES); overlayCategoriesToDisable.removeAll(categoryToPackage.keySet()); Loading @@ -241,11 +175,16 @@ public class ThemeOverlayApplier implements Dumpable { .collect(Collectors.toList()); OverlayManagerTransaction.Builder transaction = getTransactionBuilder(); if (pendingCreation != null) { for (FabricatedOverlay overlay : pendingCreation) { transaction.registerFabricatedOverlay(overlay); } } // Toggle overlays in the order of THEME_CATEGORIES. for (String category : THEME_CATEGORIES) { if (categoryToPackage.containsKey(category)) { OverlayIdentifier overlayInfo = new OverlayIdentifier(categoryToPackage.get(category)); OverlayIdentifier overlayInfo = categoryToPackage.get(category); setEnabled(transaction, overlayInfo, category, userHandles, true); } } Loading Loading @@ -284,7 +223,7 @@ public class ThemeOverlayApplier implements Dumpable { */ @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { pw.println("mMainSystemColors=" + mMainSystemColors.size()); pw.println("mAccentColors=" + mAccentColors.size()); pw.println("mTargetPackageToCategories=" + mTargetPackageToCategories); pw.println("mCategoryToTargetPackage=" + mCategoryToTargetPackage); } } packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java +83 −87 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.theme; import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR; import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.WallpaperColors; import android.app.WallpaperManager; Loading @@ -25,6 +26,8 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.om.FabricatedOverlay; import android.content.om.OverlayIdentifier; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.graphics.Color; Loading @@ -40,7 +43,6 @@ import android.util.Log; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; import com.android.systemui.Dumpable; import com.android.systemui.SystemUI; import com.android.systemui.broadcast.BroadcastDispatcher; Loading @@ -48,6 +50,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.settings.SecureSettings; Loading @@ -59,10 +62,10 @@ import org.json.JSONObject; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; import java.util.stream.Collectors; import javax.inject.Inject; Loading @@ -77,9 +80,12 @@ import javax.inject.Inject; */ @SysUISingleton public class ThemeOverlayController extends SystemUI implements Dumpable { private static final String TAG = "ThemeOverlayController"; protected static final String TAG = "ThemeOverlayController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); protected static final int MAIN = 0; protected static final int ACCENT = 1; // If lock screen wallpaper colors should also be considered when selecting the theme. // Doing this has performance impact, given that overlays would need to be swapped when // the device unlocks. Loading @@ -95,16 +101,19 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { private final Handler mBgHandler; private final WallpaperManager mWallpaperManager; private final KeyguardStateController mKeyguardStateController; private final boolean mIsMonetEnabled; private WallpaperColors mLockColors; private WallpaperColors mSystemColors; // Color extracted from wallpaper, NOT the color used on the overlay // If fabricated overlays were already created for the current theme. private boolean mNeedsOverlayCreation; // Dominant olor extracted from wallpaper, NOT the color used on the overlay protected int mMainWallpaperColor = Color.TRANSPARENT; // Color extracted from wallpaper, NOT the color used on the overlay // Accent color extracted from wallpaper, NOT the color used on the overlay protected int mWallpaperAccentColor = Color.TRANSPARENT; // Main system color that maps to an overlay color private int mSystemOverlayColor = Color.TRANSPARENT; // Accent color that maps to an overlay color private int mAccentOverlayColor = Color.TRANSPARENT; // System colors overlay private FabricatedOverlay mSystemOverlay; // Accent colors overlay private FabricatedOverlay mAccentOverlay; @Inject public ThemeOverlayController(Context context, BroadcastDispatcher broadcastDispatcher, Loading @@ -112,9 +121,10 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { @Background Executor bgExecutor, ThemeOverlayApplier themeOverlayApplier, SecureSettings secureSettings, WallpaperManager wallpaperManager, UserManager userManager, KeyguardStateController keyguardStateController, DumpManager dumpManager) { DumpManager dumpManager, FeatureFlags featureFlags) { super(context); mIsMonetEnabled = featureFlags.isMonetEnabled(); mBroadcastDispatcher = broadcastDispatcher; mUserManager = userManager; mBgExecutor = bgExecutor; Loading Loading @@ -221,20 +231,16 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { mMainWallpaperColor = mainColor; mWallpaperAccentColor = accentCandidate; // Let's compare these colors to our finite set of overlays, and then pick an overlay. List<Integer> systemColors = mThemeManager.getAvailableSystemColors(); List<Integer> accentColors = mThemeManager.getAvailableAccentColors(); if (systemColors.size() == 0 || accentColors.size() == 0) { if (mIsMonetEnabled) { mSystemOverlay = getOverlay(mMainWallpaperColor, MAIN); mAccentOverlay = getOverlay(mWallpaperAccentColor, ACCENT); mNeedsOverlayCreation = true; if (DEBUG) { Log.d(TAG, "Cannot apply system theme, palettes are unavailable"); Log.d(TAG, "fetched overlays. system: " + mSystemOverlay + " accent: " + mAccentOverlay); } return; } mSystemOverlayColor = getClosest(systemColors, mMainWallpaperColor); mAccentOverlayColor = getClosest(accentColors, mWallpaperAccentColor); updateThemeOverlays(); } Loading @@ -257,42 +263,10 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { } /** * Given a color and a list of candidates, return the candidate that's the most similar to the * given color. * Given a color candidate, return an overlay definition. */ protected int getClosest(List<Integer> candidates, int color) { float[] hslMain = new float[3]; float[] hslCandidate = new float[3]; ColorUtils.RGBToHSL(Color.red(color), Color.green(color), Color.blue(color), hslMain); hslMain[0] /= 360f; // To close to white or black, let's use the default system theme instead of // applying a colorized one. if (hslMain[2] < 0.05 || hslMain[2] > 0.95) { return Color.TRANSPARENT; } float minDistance = Float.MAX_VALUE; int closestColor = Color.TRANSPARENT; for (int candidate: candidates) { ColorUtils.RGBToHSL(Color.red(candidate), Color.green(candidate), Color.blue(candidate), hslCandidate); hslCandidate[0] /= 360f; float sqDistance = squared(hslCandidate[0] - hslMain[0]) + squared(hslCandidate[1] - hslMain[1]) + squared(hslCandidate[2] - hslMain[2]); if (sqDistance < minDistance) { minDistance = sqDistance; closestColor = candidate; } } return closestColor; } private static float squared(float f) { return f * f; protected @Nullable FabricatedOverlay getOverlay(int color, int type) { return null; } private void updateThemeOverlays() { Loading @@ -301,20 +275,15 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, currentUser); if (DEBUG) Log.d(TAG, "updateThemeOverlays. Setting: " + overlayPackageJson); boolean hasSystemPalette = false; boolean hasAccentColor = false; final Map<String, String> categoryToPackage = new ArrayMap<>(); final Map<String, OverlayIdentifier> categoryToPackage = new ArrayMap<>(); if (!TextUtils.isEmpty(overlayPackageJson)) { try { JSONObject object = new JSONObject(overlayPackageJson); for (String category : ThemeOverlayApplier.THEME_CATEGORIES) { if (object.has(category)) { if (category.equals(OVERLAY_CATEGORY_ACCENT_COLOR)) { hasAccentColor = true; } else if (category.equals(OVERLAY_CATEGORY_SYSTEM_PALETTE)) { hasSystemPalette = true; } categoryToPackage.put(category, object.getString(category)); OverlayIdentifier identifier = new OverlayIdentifier(object.getString(category)); categoryToPackage.put(category, identifier); } } } catch (JSONException e) { Loading @@ -322,17 +291,41 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { } } // Let's apply the system palette, but only if it was not overridden by the style picker. if (!hasSystemPalette && mSystemOverlayColor != Color.TRANSPARENT) { categoryToPackage.put(OVERLAY_CATEGORY_SYSTEM_PALETTE, ThemeOverlayApplier.MONET_SYSTEM_PALETTE_PACKAGE + getColorString(mSystemOverlayColor)); } // Same for the accent color if (!hasAccentColor && mAccentOverlayColor != Color.TRANSPARENT) { categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, ThemeOverlayApplier.MONET_ACCENT_COLOR_PACKAGE + getColorString(mAccentOverlayColor)); // 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) { try { int color = Integer.parseInt(systemPalette.getPackageName().toLowerCase(), 16); mSystemOverlay = getOverlay(color, MAIN); mNeedsOverlayCreation = true; categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE); } catch (NumberFormatException e) { Log.w(TAG, "Invalid color definition: " + systemPalette.getPackageName()); } } // Same for accent color. OverlayIdentifier accentPalette = categoryToPackage.get(OVERLAY_CATEGORY_ACCENT_COLOR); if (mIsMonetEnabled && accentPalette != null && accentPalette.getPackageName() != null) { try { int color = Integer.parseInt(accentPalette.getPackageName().toLowerCase(), 16); mAccentOverlay = getOverlay(color, ACCENT); mNeedsOverlayCreation = true; categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR); } catch (NumberFormatException e) { Log.w(TAG, "Invalid color definition: " + accentPalette.getPackageName()); } } // Compatibility with legacy themes, where full packages were defined, instead of just // colors. if (!categoryToPackage.containsKey(OVERLAY_CATEGORY_SYSTEM_PALETTE) && mSystemOverlay != null) { categoryToPackage.put(OVERLAY_CATEGORY_SYSTEM_PALETTE, mSystemOverlay.getIdentifier()); } if (!categoryToPackage.containsKey(OVERLAY_CATEGORY_ACCENT_COLOR) && mAccentOverlay != null) { categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, mAccentOverlay.getIdentifier()); } Set<UserHandle> userHandles = Sets.newHashSet(UserHandle.of(currentUser)); Loading @@ -341,28 +334,31 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { userHandles.add(userInfo.getUserHandle()); } } mThemeManager.applyCurrentUserOverlays(categoryToPackage, userHandles); } private String getColorString(int color) { String colorString = Integer.toHexString(color).toUpperCase(); while (colorString.length() < 6) { colorString = "0" + colorString; } // Remove alpha component if (colorString.length() > 6) { colorString = colorString.substring(colorString.length() - 6); if (DEBUG) { Log.d(TAG, "Applying overlays: " + categoryToPackage.keySet().stream() .map(key -> key + " -> " + categoryToPackage.get(key)).collect( Collectors.joining(", "))); } if (mNeedsOverlayCreation) { mNeedsOverlayCreation = false; mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[] { mSystemOverlay, mAccentOverlay }, userHandles); } else { mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, userHandles); } return colorString; } @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { pw.println("USE_LOCK_SCREEN_WALLPAPER=" + USE_LOCK_SCREEN_WALLPAPER); pw.println("mLockColors=" + mLockColors); pw.println("mSystemColors=" + mSystemColors); pw.println("mMainWallpaperColor=" + Integer.toHexString(mMainWallpaperColor)); pw.println("mWallpaperAccentColor=" + Integer.toHexString(mWallpaperAccentColor)); pw.println("mSystemOverlayColor=" + Integer.toHexString(mSystemOverlayColor)); pw.println("mAccentOverlayColor=" + Integer.toHexString(mAccentOverlayColor)); pw.println("mSystemOverlayColor=" + mSystemOverlay); pw.println("mAccentOverlayColor=" + mAccentOverlay); pw.println("mIsMonetEnabled=" + mIsMonetEnabled); pw.println("mNeedsOverlayCreation=" + mNeedsOverlayCreation); } } packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java +50 −32 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
packages/SystemUI/res/values/flags.xml +1 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ <bool name="flag_notif_updates">false</bool> <bool name="flag_shade_is_opaque">false</bool> <bool name="flag_monet">false</bool> <!-- b/171917882 --> <bool name="flag_notification_twocolumn">false</bool> Loading
packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java +4 −0 Original line number Diff line number Diff line Loading @@ -78,4 +78,8 @@ public class FeatureFlags { public boolean isToastStyleEnabled() { return mFlagReader.isEnabled(R.bool.flag_toast_style); } public boolean isMonetEnabled() { return mFlagReader.isEnabled(R.bool.flag_monet); } }
packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java +13 −74 Original line number Diff line number Diff line Loading @@ -15,11 +15,11 @@ */ package com.android.systemui.theme; import android.content.om.FabricatedOverlay; import android.content.om.OverlayIdentifier; import android.content.om.OverlayInfo; import android.content.om.OverlayManager; import android.content.om.OverlayManagerTransaction; import android.os.SystemProperties; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; Loading Loading @@ -53,13 +53,6 @@ import java.util.stream.Collectors; public class ThemeOverlayApplier implements Dumpable { private static final String TAG = "ThemeOverlayApplier"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final boolean MONET_ENABLED = SystemProperties .getBoolean("persist.sysui.monet", false); @VisibleForTesting static final String MONET_ACCENT_COLOR_PACKAGE = "com.android.theme.accentcolor.color"; @VisibleForTesting static final String MONET_SYSTEM_PALETTE_PACKAGE = "com.android.theme.systemcolors.color"; @VisibleForTesting static final String ANDROID_PACKAGE = "android"; Loading @@ -68,10 +61,8 @@ public class ThemeOverlayApplier implements Dumpable { @VisibleForTesting static final String SYSUI_PACKAGE = "com.android.systemui"; @VisibleForTesting static final String OVERLAY_CATEGORY_ACCENT_COLOR = "android.theme.customization.accent_color"; @VisibleForTesting static final String OVERLAY_CATEGORY_SYSTEM_PALETTE = "android.theme.customization.system_palette"; @VisibleForTesting Loading Loading @@ -120,16 +111,6 @@ public class ThemeOverlayApplier implements Dumpable { OVERLAY_CATEGORY_ICON_ANDROID, OVERLAY_CATEGORY_ICON_SYSUI); /** * List of main colors of Monet themes. These are extracted from overlays installed * on the system. */ private final ArrayList<Integer> mMainSystemColors = new ArrayList<>(); /** * Same as above, but providing accent colors instead of a system palette. */ private final ArrayList<Integer> mAccentColors = new ArrayList<>(); /* Allowed overlay categories for each target package. */ private final Map<String, Set<String>> mTargetPackageToCategories = new ArrayMap<>(); /* Target package for each overlay category. */ Loading Loading @@ -165,64 +146,17 @@ public class ThemeOverlayApplier implements Dumpable { mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_LAUNCHER, mLauncherPackage); mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_THEME_PICKER, mThemePickerPackage); collectMonetSystemOverlays(); dumpManager.registerDumpable(TAG, this); } /** * List of accent colors available as Monet overlays. */ List<Integer> getAvailableAccentColors() { return mAccentColors; } /** * List of main system colors available as Monet overlays. */ List<Integer> getAvailableSystemColors() { return mMainSystemColors; } private void collectMonetSystemOverlays() { if (!MONET_ENABLED) { return; } List<OverlayInfo> androidOverlays = mOverlayManager .getOverlayInfosForTarget(ANDROID_PACKAGE, UserHandle.SYSTEM); for (OverlayInfo overlayInfo : androidOverlays) { String packageName = overlayInfo.packageName; if (DEBUG) { Log.d(TAG, "Processing overlay " + packageName); } if (OVERLAY_CATEGORY_SYSTEM_PALETTE.equals(overlayInfo.category) && packageName.startsWith(MONET_SYSTEM_PALETTE_PACKAGE)) { try { String color = packageName.replace(MONET_SYSTEM_PALETTE_PACKAGE, ""); mMainSystemColors.add(Integer.parseInt(color, 16)); } catch (NumberFormatException e) { Log.w(TAG, "Invalid package name for overlay " + packageName, e); } } else if (OVERLAY_CATEGORY_ACCENT_COLOR.equals(overlayInfo.category) && packageName.startsWith(MONET_ACCENT_COLOR_PACKAGE)) { try { String color = packageName.replace(MONET_ACCENT_COLOR_PACKAGE, ""); mAccentColors.add(Integer.parseInt(color, 16)); } catch (NumberFormatException e) { Log.w(TAG, "Invalid package name for overlay " + packageName, e); } } else if (DEBUG) { Log.d(TAG, "Unknown overlay: " + packageName + " category: " + overlayInfo.category); } } } /** * Apply the set of overlay packages to the set of {@code UserHandle}s provided. Overlays that * affect sysui will also be applied to the system user. */ void applyCurrentUserOverlays( Map<String, String> categoryToPackage, Set<UserHandle> userHandles) { Map<String, OverlayIdentifier> categoryToPackage, FabricatedOverlay[] pendingCreation, Set<UserHandle> userHandles) { // Disable all overlays that have not been specified in the user setting. final Set<String> overlayCategoriesToDisable = new HashSet<>(THEME_CATEGORIES); overlayCategoriesToDisable.removeAll(categoryToPackage.keySet()); Loading @@ -241,11 +175,16 @@ public class ThemeOverlayApplier implements Dumpable { .collect(Collectors.toList()); OverlayManagerTransaction.Builder transaction = getTransactionBuilder(); if (pendingCreation != null) { for (FabricatedOverlay overlay : pendingCreation) { transaction.registerFabricatedOverlay(overlay); } } // Toggle overlays in the order of THEME_CATEGORIES. for (String category : THEME_CATEGORIES) { if (categoryToPackage.containsKey(category)) { OverlayIdentifier overlayInfo = new OverlayIdentifier(categoryToPackage.get(category)); OverlayIdentifier overlayInfo = categoryToPackage.get(category); setEnabled(transaction, overlayInfo, category, userHandles, true); } } Loading Loading @@ -284,7 +223,7 @@ public class ThemeOverlayApplier implements Dumpable { */ @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { pw.println("mMainSystemColors=" + mMainSystemColors.size()); pw.println("mAccentColors=" + mAccentColors.size()); pw.println("mTargetPackageToCategories=" + mTargetPackageToCategories); pw.println("mCategoryToTargetPackage=" + mCategoryToTargetPackage); } }
packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java +83 −87 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.theme; import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR; import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.WallpaperColors; import android.app.WallpaperManager; Loading @@ -25,6 +26,8 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.om.FabricatedOverlay; import android.content.om.OverlayIdentifier; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.graphics.Color; Loading @@ -40,7 +43,6 @@ import android.util.Log; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; import com.android.systemui.Dumpable; import com.android.systemui.SystemUI; import com.android.systemui.broadcast.BroadcastDispatcher; Loading @@ -48,6 +50,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.settings.SecureSettings; Loading @@ -59,10 +62,10 @@ import org.json.JSONObject; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; import java.util.stream.Collectors; import javax.inject.Inject; Loading @@ -77,9 +80,12 @@ import javax.inject.Inject; */ @SysUISingleton public class ThemeOverlayController extends SystemUI implements Dumpable { private static final String TAG = "ThemeOverlayController"; protected static final String TAG = "ThemeOverlayController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); protected static final int MAIN = 0; protected static final int ACCENT = 1; // If lock screen wallpaper colors should also be considered when selecting the theme. // Doing this has performance impact, given that overlays would need to be swapped when // the device unlocks. Loading @@ -95,16 +101,19 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { private final Handler mBgHandler; private final WallpaperManager mWallpaperManager; private final KeyguardStateController mKeyguardStateController; private final boolean mIsMonetEnabled; private WallpaperColors mLockColors; private WallpaperColors mSystemColors; // Color extracted from wallpaper, NOT the color used on the overlay // If fabricated overlays were already created for the current theme. private boolean mNeedsOverlayCreation; // Dominant olor extracted from wallpaper, NOT the color used on the overlay protected int mMainWallpaperColor = Color.TRANSPARENT; // Color extracted from wallpaper, NOT the color used on the overlay // Accent color extracted from wallpaper, NOT the color used on the overlay protected int mWallpaperAccentColor = Color.TRANSPARENT; // Main system color that maps to an overlay color private int mSystemOverlayColor = Color.TRANSPARENT; // Accent color that maps to an overlay color private int mAccentOverlayColor = Color.TRANSPARENT; // System colors overlay private FabricatedOverlay mSystemOverlay; // Accent colors overlay private FabricatedOverlay mAccentOverlay; @Inject public ThemeOverlayController(Context context, BroadcastDispatcher broadcastDispatcher, Loading @@ -112,9 +121,10 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { @Background Executor bgExecutor, ThemeOverlayApplier themeOverlayApplier, SecureSettings secureSettings, WallpaperManager wallpaperManager, UserManager userManager, KeyguardStateController keyguardStateController, DumpManager dumpManager) { DumpManager dumpManager, FeatureFlags featureFlags) { super(context); mIsMonetEnabled = featureFlags.isMonetEnabled(); mBroadcastDispatcher = broadcastDispatcher; mUserManager = userManager; mBgExecutor = bgExecutor; Loading Loading @@ -221,20 +231,16 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { mMainWallpaperColor = mainColor; mWallpaperAccentColor = accentCandidate; // Let's compare these colors to our finite set of overlays, and then pick an overlay. List<Integer> systemColors = mThemeManager.getAvailableSystemColors(); List<Integer> accentColors = mThemeManager.getAvailableAccentColors(); if (systemColors.size() == 0 || accentColors.size() == 0) { if (mIsMonetEnabled) { mSystemOverlay = getOverlay(mMainWallpaperColor, MAIN); mAccentOverlay = getOverlay(mWallpaperAccentColor, ACCENT); mNeedsOverlayCreation = true; if (DEBUG) { Log.d(TAG, "Cannot apply system theme, palettes are unavailable"); Log.d(TAG, "fetched overlays. system: " + mSystemOverlay + " accent: " + mAccentOverlay); } return; } mSystemOverlayColor = getClosest(systemColors, mMainWallpaperColor); mAccentOverlayColor = getClosest(accentColors, mWallpaperAccentColor); updateThemeOverlays(); } Loading @@ -257,42 +263,10 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { } /** * Given a color and a list of candidates, return the candidate that's the most similar to the * given color. * Given a color candidate, return an overlay definition. */ protected int getClosest(List<Integer> candidates, int color) { float[] hslMain = new float[3]; float[] hslCandidate = new float[3]; ColorUtils.RGBToHSL(Color.red(color), Color.green(color), Color.blue(color), hslMain); hslMain[0] /= 360f; // To close to white or black, let's use the default system theme instead of // applying a colorized one. if (hslMain[2] < 0.05 || hslMain[2] > 0.95) { return Color.TRANSPARENT; } float minDistance = Float.MAX_VALUE; int closestColor = Color.TRANSPARENT; for (int candidate: candidates) { ColorUtils.RGBToHSL(Color.red(candidate), Color.green(candidate), Color.blue(candidate), hslCandidate); hslCandidate[0] /= 360f; float sqDistance = squared(hslCandidate[0] - hslMain[0]) + squared(hslCandidate[1] - hslMain[1]) + squared(hslCandidate[2] - hslMain[2]); if (sqDistance < minDistance) { minDistance = sqDistance; closestColor = candidate; } } return closestColor; } private static float squared(float f) { return f * f; protected @Nullable FabricatedOverlay getOverlay(int color, int type) { return null; } private void updateThemeOverlays() { Loading @@ -301,20 +275,15 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, currentUser); if (DEBUG) Log.d(TAG, "updateThemeOverlays. Setting: " + overlayPackageJson); boolean hasSystemPalette = false; boolean hasAccentColor = false; final Map<String, String> categoryToPackage = new ArrayMap<>(); final Map<String, OverlayIdentifier> categoryToPackage = new ArrayMap<>(); if (!TextUtils.isEmpty(overlayPackageJson)) { try { JSONObject object = new JSONObject(overlayPackageJson); for (String category : ThemeOverlayApplier.THEME_CATEGORIES) { if (object.has(category)) { if (category.equals(OVERLAY_CATEGORY_ACCENT_COLOR)) { hasAccentColor = true; } else if (category.equals(OVERLAY_CATEGORY_SYSTEM_PALETTE)) { hasSystemPalette = true; } categoryToPackage.put(category, object.getString(category)); OverlayIdentifier identifier = new OverlayIdentifier(object.getString(category)); categoryToPackage.put(category, identifier); } } } catch (JSONException e) { Loading @@ -322,17 +291,41 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { } } // Let's apply the system palette, but only if it was not overridden by the style picker. if (!hasSystemPalette && mSystemOverlayColor != Color.TRANSPARENT) { categoryToPackage.put(OVERLAY_CATEGORY_SYSTEM_PALETTE, ThemeOverlayApplier.MONET_SYSTEM_PALETTE_PACKAGE + getColorString(mSystemOverlayColor)); } // Same for the accent color if (!hasAccentColor && mAccentOverlayColor != Color.TRANSPARENT) { categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, ThemeOverlayApplier.MONET_ACCENT_COLOR_PACKAGE + getColorString(mAccentOverlayColor)); // 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) { try { int color = Integer.parseInt(systemPalette.getPackageName().toLowerCase(), 16); mSystemOverlay = getOverlay(color, MAIN); mNeedsOverlayCreation = true; categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE); } catch (NumberFormatException e) { Log.w(TAG, "Invalid color definition: " + systemPalette.getPackageName()); } } // Same for accent color. OverlayIdentifier accentPalette = categoryToPackage.get(OVERLAY_CATEGORY_ACCENT_COLOR); if (mIsMonetEnabled && accentPalette != null && accentPalette.getPackageName() != null) { try { int color = Integer.parseInt(accentPalette.getPackageName().toLowerCase(), 16); mAccentOverlay = getOverlay(color, ACCENT); mNeedsOverlayCreation = true; categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR); } catch (NumberFormatException e) { Log.w(TAG, "Invalid color definition: " + accentPalette.getPackageName()); } } // Compatibility with legacy themes, where full packages were defined, instead of just // colors. if (!categoryToPackage.containsKey(OVERLAY_CATEGORY_SYSTEM_PALETTE) && mSystemOverlay != null) { categoryToPackage.put(OVERLAY_CATEGORY_SYSTEM_PALETTE, mSystemOverlay.getIdentifier()); } if (!categoryToPackage.containsKey(OVERLAY_CATEGORY_ACCENT_COLOR) && mAccentOverlay != null) { categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, mAccentOverlay.getIdentifier()); } Set<UserHandle> userHandles = Sets.newHashSet(UserHandle.of(currentUser)); Loading @@ -341,28 +334,31 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { userHandles.add(userInfo.getUserHandle()); } } mThemeManager.applyCurrentUserOverlays(categoryToPackage, userHandles); } private String getColorString(int color) { String colorString = Integer.toHexString(color).toUpperCase(); while (colorString.length() < 6) { colorString = "0" + colorString; } // Remove alpha component if (colorString.length() > 6) { colorString = colorString.substring(colorString.length() - 6); if (DEBUG) { Log.d(TAG, "Applying overlays: " + categoryToPackage.keySet().stream() .map(key -> key + " -> " + categoryToPackage.get(key)).collect( Collectors.joining(", "))); } if (mNeedsOverlayCreation) { mNeedsOverlayCreation = false; mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[] { mSystemOverlay, mAccentOverlay }, userHandles); } else { mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, userHandles); } return colorString; } @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { pw.println("USE_LOCK_SCREEN_WALLPAPER=" + USE_LOCK_SCREEN_WALLPAPER); pw.println("mLockColors=" + mLockColors); pw.println("mSystemColors=" + mSystemColors); pw.println("mMainWallpaperColor=" + Integer.toHexString(mMainWallpaperColor)); pw.println("mWallpaperAccentColor=" + Integer.toHexString(mWallpaperAccentColor)); pw.println("mSystemOverlayColor=" + Integer.toHexString(mSystemOverlayColor)); pw.println("mAccentOverlayColor=" + Integer.toHexString(mAccentOverlayColor)); pw.println("mSystemOverlayColor=" + mSystemOverlay); pw.println("mAccentOverlayColor=" + mAccentOverlay); pw.println("mIsMonetEnabled=" + mIsMonetEnabled); pw.println("mNeedsOverlayCreation=" + mNeedsOverlayCreation); } }
packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java +50 −32 File changed.Preview size limit exceeded, changes collapsed. Show changes