Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97772353 authored by Santiago Etchebehere's avatar Santiago Etchebehere
Browse files

Handle custom theme with default components

If a selected component (font, icon, etc) for a custom theme
is the default one, there's no overlay package, so handle
that case.

Bug: 124796742
Change-Id: I5555af21fe96b73b6b432affb4a6185d05804421
parent bba04ac3
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -71,8 +71,8 @@ public interface ResourceConstants {
    String THEME_SETTING = Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES;
    String CONFIG_BODY_FONT_FAMILY = "config_bodyFontFamily";
    String CONFIG_HEADLINE_FONT_FAMILY = "config_headlineFontFamily";
    String ICON_PREVIEW_DRAWABLE_NAME = "ic_wifi_signal_3";
    String[] SYSUI_ICONS_FOR_PREVIEW = {
    String[] ICONS_FOR_PREVIEW = {
            "ic_wifi_signal_3",
            "ic_qs_bluetooth_on",
            "ic_dnd",
            "ic_signal_flashlight",
+65 −51
Original line number Diff line number Diff line
@@ -19,14 +19,13 @@ import static com.android.customization.model.ResourceConstants.ACCENT_COLOR_DAR
import static com.android.customization.model.ResourceConstants.ACCENT_COLOR_LIGHT_NAME;
import static com.android.customization.model.ResourceConstants.ANDROID_PACKAGE;
import static com.android.customization.model.ResourceConstants.CONFIG_ICON_MASK;
import static com.android.customization.model.ResourceConstants.ICON_PREVIEW_DRAWABLE_NAME;
import static com.android.customization.model.ResourceConstants.ICONS_FOR_PREVIEW;
import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_FONT;
import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ICON_ANDROID;
import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ICON_LAUNCHER;
import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ICON_SETTINGS;
import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ICON_SYSUI;
import static com.android.customization.model.ResourceConstants.SETTINGS_PACKAGE;
import static com.android.customization.model.ResourceConstants.SYSUI_ICONS_FOR_PREVIEW;
import static com.android.customization.model.ResourceConstants.SYSUI_PACKAGE;

import android.content.Context;
@@ -235,27 +234,23 @@ public class DefaultThemeProvider extends ResourcesApkProvider implements ThemeB
    private void addSysUiIconOverlay(Builder builder, String iconSysUiOverlayPackage)
            throws NameNotFoundException {
        if (!TextUtils.isEmpty(iconSysUiOverlayPackage)) {
            builder.addOverlayPackage(getOverlayCategory(iconSysUiOverlayPackage),
                    iconSysUiOverlayPackage);
            for (String iconName : SYSUI_ICONS_FOR_PREVIEW) {
                builder.addIcon(loadIconPreviewDrawable(iconName, iconSysUiOverlayPackage));
            }
            addIconOverlay(builder, iconSysUiOverlayPackage, ICONS_FOR_PREVIEW);
        }
    }

    private void addAndroidIconOverlay(Builder builder, String iconAndroidOverlayPackage)
            throws NameNotFoundException {
        if (!TextUtils.isEmpty(iconAndroidOverlayPackage)) {
            builder.addOverlayPackage(getOverlayCategory(iconAndroidOverlayPackage),
                        iconAndroidOverlayPackage)
                    .addIcon(loadIconPreviewDrawable(
                            ICON_PREVIEW_DRAWABLE_NAME,
                            iconAndroidOverlayPackage));
            addIconOverlay(builder, iconAndroidOverlayPackage, ICONS_FOR_PREVIEW);
        } else {
            builder.addIcon(mContext.getResources().getDrawable(
                    Resources.getSystem().getIdentifier(
                            ICON_PREVIEW_DRAWABLE_NAME,
                            "drawable", ANDROID_PACKAGE), null));
            addSystemDefaultIcons(builder, ANDROID_PACKAGE, ICONS_FOR_PREVIEW);
        }
    }
    private void addIconOverlay(Builder builder, String packageName, String... previewIcons)
            throws NameNotFoundException {
        builder.addOverlayPackage(getOverlayCategory(packageName), packageName);
        for (String iconName : previewIcons) {
            builder.addIcon(loadIconPreviewDrawable(iconName, packageName, false));
        }
    }

@@ -270,6 +265,8 @@ public class DefaultThemeProvider extends ResourcesApkProvider implements ThemeB
                    .setHeadlineFontFamily(loadTypeface(
                            ResourceConstants.CONFIG_HEADLINE_FONT_FAMILY,
                            fontOverlayPackage));
        } else {
            addSystemDefaultFont(builder);
        }
    }

@@ -280,7 +277,6 @@ public class DefaultThemeProvider extends ResourcesApkProvider implements ThemeB
     */
    private void addDefaultTheme() {
        ThemeBundle.Builder builder = new Builder().asDefault();
        Resources system = Resources.getSystem();

        int titleId = mStubApkResources.getIdentifier(TITLE_PREFIX + DEFAULT_THEME_NAME,
                "string", mStubPackageName);
@@ -298,13 +294,7 @@ public class DefaultThemeProvider extends ResourcesApkProvider implements ThemeB
                    .setColorAccentDark(loadColor(ACCENT_COLOR_DARK_NAME, colorOverlayPackage));
        } catch (NameNotFoundException | NotFoundException e) {
            Log.d(TAG, "Didn't find color overlay for default theme, will use system default", e);
            int colorAccentLight = system.getColor(
                    system.getIdentifier(ACCENT_COLOR_LIGHT_NAME, "color", ANDROID_PACKAGE), null);
            builder.setColorAccentLight(colorAccentLight);

            int colorAccentDark = system.getColor(
                    system.getIdentifier(ACCENT_COLOR_DARK_NAME, "color", ANDROID_PACKAGE), null);
            builder.setColorAccentDark(colorAccentDark);
            addSystemDefaultColor(builder);
        }

        String fontOverlayPackage = getOverlayPackage(FONT_PREFIX, DEFAULT_THEME_NAME);
@@ -318,24 +308,16 @@ public class DefaultThemeProvider extends ResourcesApkProvider implements ThemeB
                            fontOverlayPackage));
        } catch (NameNotFoundException | NotFoundException e) {
            Log.d(TAG, "Didn't find font overlay for default theme, will use system default", e);
            String headlineFontFamily = system.getString(system.getIdentifier(
                    ResourceConstants.CONFIG_HEADLINE_FONT_FAMILY,"string", ANDROID_PACKAGE));
            String bodyFontFamily = system.getString(system.getIdentifier(
                    ResourceConstants.CONFIG_BODY_FONT_FAMILY,
                    "string", ANDROID_PACKAGE));
            builder.setHeadlineFontFamily(Typeface.create(headlineFontFamily, Typeface.NORMAL))
                    .setBodyFontFamily(Typeface.create(bodyFontFamily, Typeface.NORMAL));
            addSystemDefaultFont(builder);
        }

        try {
            String shapeOverlayPackage = getOverlayPackage(SHAPE_PREFIX, DEFAULT_THEME_NAME);
            builder.addOverlayPackage(getOverlayCategory(shapeOverlayPackage), shapeOverlayPackage)
                    .setShapePath(loadString(ICON_PREVIEW_DRAWABLE_NAME, colorOverlayPackage));
                    .setShapePath(loadString(CONFIG_ICON_MASK, shapeOverlayPackage));
        } catch (NameNotFoundException | NotFoundException e) {
            Log.d(TAG, "Didn't find shape overlay for default theme, will use system default", e);
            String iconMaskPath = system.getString(system.getIdentifier(CONFIG_ICON_MASK,
                    "string", ANDROID_PACKAGE));
            builder.setShapePath(iconMaskPath);
            addSystemDefaultShape(builder);
        }
        for (String packageName : mShapePreviewIconPackages) {
            try {
@@ -353,13 +335,11 @@ public class DefaultThemeProvider extends ResourcesApkProvider implements ThemeB
            builder.addOverlayPackage(getOverlayCategory(iconAndroidOverlayPackage),
                        iconAndroidOverlayPackage)
                    .addIcon(loadIconPreviewDrawable(ICON_ANDROID_PREFIX,
                            iconAndroidOverlayPackage));
                            iconAndroidOverlayPackage, false));
        } catch (NameNotFoundException | NotFoundException e) {
            Log.d(TAG, "Didn't find Android icons overlay for default theme, using system default",
                    e);
            builder.addIcon(system.getDrawable(system.getIdentifier(
                    ICON_PREVIEW_DRAWABLE_NAME,
                            "drawable", ANDROID_PACKAGE), null));
            addSystemDefaultIcons(builder, ANDROID_PACKAGE, ICONS_FOR_PREVIEW);
        }

        try {
@@ -369,13 +349,7 @@ public class DefaultThemeProvider extends ResourcesApkProvider implements ThemeB
        } catch (NameNotFoundException | NotFoundException e) {
            Log.d(TAG, "Didn't find SystemUi icons overlay for default theme, using system default",
                    e);
            try {
                for (String iconName : SYSUI_ICONS_FOR_PREVIEW) {
                    builder.addIcon(loadIconPreviewDrawable(iconName, SYSUI_PACKAGE));
                }
            } catch (NameNotFoundException | NotFoundException e2) {
                Log.w(TAG, "Didn't find SystemUi package icons, will skip preview", e);
            }
            addSystemDefaultIcons(builder, SYSUI_PACKAGE, ICONS_FOR_PREVIEW);
        }

        try {
@@ -405,6 +379,45 @@ public class DefaultThemeProvider extends ResourcesApkProvider implements ThemeB
        mThemes.add(builder.build());
    }

    private void addSystemDefaultIcons(Builder builder, String packageName, String... previewIcons) {
        try {
            for (String iconName : previewIcons) {
                builder.addIcon(loadIconPreviewDrawable(iconName, packageName, true));
            }
        } catch (NameNotFoundException | NotFoundException e) {
            Log.w(TAG, "Didn't find android package icons, will skip preview", e);
        }
    }

    private void addSystemDefaultShape(Builder builder) {
        Resources system = Resources.getSystem();
        String iconMaskPath = system.getString(system.getIdentifier(CONFIG_ICON_MASK,
                "string", ANDROID_PACKAGE));
        builder.setShapePath(iconMaskPath);
    }

    private void addSystemDefaultColor(Builder builder) {
        Resources system = Resources.getSystem();
        int colorAccentLight = system.getColor(
                system.getIdentifier(ACCENT_COLOR_LIGHT_NAME, "color", ANDROID_PACKAGE), null);
        builder.setColorAccentLight(colorAccentLight);

        int colorAccentDark = system.getColor(
                system.getIdentifier(ACCENT_COLOR_DARK_NAME, "color", ANDROID_PACKAGE), null);
        builder.setColorAccentDark(colorAccentDark);
    }

    private void addSystemDefaultFont(Builder builder) {
        Resources system = Resources.getSystem();
        String headlineFontFamily = system.getString(system.getIdentifier(
                ResourceConstants.CONFIG_HEADLINE_FONT_FAMILY,"string", ANDROID_PACKAGE));
        String bodyFontFamily = system.getString(system.getIdentifier(
                ResourceConstants.CONFIG_BODY_FONT_FAMILY,
                "string", ANDROID_PACKAGE));
        builder.setHeadlineFontFamily(Typeface.create(headlineFontFamily, Typeface.NORMAL))
                .setBodyFontFamily(Typeface.create(bodyFontFamily, Typeface.NORMAL));
    }

    @Override
    public void storeCustomTheme(CustomTheme theme) {
        mCustomizationPreferences.storeCustomTheme(theme.getSerializedPackages());
@@ -501,12 +514,13 @@ public class DefaultThemeProvider extends ResourcesApkProvider implements ThemeB
        return overlayRes.getString(overlayRes.getIdentifier(stringName, "string", packageName));
    }

    private Drawable loadIconPreviewDrawable(String drawableName, String packageName)
         throws NameNotFoundException, NotFoundException {
    private Drawable loadIconPreviewDrawable(String drawableName, String packageName,
            boolean fromSystem) throws NameNotFoundException, NotFoundException {

        Resources overlayRes = mContext.getPackageManager().getResourcesForApplication(packageName);
        return overlayRes.getDrawable(
                overlayRes.getIdentifier(drawableName, "drawable", packageName), null);
        Resources packageRes = mContext.getPackageManager().getResourcesForApplication(packageName);
        Resources res = fromSystem ? Resources.getSystem() : packageRes;
        return res.getDrawable(
                packageRes.getIdentifier(drawableName, "drawable", packageName), null);
    }

    @Nullable
+22 −3
Original line number Diff line number Diff line
@@ -52,8 +52,11 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Represents a Theme component available in the system as a "persona" bundle.
@@ -148,16 +151,32 @@ public class ThemeBundle implements CustomizationOption<ThemeBundle> {
        return mIsDefault;
    }

    Collection<String> getAllPackages() {
        return mPackagesByCategory.values();
    public Map<String, String> getPackagesByCategory() {
        return mPackagesByCategory;
    }

    public String getSerializedPackages() {
        if (isDefault()) {
            return "";
        }
        JSONObject json = new JSONObject(mPackagesByCategory);
        // Remove items with null values to avoid deserialization issues.
        removeNullValues(json);
        return json.toString();
    }

        return new JSONObject(mPackagesByCategory).toString();
    private void removeNullValues(JSONObject json) {
        Iterator<String> keys = json.keys();
        Set<String> keysToRemove = new HashSet<>();
        while(keys.hasNext()) {
            String key = keys.next();
            if (json.isNull(key)) {
                keysToRemove.add(key);
            }
        }
        for (String key : keysToRemove) {
            json.remove(key);
        }
    }


+23 −7
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static com.android.customization.model.ResourceConstants.SYSUI_PACKAGE;
import android.graphics.Point;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;

import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
@@ -151,21 +152,26 @@ public class ThemeManager implements CustomizationManager<ThemeBundle> {
    private void applyOverlays(ThemeBundle theme, Callback callback) {
        boolean allApplied = true;
        if (theme.isDefault()) {
            allApplied &= disableCurrentOverlay(ANDROID_PACKAGE, OVERLAY_CATEGORY_SHAPE);
            allApplied &= disableCurrentOverlay(ANDROID_PACKAGE, OVERLAY_CATEGORY_COLOR);
            allApplied &= disableCurrentOverlay(ANDROID_PACKAGE, OVERLAY_CATEGORY_FONT);
            allApplied &= disableCurrentOverlay(ANDROID_PACKAGE, OVERLAY_CATEGORY_SHAPE);
            allApplied &= disableCurrentOverlay(ANDROID_PACKAGE, OVERLAY_CATEGORY_ICON_ANDROID);
            allApplied &= disableCurrentOverlay(SYSUI_PACKAGE, OVERLAY_CATEGORY_ICON_SYSUI);
            allApplied &= disableCurrentOverlay(SETTINGS_PACKAGE, OVERLAY_CATEGORY_ICON_SETTINGS);
            allApplied &= disableCurrentOverlay(ResourceConstants.getLauncherPackage(mActivity),
                    OVERLAY_CATEGORY_ICON_LAUNCHER);
        } else {
            for (String packageName : theme.getAllPackages()) {
                if (packageName != null) {
                    allApplied &= mOverlayManagerCompat.setEnabledExclusiveInCategory(packageName,
                            UserHandle.myUserId());
                }
            }
            allApplied &= applyOverlayOrDefault(theme, ANDROID_PACKAGE, OVERLAY_CATEGORY_SHAPE);
            allApplied &= applyOverlayOrDefault(theme, ANDROID_PACKAGE, OVERLAY_CATEGORY_COLOR);
            allApplied &= applyOverlayOrDefault(theme, ANDROID_PACKAGE, OVERLAY_CATEGORY_FONT);
            allApplied &= applyOverlayOrDefault(theme, ANDROID_PACKAGE,
                    OVERLAY_CATEGORY_ICON_ANDROID);
            allApplied &= applyOverlayOrDefault(theme, SYSUI_PACKAGE, OVERLAY_CATEGORY_ICON_SYSUI);
            allApplied &= applyOverlayOrDefault(theme, SETTINGS_PACKAGE,
                    OVERLAY_CATEGORY_ICON_SETTINGS);
            allApplied &= applyOverlayOrDefault(theme,
                    ResourceConstants.getLauncherPackage(mActivity),
                    OVERLAY_CATEGORY_ICON_LAUNCHER);
        }
        allApplied &= Settings.Secure.putString(mActivity.getContentResolver(),
                ResourceConstants.THEME_SETTING, theme.getSerializedPackages());
@@ -198,6 +204,16 @@ public class ThemeManager implements CustomizationManager<ThemeBundle> {
        return true;
    }

    private boolean applyOverlayOrDefault(ThemeBundle theme, String targetPkg, String category) {
        String themePackage = theme.getPackagesByCategory().get(category);
        if (!TextUtils.isEmpty(themePackage)) {
            return mOverlayManagerCompat.setEnabledExclusiveInCategory(themePackage,
                    UserHandle.myUserId());
        } else {
            return disableCurrentOverlay(targetPkg, category);
        }
    }

    public Map<String, String> getCurrentOverlays() {
        if (mCurrentOverlays == null) {
            mCurrentOverlays = mOverlayManagerCompat.getEnabledOverlaysForTargets(
+2 −2
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY
import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ICON_SYSUI;
import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_SHAPE;
import static com.android.customization.model.ResourceConstants.PATH_SIZE;
import static com.android.customization.model.ResourceConstants.SYSUI_ICONS_FOR_PREVIEW;
import static com.android.customization.model.ResourceConstants.ICONS_FOR_PREVIEW;
import static com.android.customization.model.ResourceConstants.SYSUI_PACKAGE;
import static com.android.customization.model.theme.custom.ThemeComponentOption.ColorOption.COLOR_TILES_ICON_IDS;

@@ -77,7 +77,7 @@ public class ColorOptionsProvider extends ThemeComponentOptionProvider<ColorOpti
        if (TextUtils.isEmpty(iconPackage)) {
            iconPackage = SYSUI_PACKAGE;
        }
        for (String iconName : SYSUI_ICONS_FOR_PREVIEW) {
        for (String iconName : ICONS_FOR_PREVIEW) {
            try {
                if (previewIcons.size() == COLOR_TILES_ICON_IDS.length) {
                    break;
Loading