android 壁纸主题色

​ android 壁纸主题色

官方文档:

https://source.android.google.cn/docs/core/display/material?hl=zh-cn
https://source.android.google.cn/docs/core/display/dynamic-color?hl=zh-cn

adb命令设置颜色:

adb shell settings put secure theme_customization_overlay_packages "\{\"android.theme.customization.system_palette\":\"1CC886\",\"android.theme.customization.theme_style\":\"TONAL_SPOT\"\}"

adb shell settings put secure theme_customization_overlay_packages "\{\"android.theme.customization.system_palette\":\"1CC886\",\"android.theme.customization.theme_style\":\"EXPRESSIVE\"\}"

主要样式:

Arrays.asList(Style.EXPRESSIVE, Style.SPRITZ, Style.TONAL_SPOT, Style.FRUIT_SALAD, Style.RAINBOW, Style.VIBRANT);

Primary:主色调(品牌主色调)Secondary:副色调(能从主色调中跳色出来)Tertiary:变化色或称第三色(可以中和主色调和副色调)Background:背景底色Surface:表层色Error:用在错误字、错误对话框

在 Material Design 3 官网还有这样区分颜色
Primary、Secondary、Tertiary又称为强调色(Accent colors)
Background、Surface 又称自然色(Neutral colors)
Error 则是追加色(Additional colors)

vendor/packages/apps/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java

   mWallpaperManager.addOnColorsChangedListener(mOnColorsChangedListener,null,UserHandle.USER_ALL);

private final OnColorsChangedListener mOnColorsChangedListener = new OnColorsChangedListener() {
        @Override
        public void onColorsChanged(WallpaperColors wallpaperColors, int which) {
            throw new IllegalStateException("This should never be invoked, all messages should "
                    + "arrive on the overload that has a user id");
        }
        @Override
    public void onColorsChanged(WallpaperColors wallpaperColors, int which, int userId) {
        ......

        handleWallpaperColors(wallpaperColors, which, userId);
    }
};
private void handleWallpaperColors(WallpaperColors wallpaperColors, int flags, int userId) {
    
    String overlayPackageJson = mSecureSettings.getStringForUser(
            Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
            currentUser);
    boolean isDestinationBoth = (flags == (WallpaperManager.FLAG_SYSTEM
            | WallpaperManager.FLAG_LOCK));
    try {
        JSONObject jsonObject = (overlayPackageJson == null) ? new JSONObject()
                : new JSONObject(overlayPackageJson);
        // The latest applied wallpaper should be the source of system colors when:
        // There is not preset color applied and the incoming wallpaper color is not applied
        if (!COLOR_SOURCE_PRESET.equals(jsonObject.optString(OVERLAY_COLOR_SOURCE))
                && ((flags & latestWallpaperType) != 0 && !isSeedColorSet(jsonObject,
                wallpaperColors))) {
            mSkipSettingChange = true;
            if (jsonObject.has(OVERLAY_CATEGORY_ACCENT_COLOR) || jsonObject.has(
                    OVERLAY_CATEGORY_SYSTEM_PALETTE)) {
                jsonObject.remove(OVERLAY_CATEGORY_ACCENT_COLOR);
                jsonObject.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE);
                jsonObject.remove(OVERLAY_COLOR_INDEX);
            }
            // Keep color_both value because users can change either or both home and
            // lock screen wallpapers.
            jsonObject.put(OVERLAY_COLOR_BOTH, isDestinationBoth ? "1" : "0");

            jsonObject.put(OVERLAY_COLOR_SOURCE,
                    (flags == WallpaperManager.FLAG_LOCK) ? COLOR_SOURCE_LOCK
                            : COLOR_SOURCE_HOME);
            jsonObject.put(TIMESTAMP_FIELD, System.currentTimeMillis());
            if (DEBUG) {
                Log.d(TAG, "Updating theme setting from "
                        + overlayPackageJson + " to " + jsonObject.toString());
            }
            mSecureSettings.putStringForUser(
                    Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
                    jsonObject.toString(), UserHandle.USER_CURRENT);
        }
    } catch (JSONException e) {
        Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e);
    }
    reevaluateSystemTheme(false /* forceReload */);
}

2.切换用户,壁纸变换,开机引导走完等调用reevaluateSystemTheme(true)

reevaluateSystemTheme(boolean forceReload)`

3.根据壁纸颜色,得到主要颜色 mSecondaryOverlay,mNeutralOverlay

 private void reevaluateSystemTheme(boolean forceReload) {
     final WallpaperColors currentColors = mCurrentColors.get(mUserTracker.getUserId());
    final int mainColor;
    if (currentColors == null) {
        mainColor = Color.TRANSPARENT;
    } else {
        mainColor = getNeutralColor(currentColors);
    }

    if (mMainWallpaperColor == mainColor && !forceReload) {
        return;
    }
    mMainWallpaperColor = mainColor;

    if (mIsMonetEnabled) {
        mThemeStyle = fetchThemeStyleFromSetting();
        mSecondaryOverlay = getOverlay(mMainWallpaperColor, ACCENT, mThemeStyle);
        mNeutralOverlay = getOverlay(mMainWallpaperColor, NEUTRAL, mThemeStyle);
        mNeedsOverlayCreation = true;
        if (DEBUG) {
            Log.d(TAG, "fetched overlays. accent: " + mSecondaryOverlay
                    + " neutral: " + mNeutralOverlay);
        }
    }

    updateThemeOverlays();
}
protected @Nullable 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);
    List<Integer> colorShades = type == ACCENT
            ? mColorScheme.getAllAccentColors() : mColorScheme.getAllNeutralColors();
    String name = type == ACCENT ? "accent" : "neutral";
    int paletteSize = mColorScheme.getAccent1().size();
    FabricatedOverlay.Builder overlay =
            new FabricatedOverlay.Builder("com.android.systemui", name, "android");
    for (int i = 0; i < colorShades.size(); i++) {
        int luminosity = i % paletteSize;
        int paletteIndex = i / paletteSize + 1;
        String resourceName;
        switch (luminosity) {
            case 0:
                resourceName = "android:color/system_" + name + paletteIndex + "_10";
                break;
            case 1:
                resourceName = "android:color/system_" + name + paletteIndex + "_50";
                break;
            default:
                int l = luminosity - 1;
                resourceName = "android:color/system_" + name + paletteIndex + "_" + l + "00";
        }
        overlay.setResourceValue(resourceName, TypedValue.TYPE_INT_COLOR_ARGB8,
                ColorUtils.setAlphaComponent(colorShades.get(i), 0xFF));
    }

    return overlay.build();
}

mssi/vendor/mediatek/proprietary/packages/apps/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt

class ColorScheme(
    @ColorInt val seed: Int,
    val darkTheme: Boolean,
    val style: Style = Style.TONAL_SPOT

) {
val accent1: List<Int>
val accent2: List<Int>
val accent3: List<Int>
val neutral1: List<Int>
val neutral2: List<Int>

constructor(@ColorInt seed: Int, darkTheme: Boolean):
        this(seed, darkTheme, Style.TONAL_SPOT)

@JvmOverloads
constructor(
    wallpaperColors: WallpaperColors,
    darkTheme: Boolean,
    style: Style = Style.TONAL_SPOT
):
        this(getSeedColor(wallpaperColors, style != Style.CONTENT), darkTheme, style)

val allAccentColors: List<Int>
    get() {
        val allColors = mutableListOf<Int>()
        allColors.addAll(accent1)
        allColors.addAll(accent2)
        allColors.addAll(accent3)
        return allColors
    }

val allNeutralColors: List<Int>
    get() {
        val allColors = mutableListOf<Int>()
        allColors.addAll(neutral1)
        allColors.addAll(neutral2)
        return allColors
    }

val backgroundColor
    get() = ColorUtils.setAlphaComponent(if (darkTheme) neutral1[8] else neutral1[0], 0xFF)

val accentColor
    get() = ColorUtils.setAlphaComponent(if (darkTheme) accent1[2] else accent1[6], 0xFF)

init {
    val proposedSeedCam = Cam.fromInt(seed)
    val seedArgb = if (seed == Color.TRANSPARENT) {
        GOOGLE_BLUE
    } else if (style != Style.CONTENT && proposedSeedCam.chroma < 5) {
        GOOGLE_BLUE
    } else {
        seed
    }
    val camSeed = Cam.fromInt(seedArgb)
   //通过从壁纸中取到seedColor得到一个camSeed Cam对象,5组颜色(其中3组强调色,2组自然色),每一组里有13种颜色
    accent1 = style.coreSpec.a1.shades(camSeed)
    accent2 = style.coreSpec.a2.shades(camSeed)
    accent3 = style.coreSpec.a3.shades(camSeed)
    neutral1 = style.coreSpec.n1.shades(camSeed)
    neutral2 = style.coreSpec.n2.shades(camSeed)
}

4.应用主题颜色到系统中applyCurrentUserOverlays

private void updateThemeOverlays() {
    final int currentUser = mUserTracker.getUserId();
    final String overlayPackageJson = mSecureSettings.getStringForUser(
            Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
            currentUser);
    if (DEBUG) Log.d(TAG, "updateThemeOverlays. Setting: " + overlayPackageJson);
    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)) {
                    OverlayIdentifier identifier =
                            new OverlayIdentifier(object.getString(category));
                    categoryToPackage.put(category, identifier);
                }
            }
        } catch (JSONException e) {
            Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e);
        }
    }

    // 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 {
            String colorString =  systemPalette.getPackageName().toLowerCase();
            if (!colorString.startsWith("#")) {
                colorString = "#" + colorString;
            }
            int color = Color.parseColor(colorString);
            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);
        }
    } else if (!mIsMonetEnabled && systemPalette != null) {
        try {
            // It's possible that we flipped the flag off and still have a @ColorInt in the
            // setting. We need to sanitize the input, otherwise the overlay transaction will
            // fail.
            categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE);
            categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR);
        } catch (NumberFormatException e) {
            // This is a package name. All good, let's continue
        }
    }

    // Compatibility with legacy themes, where full packages were defined, instead of just
    // colors.
    if (!categoryToPackage.containsKey(OVERLAY_CATEGORY_SYSTEM_PALETTE)
            && mNeutralOverlay != null) {
        categoryToPackage.put(OVERLAY_CATEGORY_SYSTEM_PALETTE,
                mNeutralOverlay.getIdentifier());
    }
    if (!categoryToPackage.containsKey(OVERLAY_CATEGORY_ACCENT_COLOR)
            && mSecondaryOverlay != null) {
        categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, mSecondaryOverlay.getIdentifier());
    }

    Set<UserHandle> managedProfiles = new HashSet<>();
    for (UserInfo userInfo : mUserManager.getEnabledProfiles(currentUser)) {
        if (userInfo.isManagedProfile()) {
            managedProfiles.add(userInfo.getUserHandle());
        }
    }

    if (colorSchemeIsApplied(managedProfiles)) {
        return;
    }

    if (DEBUG) {
        Log.d(TAG, "Applying overlays: " + categoryToPackage.keySet().stream()
                .map(key -> key + " -> " + categoryToPackage.get(key)).collect(
                        Collectors.joining(", ")));
    }
    boolean defMaterialYouEnabled = (Settings.Global.getInt(mContext.getContentResolver(),Settings.Global.DEF_MATERIAL_YOU_ENABLED, 1) == 1);
    Log.d(TAG,"defMaterialYouEnabled:"+defMaterialYouEnabled);
    if (mNeedsOverlayCreation) {
        mNeedsOverlayCreation = false;
        if(defMaterialYouEnabled)
            mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[] {
                    mSecondaryOverlay, mNeutralOverlay
            }, currentUser, managedProfiles);
    } else {
         if(defMaterialYouEnabled)
            mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, currentUser,
                managedProfiles);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值