diff options
Diffstat (limited to 'src/com/android/customization/model/theme')
14 files changed, 0 insertions, 2959 deletions
diff --git a/src/com/android/customization/model/theme/DefaultThemeProvider.java b/src/com/android/customization/model/theme/DefaultThemeProvider.java deleted file mode 100644 index 89067c65..00000000 --- a/src/com/android/customization/model/theme/DefaultThemeProvider.java +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (C) 2019 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.customization.model.theme; - -import static com.android.customization.model.ResourceConstants.ANDROID_PACKAGE; -import static com.android.customization.model.ResourceConstants.ICONS_FOR_PREVIEW; -import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_COLOR; -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.OVERLAY_CATEGORY_ICON_THEMEPICKER; -import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_SHAPE; -import static com.android.customization.model.ResourceConstants.SYSUI_PACKAGE; - -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources.NotFoundException; -import android.graphics.drawable.Drawable; -import android.text.TextUtils; -import android.util.Log; - -import androidx.annotation.Nullable; - -import com.android.customization.model.CustomizationManager.OptionsFetchedListener; -import com.android.customization.model.ResourcesApkProvider; -import com.android.customization.model.theme.ThemeBundle.Builder; -import com.android.customization.model.theme.ThemeBundle.PreviewInfo.ShapeAppIcon; -import com.android.customization.model.theme.custom.CustomTheme; -import com.android.customization.module.CustomizationPreferences; -import com.android.wallpaper.R; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * Default implementation of {@link ThemeBundleProvider} that reads Themes' overlays from a stub APK. - */ -public class DefaultThemeProvider extends ResourcesApkProvider implements ThemeBundleProvider { - - private static final String TAG = "DefaultThemeProvider"; - - private static final String THEMES_ARRAY = "themes"; - private static final String TITLE_PREFIX = "theme_title_"; - private static final String FONT_PREFIX = "theme_overlay_font_"; - private static final String COLOR_PREFIX = "theme_overlay_color_"; - private static final String SHAPE_PREFIX = "theme_overlay_shape_"; - private static final String ICON_ANDROID_PREFIX = "theme_overlay_icon_android_"; - private static final String ICON_LAUNCHER_PREFIX = "theme_overlay_icon_launcher_"; - private static final String ICON_THEMEPICKER_PREFIX = "theme_overlay_icon_themepicker_"; - private static final String ICON_SETTINGS_PREFIX = "theme_overlay_icon_settings_"; - private static final String ICON_SYSUI_PREFIX = "theme_overlay_icon_sysui_"; - - private static final String DEFAULT_THEME_NAME= "default"; - private static final String THEME_TITLE_FIELD = "_theme_title"; - private static final String THEME_ID_FIELD = "_theme_id"; - - private final OverlayThemeExtractor mOverlayProvider; - private List<ThemeBundle> mThemes; - private final CustomizationPreferences mCustomizationPreferences; - - public DefaultThemeProvider(Context context, CustomizationPreferences customizationPrefs) { - super(context, context.getString(R.string.themes_stub_package)); - mOverlayProvider = new OverlayThemeExtractor(context); - mCustomizationPreferences = customizationPrefs; - } - - @Override - public void fetch(OptionsFetchedListener<ThemeBundle> callback, boolean reload) { - if (mThemes == null || reload) { - mThemes = new ArrayList<>(); - loadAll(); - } - - if(callback != null) { - callback.onOptionsLoaded(mThemes); - } - } - - @Override - public boolean isAvailable() { - return mOverlayProvider.isAvailable() && super.isAvailable(); - } - - private void loadAll() { - // Add "Custom" option at the beginning. - mThemes.add(new CustomTheme.Builder() - .setId(CustomTheme.newId()) - .setTitle(mContext.getString(R.string.custom_theme)) - .build(mContext)); - - addDefaultTheme(); - - String[] themeNames = getItemsFromStub(THEMES_ARRAY); - - for (String themeName : themeNames) { - // Default theme needs special treatment (see #addDefaultTheme()) - if (DEFAULT_THEME_NAME.equals(themeName)) { - continue; - } - ThemeBundle.Builder builder = new Builder(); - try { - builder.setTitle(mStubApkResources.getString( - mStubApkResources.getIdentifier(TITLE_PREFIX + themeName, - "string", mStubPackageName))); - - String shapeOverlayPackage = getOverlayPackage(SHAPE_PREFIX, themeName); - mOverlayProvider.addShapeOverlay(builder, shapeOverlayPackage); - - String fontOverlayPackage = getOverlayPackage(FONT_PREFIX, themeName); - mOverlayProvider.addFontOverlay(builder, fontOverlayPackage); - - String colorOverlayPackage = getOverlayPackage(COLOR_PREFIX, themeName); - mOverlayProvider.addColorOverlay(builder, colorOverlayPackage); - - String iconAndroidOverlayPackage = getOverlayPackage(ICON_ANDROID_PREFIX, - themeName); - - mOverlayProvider.addAndroidIconOverlay(builder, iconAndroidOverlayPackage); - - String iconSysUiOverlayPackage = getOverlayPackage(ICON_SYSUI_PREFIX, themeName); - - mOverlayProvider.addSysUiIconOverlay(builder, iconSysUiOverlayPackage); - - String iconLauncherOverlayPackage = getOverlayPackage(ICON_LAUNCHER_PREFIX, - themeName); - mOverlayProvider.addNoPreviewIconOverlay(builder, iconLauncherOverlayPackage); - - String iconThemePickerOverlayPackage = getOverlayPackage(ICON_THEMEPICKER_PREFIX, - themeName); - mOverlayProvider.addNoPreviewIconOverlay(builder, - iconThemePickerOverlayPackage); - - String iconSettingsOverlayPackage = getOverlayPackage(ICON_SETTINGS_PREFIX, - themeName); - - mOverlayProvider.addNoPreviewIconOverlay(builder, iconSettingsOverlayPackage); - - mThemes.add(builder.build(mContext)); - } catch (NameNotFoundException | NotFoundException e) { - Log.w(TAG, String.format("Couldn't load part of theme %s, will skip it", themeName), - e); - } - } - - addCustomThemes(); - } - - /** - * Default theme requires different treatment: if there are overlay packages specified in the - * stub apk, we'll use those, otherwise we'll get the System default values. But we cannot skip - * the default theme. - */ - private void addDefaultTheme() { - ThemeBundle.Builder builder = new Builder().asDefault(); - - int titleId = mStubApkResources.getIdentifier(TITLE_PREFIX + DEFAULT_THEME_NAME, - "string", mStubPackageName); - if (titleId > 0) { - builder.setTitle(mStubApkResources.getString(titleId)); - } else { - builder.setTitle(mContext.getString(R.string.default_theme_title)); - } - - try { - String colorOverlayPackage = getOverlayPackage(COLOR_PREFIX, DEFAULT_THEME_NAME); - mOverlayProvider.addColorOverlay(builder, colorOverlayPackage); - } catch (NameNotFoundException | NotFoundException e) { - Log.d(TAG, "Didn't find color overlay for default theme, will use system default"); - mOverlayProvider.addSystemDefaultColor(builder); - } - - try { - String fontOverlayPackage = getOverlayPackage(FONT_PREFIX, DEFAULT_THEME_NAME); - mOverlayProvider.addFontOverlay(builder, fontOverlayPackage); - } catch (NameNotFoundException | NotFoundException e) { - Log.d(TAG, "Didn't find font overlay for default theme, will use system default"); - mOverlayProvider.addSystemDefaultFont(builder); - } - - try { - String shapeOverlayPackage = getOverlayPackage(SHAPE_PREFIX, DEFAULT_THEME_NAME); - mOverlayProvider.addShapeOverlay(builder ,shapeOverlayPackage, false); - } catch (NameNotFoundException | NotFoundException e) { - Log.d(TAG, "Didn't find shape overlay for default theme, will use system default"); - mOverlayProvider.addSystemDefaultShape(builder); - } - - List<ShapeAppIcon> icons = new ArrayList<>(); - for (String packageName : mOverlayProvider.getShapePreviewIconPackages()) { - Drawable icon = null; - CharSequence name = null; - try { - icon = mContext.getPackageManager().getApplicationIcon(packageName); - ApplicationInfo appInfo = mContext.getPackageManager() - .getApplicationInfo(packageName, /* flag= */ 0); - name = mContext.getPackageManager().getApplicationLabel(appInfo); - } catch (NameNotFoundException e) { - Log.d(TAG, "Couldn't find app " + packageName + ", won't use it for icon shape" - + "preview"); - } finally { - if (icon != null && !TextUtils.isEmpty(name)) { - icons.add(new ShapeAppIcon(icon, name)); - } - } - } - builder.setShapePreviewIcons(icons); - - try { - String iconAndroidOverlayPackage = getOverlayPackage(ICON_ANDROID_PREFIX, - DEFAULT_THEME_NAME); - mOverlayProvider.addAndroidIconOverlay(builder, iconAndroidOverlayPackage); - } catch (NameNotFoundException | NotFoundException e) { - Log.d(TAG, "Didn't find Android icons overlay for default theme, using system default"); - mOverlayProvider.addSystemDefaultIcons(builder, ANDROID_PACKAGE, ICONS_FOR_PREVIEW); - } - - try { - String iconSysUiOverlayPackage = getOverlayPackage(ICON_SYSUI_PREFIX, - DEFAULT_THEME_NAME); - mOverlayProvider.addSysUiIconOverlay(builder, iconSysUiOverlayPackage); - } catch (NameNotFoundException | NotFoundException e) { - Log.d(TAG, - "Didn't find SystemUi icons overlay for default theme, using system default"); - mOverlayProvider.addSystemDefaultIcons(builder, SYSUI_PACKAGE, ICONS_FOR_PREVIEW); - } - - mThemes.add(builder.build(mContext)); - } - - @Override - public void storeCustomTheme(CustomTheme theme) { - if (mThemes == null) { - fetch(options -> { - addCustomThemeAndStore(theme); - }, false); - } else { - addCustomThemeAndStore(theme); - } - } - - private void addCustomThemeAndStore(CustomTheme theme) { - if (!mThemes.contains(theme)) { - mThemes.add(theme); - } else { - mThemes.replaceAll(t -> theme.equals(t) ? theme : t); - } - JSONArray themesArray = new JSONArray(); - mThemes.stream() - .filter(themeBundle -> themeBundle instanceof CustomTheme - && !themeBundle.getPackagesByCategory().isEmpty()) - .forEachOrdered(themeBundle -> addThemeBundleToArray(themesArray, themeBundle)); - mCustomizationPreferences.storeCustomThemes(themesArray.toString()); - } - - private void addThemeBundleToArray(JSONArray themesArray, ThemeBundle themeBundle) { - JSONObject jsonPackages = themeBundle.getJsonPackages(false); - try { - jsonPackages.put(THEME_TITLE_FIELD, themeBundle.getTitle()); - if (themeBundle instanceof CustomTheme) { - jsonPackages.put(THEME_ID_FIELD, ((CustomTheme)themeBundle).getId()); - } - } catch (JSONException e) { - Log.w("Exception saving theme's title", e); - } - themesArray.put(jsonPackages); - } - - @Override - public void removeCustomTheme(CustomTheme theme) { - JSONArray themesArray = new JSONArray(); - mThemes.stream() - .filter(themeBundle -> themeBundle instanceof CustomTheme - && ((CustomTheme) themeBundle).isDefined()) - .forEachOrdered(customTheme -> { - if (!customTheme.equals(theme)) { - addThemeBundleToArray(themesArray, customTheme); - } - }); - mCustomizationPreferences.storeCustomThemes(themesArray.toString()); - } - - private void addCustomThemes() { - String serializedThemes = mCustomizationPreferences.getSerializedCustomThemes(); - int customThemesCount = 0; - if (!TextUtils.isEmpty(serializedThemes)) { - try { - JSONArray customThemes = new JSONArray(serializedThemes); - for (int i = 0; i < customThemes.length(); i++) { - JSONObject jsonTheme = customThemes.getJSONObject(i); - CustomTheme.Builder builder = new CustomTheme.Builder(); - try { - convertJsonToBuilder(jsonTheme, builder); - } catch (NameNotFoundException | NotFoundException e) { - Log.i(TAG, "Couldn't parse serialized custom theme", e); - builder = null; - } - if (builder != null) { - if (TextUtils.isEmpty(builder.getTitle())) { - builder.setTitle(mContext.getString(R.string.custom_theme_title, - customThemesCount + 1)); - } - mThemes.add(builder.build(mContext)); - } else { - Log.w(TAG, "Couldn't read stored custom theme, resetting"); - mThemes.add(new CustomTheme.Builder() - .setId(CustomTheme.newId()) - .setTitle(mContext.getString( - R.string.custom_theme_title, customThemesCount + 1)) - .build(mContext)); - } - customThemesCount++; - } - } catch (JSONException e) { - Log.w(TAG, "Couldn't read stored custom theme, resetting", e); - mThemes.add(new CustomTheme.Builder() - .setId(CustomTheme.newId()) - .setTitle(mContext.getString( - R.string.custom_theme_title, customThemesCount + 1)) - .build(mContext)); - } - } - } - - @Nullable - @Override - public ThemeBundle.Builder parseThemeBundle(String serializedTheme) throws JSONException { - JSONObject theme = new JSONObject(serializedTheme); - try { - ThemeBundle.Builder builder = new ThemeBundle.Builder(); - convertJsonToBuilder(theme, builder); - return builder; - } catch (NameNotFoundException | NotFoundException e) { - Log.i(TAG, "Couldn't parse serialized custom theme", e); - return null; - } - } - - @Nullable - @Override - public CustomTheme.Builder parseCustomTheme(String serializedTheme) throws JSONException { - JSONObject theme = new JSONObject(serializedTheme); - try { - CustomTheme.Builder builder = new CustomTheme.Builder(); - convertJsonToBuilder(theme, builder); - return builder; - } catch (NameNotFoundException | NotFoundException e) { - Log.i(TAG, "Couldn't parse serialized custom theme", e); - return null; - } - } - - private void convertJsonToBuilder(JSONObject theme, ThemeBundle.Builder builder) - throws JSONException, NameNotFoundException, NotFoundException { - Map<String, String> customPackages = new HashMap<>(); - Iterator<String> keysIterator = theme.keys(); - - while (keysIterator.hasNext()) { - String category = keysIterator.next(); - customPackages.put(category, theme.getString(category)); - } - mOverlayProvider.addShapeOverlay(builder, - customPackages.get(OVERLAY_CATEGORY_SHAPE)); - mOverlayProvider.addFontOverlay(builder, - customPackages.get(OVERLAY_CATEGORY_FONT)); - mOverlayProvider.addColorOverlay(builder, - customPackages.get(OVERLAY_CATEGORY_COLOR)); - mOverlayProvider.addAndroidIconOverlay(builder, - customPackages.get(OVERLAY_CATEGORY_ICON_ANDROID)); - mOverlayProvider.addSysUiIconOverlay(builder, - customPackages.get(OVERLAY_CATEGORY_ICON_SYSUI)); - mOverlayProvider.addNoPreviewIconOverlay(builder, - customPackages.get(OVERLAY_CATEGORY_ICON_SETTINGS)); - mOverlayProvider.addNoPreviewIconOverlay(builder, - customPackages.get(OVERLAY_CATEGORY_ICON_LAUNCHER)); - mOverlayProvider.addNoPreviewIconOverlay(builder, - customPackages.get(OVERLAY_CATEGORY_ICON_THEMEPICKER)); - if (theme.has(THEME_TITLE_FIELD)) { - builder.setTitle(theme.getString(THEME_TITLE_FIELD)); - } - if (builder instanceof CustomTheme.Builder && theme.has(THEME_ID_FIELD)) { - ((CustomTheme.Builder) builder).setId(theme.getString(THEME_ID_FIELD)); - } - } - - @Override - public ThemeBundle findEquivalent(ThemeBundle other) { - if (mThemes == null) { - return null; - } - for (ThemeBundle theme : mThemes) { - if (theme.isEquivalent(other)) { - return theme; - } - } - return null; - } - - private String getOverlayPackage(String prefix, String themeName) { - return getItemStringFromStub(prefix, themeName); - } -} diff --git a/src/com/android/customization/model/theme/OverlayThemeExtractor.java b/src/com/android/customization/model/theme/OverlayThemeExtractor.java deleted file mode 100644 index 816176e7..00000000 --- a/src/com/android/customization/model/theme/OverlayThemeExtractor.java +++ /dev/null @@ -1,293 +0,0 @@ -package com.android.customization.model.theme; - -import static com.android.customization.model.ResourceConstants.ANDROID_PACKAGE; -import static com.android.customization.model.ResourceConstants.ICONS_FOR_PREVIEW; -import static com.android.customization.model.ResourceConstants.SETTINGS_PACKAGE; -import static com.android.customization.model.ResourceConstants.SYSUI_PACKAGE; - -import android.content.Context; -import android.content.om.OverlayInfo; -import android.content.om.OverlayManager; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; -import android.graphics.Typeface; -import android.graphics.drawable.Drawable; -import android.os.UserHandle; -import android.text.TextUtils; -import android.util.Log; - -import androidx.annotation.Dimension; -import androidx.annotation.Nullable; - -import com.android.customization.model.ResourceConstants; -import com.android.customization.model.theme.ThemeBundle.Builder; -import com.android.customization.model.theme.ThemeBundle.PreviewInfo.ShapeAppIcon; -import com.android.wallpaper.R; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; - -class OverlayThemeExtractor { - - private static final String TAG = "OverlayThemeExtractor"; - - private final Context mContext; - private final Map<String, OverlayInfo> mOverlayInfos = new HashMap<>(); - // List of packages - private final String[] mShapePreviewIconPackages; - - OverlayThemeExtractor(Context context) { - mContext = context; - OverlayManager om = context.getSystemService(OverlayManager.class); - if (om != null) { - Consumer<OverlayInfo> addToMap = overlayInfo -> mOverlayInfos.put( - overlayInfo.getPackageName(), overlayInfo); - - UserHandle user = UserHandle.of(UserHandle.myUserId()); - om.getOverlayInfosForTarget(ANDROID_PACKAGE, user).forEach(addToMap); - om.getOverlayInfosForTarget(SYSUI_PACKAGE, user).forEach(addToMap); - om.getOverlayInfosForTarget(SETTINGS_PACKAGE, user).forEach(addToMap); - om.getOverlayInfosForTarget(ResourceConstants.getLauncherPackage(context), user) - .forEach(addToMap); - om.getOverlayInfosForTarget(context.getPackageName(), user).forEach(addToMap); - } - mShapePreviewIconPackages = context.getResources().getStringArray( - R.array.icon_shape_preview_packages); - } - - boolean isAvailable() { - return !mOverlayInfos.isEmpty(); - } - - void addColorOverlay(Builder builder, String colorOverlayPackage) - throws NameNotFoundException { - if (!TextUtils.isEmpty(colorOverlayPackage)) { - builder.addOverlayPackage(getOverlayCategory(colorOverlayPackage), - colorOverlayPackage) - .setColorAccentLight(loadColor(ResourceConstants.ACCENT_COLOR_LIGHT_NAME, - colorOverlayPackage)) - .setColorAccentDark(loadColor(ResourceConstants.ACCENT_COLOR_DARK_NAME, - colorOverlayPackage)); - } else { - addSystemDefaultColor(builder); - } - } - - void addShapeOverlay(Builder builder, String shapeOverlayPackage) - throws NameNotFoundException { - addShapeOverlay(builder, shapeOverlayPackage, true); - } - - void addShapeOverlay(Builder builder, String shapeOverlayPackage, boolean addPreview) - throws NameNotFoundException { - if (!TextUtils.isEmpty(shapeOverlayPackage)) { - builder.addOverlayPackage(getOverlayCategory(shapeOverlayPackage), - shapeOverlayPackage) - .setShapePath( - loadString(ResourceConstants.CONFIG_ICON_MASK, shapeOverlayPackage)) - .setBottomSheetCornerRadius( - loadDimen(ResourceConstants.CONFIG_CORNERRADIUS, shapeOverlayPackage)); - } else { - addSystemDefaultShape(builder); - } - if (addPreview) { - addShapePreviewIcons(builder); - } - } - - private void addShapePreviewIcons(Builder builder) { - List<ShapeAppIcon> icons = new ArrayList<>(); - for (String packageName : mShapePreviewIconPackages) { - Drawable icon = null; - CharSequence name = null; - try { - icon = mContext.getPackageManager().getApplicationIcon(packageName); - // Add the shape icon app name. - ApplicationInfo appInfo = mContext.getPackageManager() - .getApplicationInfo(packageName, /* flag= */ 0); - name = mContext.getPackageManager().getApplicationLabel(appInfo); - } catch (NameNotFoundException e) { - Log.d(TAG, "Couldn't find app " + packageName - + ", won't use it for icon shape preview"); - } finally { - if (icon != null && !TextUtils.isEmpty(name)) { - icons.add(new ShapeAppIcon(icon, name)); - } - } - } - builder.setShapePreviewIcons(icons); - } - - void addNoPreviewIconOverlay(Builder builder, String overlayPackage) { - if (!TextUtils.isEmpty(overlayPackage)) { - builder.addOverlayPackage(getOverlayCategory(overlayPackage), - overlayPackage); - } - } - - void addSysUiIconOverlay(Builder builder, String iconSysUiOverlayPackage) - throws NameNotFoundException { - if (!TextUtils.isEmpty(iconSysUiOverlayPackage)) { - addIconOverlay(builder, iconSysUiOverlayPackage); - } - } - - void addAndroidIconOverlay(Builder builder, String iconAndroidOverlayPackage) - throws NameNotFoundException { - if (!TextUtils.isEmpty(iconAndroidOverlayPackage)) { - addIconOverlay(builder, iconAndroidOverlayPackage, ICONS_FOR_PREVIEW); - } else { - addSystemDefaultIcons(builder, ANDROID_PACKAGE, ICONS_FOR_PREVIEW); - } - } - - 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)); - } - } - - void addFontOverlay(Builder builder, String fontOverlayPackage) - throws NameNotFoundException { - if (!TextUtils.isEmpty(fontOverlayPackage)) { - builder.addOverlayPackage(getOverlayCategory(fontOverlayPackage), - fontOverlayPackage) - .setBodyFontFamily(loadTypeface( - ResourceConstants.CONFIG_BODY_FONT_FAMILY, - fontOverlayPackage)) - .setHeadlineFontFamily(loadTypeface( - ResourceConstants.CONFIG_HEADLINE_FONT_FAMILY, - fontOverlayPackage)); - } else { - addSystemDefaultFont(builder); - } - } - - 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); - } - } - - void addSystemDefaultShape(Builder builder) { - Resources system = Resources.getSystem(); - String iconMaskPath = system.getString( - system.getIdentifier(ResourceConstants.CONFIG_ICON_MASK, - "string", ResourceConstants.ANDROID_PACKAGE)); - builder.setShapePath(iconMaskPath) - .setBottomSheetCornerRadius( - system.getDimensionPixelOffset( - system.getIdentifier(ResourceConstants.CONFIG_CORNERRADIUS, - "dimen", ResourceConstants.ANDROID_PACKAGE))); - } - - void addSystemDefaultColor(Builder builder) { - Resources system = Resources.getSystem(); - int colorAccentLight = system.getColor( - system.getIdentifier(ResourceConstants.ACCENT_COLOR_LIGHT_NAME, "color", - ResourceConstants.ANDROID_PACKAGE), null); - builder.setColorAccentLight(colorAccentLight); - - int colorAccentDark = system.getColor( - system.getIdentifier(ResourceConstants.ACCENT_COLOR_DARK_NAME, "color", - ResourceConstants.ANDROID_PACKAGE), null); - builder.setColorAccentDark(colorAccentDark); - } - - void addSystemDefaultFont(Builder builder) { - Resources system = Resources.getSystem(); - String headlineFontFamily = system.getString(system.getIdentifier( - ResourceConstants.CONFIG_HEADLINE_FONT_FAMILY, "string", - ResourceConstants.ANDROID_PACKAGE)); - String bodyFontFamily = system.getString(system.getIdentifier( - ResourceConstants.CONFIG_BODY_FONT_FAMILY, - "string", ResourceConstants.ANDROID_PACKAGE)); - builder.setHeadlineFontFamily(Typeface.create(headlineFontFamily, Typeface.NORMAL)) - .setBodyFontFamily(Typeface.create(bodyFontFamily, Typeface.NORMAL)); - } - - Typeface loadTypeface(String configName, String fontOverlayPackage) - throws NameNotFoundException, NotFoundException { - - // TODO(santie): check for font being present in system - - Resources overlayRes = mContext.getPackageManager() - .getResourcesForApplication(fontOverlayPackage); - - String fontFamily = overlayRes.getString(overlayRes.getIdentifier(configName, - "string", fontOverlayPackage)); - return Typeface.create(fontFamily, Typeface.NORMAL); - } - - int loadColor(String colorName, String colorPackage) - throws NameNotFoundException, NotFoundException { - - Resources overlayRes = mContext.getPackageManager() - .getResourcesForApplication(colorPackage); - return overlayRes.getColor(overlayRes.getIdentifier(colorName, "color", colorPackage), - null); - } - - String loadString(String stringName, String packageName) - throws NameNotFoundException, NotFoundException { - - Resources overlayRes = - mContext.getPackageManager().getResourcesForApplication( - packageName); - return overlayRes.getString(overlayRes.getIdentifier(stringName, "string", packageName)); - } - - @Dimension - int loadDimen(String dimenName, String packageName) - throws NameNotFoundException, NotFoundException { - - Resources overlayRes = - mContext.getPackageManager().getResourcesForApplication( - packageName); - return overlayRes.getDimensionPixelOffset(overlayRes.getIdentifier( - dimenName, "dimen", packageName)); - } - - boolean loadBoolean(String booleanName, String packageName) - throws NameNotFoundException, NotFoundException { - - Resources overlayRes = - mContext.getPackageManager().getResourcesForApplication( - packageName); - return overlayRes.getBoolean(overlayRes.getIdentifier( - booleanName, "boolean", packageName)); - } - - Drawable loadIconPreviewDrawable(String drawableName, String packageName, - boolean fromSystem) throws NameNotFoundException, NotFoundException { - - Resources packageRes = - mContext.getPackageManager().getResourcesForApplication( - packageName); - Resources res = fromSystem ? Resources.getSystem() : packageRes; - return res.getDrawable( - packageRes.getIdentifier(drawableName, "drawable", packageName), null); - } - - @Nullable - String getOverlayCategory(String packageName) { - OverlayInfo info = mOverlayInfos.get(packageName); - return info != null ? info.getCategory() : null; - } - - String[] getShapePreviewIconPackages() { - return mShapePreviewIconPackages; - } -}
\ No newline at end of file diff --git a/src/com/android/customization/model/theme/ThemeBundle.java b/src/com/android/customization/model/theme/ThemeBundle.java deleted file mode 100644 index 3a32f257..00000000 --- a/src/com/android/customization/model/theme/ThemeBundle.java +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Copyright (C) 2019 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.customization.model.theme; - -import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_COLOR; -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_SHAPE; -import static com.android.customization.model.ResourceConstants.PATH_SIZE; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.Path; -import android.graphics.Typeface; -import android.graphics.drawable.AdaptiveIconDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.ShapeDrawable; -import android.graphics.drawable.shapes.PathShape; -import android.text.TextUtils; -import android.util.Log; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import androidx.annotation.ColorInt; -import androidx.annotation.Dimension; -import androidx.annotation.Nullable; -import androidx.core.graphics.PathParser; - -import com.android.customization.model.CustomizationManager; -import com.android.customization.model.CustomizationOption; -import com.android.customization.model.theme.ThemeBundle.PreviewInfo.ShapeAppIcon; -import com.android.customization.widget.DynamicAdaptiveIconDrawable; -import com.android.wallpaper.R; -import com.android.wallpaper.asset.Asset; -import com.android.wallpaper.asset.BitmapCachingAsset; -import com.android.wallpaper.model.WallpaperInfo; -import com.android.wallpaper.util.ResourceUtils; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -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; -import java.util.stream.Collectors; - -/** - * Represents a Theme component available in the system as a "persona" bundle. - * Note that in this context a Theme is not related to Android's Styles, but it's rather an - * abstraction representing a series of overlays to be applied to the system. - */ -public class ThemeBundle implements CustomizationOption<ThemeBundle> { - - private static final String TAG = "ThemeBundle"; - private final static String EMPTY_JSON = "{}"; - private final static String TIMESTAMP_FIELD = "_applied_timestamp"; - - private final String mTitle; - private final PreviewInfo mPreviewInfo; - private final boolean mIsDefault; - protected final Map<String, String> mPackagesByCategory; - private WallpaperInfo mOverrideWallpaper; - private Asset mOverrideWallpaperAsset; - private CharSequence mContentDescription; - - protected ThemeBundle(String title, Map<String, String> overlayPackages, - boolean isDefault, PreviewInfo previewInfo) { - mTitle = title; - mIsDefault = isDefault; - mPreviewInfo = previewInfo; - mPackagesByCategory = Collections.unmodifiableMap(removeNullValues(overlayPackages)); - } - - @Override - public String getTitle() { - return mTitle; - } - - @Override - public void bindThumbnailTile(View view) { - Resources res = view.getContext().getResources(); - - ((TextView) view.findViewById(R.id.theme_option_font)).setTypeface( - mPreviewInfo.headlineFontFamily); - if (mPreviewInfo.shapeDrawable != null) { - ((ShapeDrawable) mPreviewInfo.shapeDrawable).getPaint().setColor( - mPreviewInfo.resolveAccentColor(res)); - ((ImageView) view.findViewById(R.id.theme_option_shape)).setImageDrawable( - mPreviewInfo.shapeDrawable); - } - if (!mPreviewInfo.icons.isEmpty()) { - Drawable icon = mPreviewInfo.icons.get(0).getConstantState().newDrawable().mutate(); - icon.setTint(ResourceUtils.getColorAttr( - view.getContext(), android.R.attr.textColorSecondary)); - ((ImageView) view.findViewById(R.id.theme_option_icon)).setImageDrawable( - icon); - } - view.setContentDescription(getContentDescription(view.getContext())); - } - - @Override - public boolean isActive(CustomizationManager<ThemeBundle> manager) { - ThemeManager themeManager = (ThemeManager) manager; - - if (mIsDefault) { - String serializedOverlays = themeManager.getStoredOverlays(); - return TextUtils.isEmpty(serializedOverlays) || EMPTY_JSON.equals(serializedOverlays); - } else { - Map<String, String> currentOverlays = themeManager.getCurrentOverlays(); - return mPackagesByCategory.equals(currentOverlays); - } - } - - @Override - public int getLayoutResId() { - return R.layout.theme_option; - } - - /** - * This is similar to #equals() but it only compares this theme's packages with the other, that - * is, it will return true if applying this theme has the same effect of applying the given one. - */ - public boolean isEquivalent(ThemeBundle other) { - if (other == null) { - return false; - } - if (mIsDefault) { - return other.isDefault() || TextUtils.isEmpty(other.getSerializedPackages()) - || EMPTY_JSON.equals(other.getSerializedPackages()); - } - // Map#equals ensures keys and values are compared. - return mPackagesByCategory.equals(other.mPackagesByCategory); - } - - public PreviewInfo getPreviewInfo() { - return mPreviewInfo; - } - - public void setOverrideThemeWallpaper(WallpaperInfo homeWallpaper) { - mOverrideWallpaper = homeWallpaper; - mOverrideWallpaperAsset = null; - } - - private Asset getOverrideWallpaperAsset(Context context) { - if (mOverrideWallpaperAsset == null) { - mOverrideWallpaperAsset = new BitmapCachingAsset(context, - mOverrideWallpaper.getThumbAsset(context)); - } - return mOverrideWallpaperAsset; - } - - boolean isDefault() { - return mIsDefault; - } - - public Map<String, String> getPackagesByCategory() { - return mPackagesByCategory; - } - - public String getSerializedPackages() { - return getJsonPackages(false).toString(); - } - - public String getSerializedPackagesWithTimestamp() { - return getJsonPackages(true).toString(); - } - - JSONObject getJsonPackages(boolean insertTimestamp) { - if (isDefault()) { - return new JSONObject(); - } - JSONObject json = new JSONObject(mPackagesByCategory); - // Remove items with null values to avoid deserialization issues. - removeNullValues(json); - if (insertTimestamp) { - try { - json.put(TIMESTAMP_FIELD, System.currentTimeMillis()); - } catch (JSONException e) { - Log.e(TAG, "Couldn't add timestamp to serialized themebundle"); - } - } - return json; - } - - 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); - } - } - - private Map<String, String> removeNullValues(Map<String, String> map) { - return map.entrySet() - .stream() - .filter(entry -> entry.getValue() != null) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - } - - protected CharSequence getContentDescription(Context context) { - if (mContentDescription == null) { - CharSequence defaultName = context.getString(R.string.default_theme_title); - if (isDefault()) { - mContentDescription = defaultName; - } else { - PackageManager pm = context.getPackageManager(); - CharSequence fontName = getOverlayName(pm, OVERLAY_CATEGORY_FONT); - CharSequence iconName = getOverlayName(pm, OVERLAY_CATEGORY_ICON_ANDROID); - CharSequence shapeName = getOverlayName(pm, OVERLAY_CATEGORY_SHAPE); - CharSequence colorName = getOverlayName(pm, OVERLAY_CATEGORY_COLOR); - mContentDescription = context.getString(R.string.theme_description, - TextUtils.isEmpty(fontName) ? defaultName : fontName, - TextUtils.isEmpty(iconName) ? defaultName : iconName, - TextUtils.isEmpty(shapeName) ? defaultName : shapeName, - TextUtils.isEmpty(colorName) ? defaultName : colorName); - } - } - return mContentDescription; - } - - private CharSequence getOverlayName(PackageManager pm, String overlayCategoryFont) { - try { - return pm.getApplicationInfo( - mPackagesByCategory.get(overlayCategoryFont), 0).loadLabel(pm); - } catch (PackageManager.NameNotFoundException e) { - return ""; - } - } - - public static class PreviewInfo { - public final Typeface bodyFontFamily; - public final Typeface headlineFontFamily; - @ColorInt public final int colorAccentLight; - @ColorInt public final int colorAccentDark; - public final List<Drawable> icons; - public final Drawable shapeDrawable; - public final List<ShapeAppIcon> shapeAppIcons; - @Dimension public final int bottomSheeetCornerRadius; - - /** A class to represent an App icon and its name. */ - public static class ShapeAppIcon { - private Drawable mIconDrawable; - private CharSequence mAppName; - - public ShapeAppIcon(Drawable icon, CharSequence appName) { - mIconDrawable = icon; - mAppName = appName; - } - - /** Returns a copy of app icon drawable. */ - public Drawable getDrawableCopy() { - return mIconDrawable.getConstantState().newDrawable().mutate(); - } - - /** Returns the app name. */ - public CharSequence getAppName() { - return mAppName; - } - } - - private PreviewInfo(Context context, Typeface bodyFontFamily, Typeface headlineFontFamily, - int colorAccentLight, int colorAccentDark, List<Drawable> icons, - Drawable shapeDrawable, @Dimension int cornerRadius, - List<ShapeAppIcon> shapeAppIcons) { - this.bodyFontFamily = bodyFontFamily; - this.headlineFontFamily = headlineFontFamily; - this.colorAccentLight = colorAccentLight; - this.colorAccentDark = colorAccentDark; - this.icons = icons; - this.shapeDrawable = shapeDrawable; - this.bottomSheeetCornerRadius = cornerRadius; - this.shapeAppIcons = shapeAppIcons; - } - - /** - * Returns the accent color to be applied corresponding with the current configuration's - * UI mode. - * @return one of {@link #colorAccentDark} or {@link #colorAccentLight} - */ - @ColorInt - public int resolveAccentColor(Resources res) { - return (res.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) - == Configuration.UI_MODE_NIGHT_YES ? colorAccentDark : colorAccentLight; - } - } - - public static class Builder { - protected String mTitle; - private Typeface mBodyFontFamily; - private Typeface mHeadlineFontFamily; - @ColorInt private int mColorAccentLight = -1; - @ColorInt private int mColorAccentDark = -1; - private List<Drawable> mIcons = new ArrayList<>(); - private String mPathString; - private Path mShapePath; - private boolean mIsDefault; - @Dimension private int mCornerRadius; - protected Map<String, String> mPackages = new HashMap<>(); - private List<ShapeAppIcon> mAppIcons = new ArrayList<>(); - - public ThemeBundle build(Context context) { - return new ThemeBundle(mTitle, mPackages, mIsDefault, createPreviewInfo(context)); - } - - public PreviewInfo createPreviewInfo(Context context) { - ShapeDrawable shapeDrawable = null; - List<ShapeAppIcon> shapeIcons = new ArrayList<>(); - Path path = mShapePath; - if (!TextUtils.isEmpty(mPathString)) { - path = PathParser.createPathFromPathData(mPathString); - } - if (path != null) { - PathShape shape = new PathShape(path, PATH_SIZE, PATH_SIZE); - shapeDrawable = new ShapeDrawable(shape); - shapeDrawable.setIntrinsicHeight((int) PATH_SIZE); - shapeDrawable.setIntrinsicWidth((int) PATH_SIZE); - for (ShapeAppIcon icon : mAppIcons) { - Drawable drawable = icon.mIconDrawable; - if (drawable instanceof AdaptiveIconDrawable) { - AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) drawable; - shapeIcons.add(new ShapeAppIcon( - new DynamicAdaptiveIconDrawable(adaptiveIcon.getBackground(), - adaptiveIcon.getForeground(), path), - icon.getAppName())); - } else if (drawable instanceof DynamicAdaptiveIconDrawable) { - shapeIcons.add(icon); - } - // TODO: add iconloader library's legacy treatment helper methods for - // non-adaptive icons - } - } - return new PreviewInfo(context, mBodyFontFamily, mHeadlineFontFamily, mColorAccentLight, - mColorAccentDark, mIcons, shapeDrawable, mCornerRadius, shapeIcons); - } - - public Map<String, String> getPackages() { - return Collections.unmodifiableMap(mPackages); - } - - public String getTitle() { - return mTitle; - } - - public Builder setTitle(String title) { - mTitle = title; - return this; - } - - public Builder setBodyFontFamily(@Nullable Typeface bodyFontFamily) { - mBodyFontFamily = bodyFontFamily; - return this; - } - - public Builder setHeadlineFontFamily(@Nullable Typeface headlineFontFamily) { - mHeadlineFontFamily = headlineFontFamily; - return this; - } - - public Builder setColorAccentLight(@ColorInt int colorAccentLight) { - mColorAccentLight = colorAccentLight; - return this; - } - - public Builder setColorAccentDark(@ColorInt int colorAccentDark) { - mColorAccentDark = colorAccentDark; - return this; - } - - public Builder addIcon(Drawable icon) { - mIcons.add(icon); - return this; - } - - public Builder addOverlayPackage(String category, String packageName) { - mPackages.put(category, packageName); - return this; - } - - public Builder setShapePath(String path) { - mPathString = path; - return this; - } - - public Builder setShapePath(Path path) { - mShapePath = path; - return this; - } - - public Builder asDefault() { - mIsDefault = true; - return this; - } - - public Builder setShapePreviewIcons(List<ShapeAppIcon> appIcons) { - mAppIcons.clear(); - mAppIcons.addAll(appIcons); - return this; - } - - public Builder setBottomSheetCornerRadius(@Dimension int radius) { - mCornerRadius = radius; - return this; - } - } -} diff --git a/src/com/android/customization/model/theme/ThemeBundleProvider.java b/src/com/android/customization/model/theme/ThemeBundleProvider.java deleted file mode 100644 index 34342b31..00000000 --- a/src/com/android/customization/model/theme/ThemeBundleProvider.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2019 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.customization.model.theme; - -import androidx.annotation.Nullable; - -import com.android.customization.model.CustomizationManager.OptionsFetchedListener; -import com.android.customization.model.theme.custom.CustomTheme; - -import org.json.JSONException; - -/** - * Interface for a class that can retrieve Themes from the system. - */ -public interface ThemeBundleProvider { - - /** - * Returns whether themes are available in the current setup. - */ - boolean isAvailable(); - - /** - * Retrieve the available themes. - * @param callback called when the themes have been retrieved (or immediately if cached) - * @param reload whether to reload themes if they're cached. - */ - void fetch(OptionsFetchedListener<ThemeBundle> callback, boolean reload); - - void storeCustomTheme(CustomTheme theme); - - void removeCustomTheme(CustomTheme theme); - - @Nullable ThemeBundle.Builder parseThemeBundle(String serializedTheme) throws JSONException; - - @Nullable CustomTheme.Builder parseCustomTheme(String serializedTheme) throws JSONException; - - ThemeBundle findEquivalent(ThemeBundle other); -} diff --git a/src/com/android/customization/model/theme/ThemeBundledWallpaperInfo.java b/src/com/android/customization/model/theme/ThemeBundledWallpaperInfo.java deleted file mode 100644 index 4f0cd6c7..00000000 --- a/src/com/android/customization/model/theme/ThemeBundledWallpaperInfo.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2019 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.customization.model.theme; - -import android.app.Activity; -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.os.Parcel; -import android.util.Log; - -import androidx.annotation.DrawableRes; -import androidx.annotation.StringRes; - -import com.android.wallpaper.asset.Asset; -import com.android.wallpaper.asset.ResourceAsset; -import com.android.wallpaper.model.InlinePreviewIntentFactory; -import com.android.wallpaper.model.WallpaperInfo; - -import java.util.ArrayList; -import java.util.List; - -/** - * Represents a wallpaper coming from the resources of the theme bundle container APK. - */ -public class ThemeBundledWallpaperInfo extends WallpaperInfo { - public static final Creator<ThemeBundledWallpaperInfo> CREATOR = - new Creator<ThemeBundledWallpaperInfo>() { - @Override - public ThemeBundledWallpaperInfo createFromParcel(Parcel in) { - return new ThemeBundledWallpaperInfo(in); - } - - @Override - public ThemeBundledWallpaperInfo[] newArray(int size) { - return new ThemeBundledWallpaperInfo[size]; - } - }; - - private static final String TAG = "ThemeBundledWallpaperInfo"; - - private final String mPackageName; - private final String mResName; - private final String mCollectionId; - @DrawableRes private final int mDrawableResId; - @StringRes private final int mTitleResId; - @StringRes private final int mAttributionResId; - @StringRes private final int mActionUrlResId; - private List<String> mAttributions; - private String mActionUrl; - private Resources mResources; - private Asset mAsset; - - /** - * Constructs a new theme-bundled static wallpaper model object. - * - * @param drawableResId Resource ID of the raw wallpaper image. - * @param resName The unique name of the wallpaper resource, e.g. "z_wp001". - * @param themeName Unique name of the collection this wallpaper belongs in; used for logging. - * @param titleResId Resource ID of the string for the title attribution. - * @param attributionResId Resource ID of the string for the first subtitle attribution. - */ - public ThemeBundledWallpaperInfo(String packageName, String resName, String themeName, - int drawableResId, int titleResId, int attributionResId, int actionUrlResId) { - mPackageName = packageName; - mResName = resName; - mCollectionId = themeName; - mDrawableResId = drawableResId; - mTitleResId = titleResId; - mAttributionResId = attributionResId; - mActionUrlResId = actionUrlResId; - } - - private ThemeBundledWallpaperInfo(Parcel in) { - super(in); - mPackageName = in.readString(); - mResName = in.readString(); - mCollectionId = in.readString(); - mDrawableResId = in.readInt(); - mTitleResId = in.readInt(); - mAttributionResId = in.readInt(); - mActionUrlResId = in.readInt(); - } - - @Override - public List<String> getAttributions(Context context) { - if (mAttributions == null) { - Resources res = getPackageResources(context); - mAttributions = new ArrayList<>(); - if (mTitleResId != 0) { - mAttributions.add(res.getString(mTitleResId)); - } - if (mAttributionResId != 0) { - mAttributions.add(res.getString(mAttributionResId)); - } - } - - return mAttributions; - } - - @Override - public String getActionUrl(Context context) { - if (mActionUrl == null && mActionUrlResId != 0) { - mActionUrl = getPackageResources(context).getString(mActionUrlResId); - } - return mActionUrl; - } - - @Override - public Asset getAsset(Context context) { - if (mAsset == null) { - Resources res = getPackageResources(context); - mAsset = new ResourceAsset(res, mDrawableResId); - } - - return mAsset; - } - - @Override - public Asset getThumbAsset(Context context) { - return getAsset(context); - } - - @Override - public void showPreview(Activity srcActivity, InlinePreviewIntentFactory factory, - int requestCode, boolean isAssetIdPresent) { - try { - srcActivity.startActivityForResult(factory.newIntent(srcActivity, this, - isAssetIdPresent), requestCode); - } catch (ActivityNotFoundException |SecurityException e) { - Log.e(TAG, "App isn't installed or ThemePicker doesn't have permission to launch", e); - } - } - - @Override - public String getCollectionId(Context unused) { - return mCollectionId; - } - - @Override - public String getWallpaperId() { - return mResName; - } - - public String getResName() { - return mResName; - } - - /** - * Returns the {@link Resources} instance for the theme bundles stub APK. - */ - private Resources getPackageResources(Context context) { - if (mResources != null) { - return mResources; - } - - try { - mResources = context.getPackageManager().getResourcesForApplication(mPackageName); - } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, "Could not get app resources for " + mPackageName); - } - return mResources; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeString(mPackageName); - dest.writeString(mResName); - dest.writeString(mCollectionId); - dest.writeInt(mDrawableResId); - dest.writeInt(mTitleResId); - dest.writeInt(mAttributionResId); - dest.writeInt(mActionUrlResId); - } -} diff --git a/src/com/android/customization/model/theme/ThemeManager.java b/src/com/android/customization/model/theme/ThemeManager.java deleted file mode 100644 index 85241c13..00000000 --- a/src/com/android/customization/model/theme/ThemeManager.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2019 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.customization.model.theme; - -import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_COLOR; -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.OVERLAY_CATEGORY_ICON_THEMEPICKER; -import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_SHAPE; - -import android.provider.Settings; -import android.text.TextUtils; - -import androidx.annotation.Nullable; -import androidx.fragment.app.FragmentActivity; - -import com.android.customization.model.CustomizationManager; -import com.android.customization.model.ResourceConstants; -import com.android.customization.model.theme.custom.CustomTheme; -import com.android.customization.module.ThemesUserEventLogger; - -import org.json.JSONObject; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -public class ThemeManager implements CustomizationManager<ThemeBundle> { - - public static final Set<String> THEME_CATEGORIES = new HashSet<>(); - static { - THEME_CATEGORIES.add(OVERLAY_CATEGORY_COLOR); - THEME_CATEGORIES.add(OVERLAY_CATEGORY_FONT); - THEME_CATEGORIES.add(OVERLAY_CATEGORY_SHAPE); - THEME_CATEGORIES.add(OVERLAY_CATEGORY_ICON_ANDROID); - THEME_CATEGORIES.add(OVERLAY_CATEGORY_ICON_SETTINGS); - THEME_CATEGORIES.add(OVERLAY_CATEGORY_ICON_SYSUI); - THEME_CATEGORIES.add(OVERLAY_CATEGORY_ICON_LAUNCHER); - THEME_CATEGORIES.add(OVERLAY_CATEGORY_ICON_THEMEPICKER); - } - - private final ThemeBundleProvider mProvider; - private final OverlayManagerCompat mOverlayManagerCompat; - - protected final FragmentActivity mActivity; - private final ThemesUserEventLogger mEventLogger; - - private Map<String, String> mCurrentOverlays; - - public ThemeManager(ThemeBundleProvider provider, FragmentActivity activity, - OverlayManagerCompat overlayManagerCompat, - ThemesUserEventLogger logger) { - mProvider = provider; - mActivity = activity; - mOverlayManagerCompat = overlayManagerCompat; - mEventLogger = logger; - } - - @Override - public boolean isAvailable() { - return mOverlayManagerCompat.isAvailable() && mProvider.isAvailable(); - } - - @Override - public void apply(ThemeBundle theme, Callback callback) { - applyOverlays(theme, callback); - } - - private void applyOverlays(ThemeBundle theme, Callback callback) { - boolean allApplied = Settings.Secure.putString(mActivity.getContentResolver(), - ResourceConstants.THEME_SETTING, theme.getSerializedPackagesWithTimestamp()); - if (theme instanceof CustomTheme) { - storeCustomTheme((CustomTheme) theme); - } - mCurrentOverlays = null; - if (allApplied) { - mEventLogger.logThemeApplied(theme, theme instanceof CustomTheme); - callback.onSuccess(); - } else { - callback.onError(null); - } - } - - private void storeCustomTheme(CustomTheme theme) { - mProvider.storeCustomTheme(theme); - } - - @Override - public void fetchOptions(OptionsFetchedListener<ThemeBundle> callback, boolean reload) { - mProvider.fetch(callback, reload); - } - - public Map<String, String> getCurrentOverlays() { - if (mCurrentOverlays == null) { - mCurrentOverlays = mOverlayManagerCompat.getEnabledOverlaysForTargets( - ResourceConstants.getPackagesToOverlay(mActivity)); - mCurrentOverlays.entrySet().removeIf( - categoryAndPackage -> !THEME_CATEGORIES.contains(categoryAndPackage.getKey())); - } - return mCurrentOverlays; - } - - public String getStoredOverlays() { - return Settings.Secure.getString(mActivity.getContentResolver(), - ResourceConstants.THEME_SETTING); - } - - public void removeCustomTheme(CustomTheme theme) { - mProvider.removeCustomTheme(theme); - } - - /** - * @return an existing ThemeBundle that matches the same packages as the given one, if one - * exists, or {@code null} otherwise. - */ - @Nullable - public ThemeBundle findThemeByPackages(ThemeBundle other) { - return mProvider.findEquivalent(other); - } - - /** - * Store empty theme if no theme has been set yet. This will prevent Settings from showing the - * suggestion to select a theme - */ - public void storeEmptyTheme() { - String themeSetting = Settings.Secure.getString(mActivity.getContentResolver(), - ResourceConstants.THEME_SETTING); - if (TextUtils.isEmpty(themeSetting)) { - Settings.Secure.putString(mActivity.getContentResolver(), - ResourceConstants.THEME_SETTING, new JSONObject().toString()); - } - } -} diff --git a/src/com/android/customization/model/theme/custom/ColorOptionsProvider.java b/src/com/android/customization/model/theme/custom/ColorOptionsProvider.java deleted file mode 100644 index f3b950b5..00000000 --- a/src/com/android/customization/model/theme/custom/ColorOptionsProvider.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2019 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.customization.model.theme.custom; - -import static com.android.customization.model.ResourceConstants.ACCENT_COLOR_DARK_NAME; -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.ICONS_FOR_PREVIEW; -import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ANDROID_THEME; -import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_COLOR; -import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ICON_ANDROID; -import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_SHAPE; -import static com.android.customization.model.ResourceConstants.PATH_SIZE; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.ShapeDrawable; -import android.graphics.drawable.shapes.PathShape; -import android.os.UserHandle; -import android.text.TextUtils; -import android.util.Log; - -import androidx.core.graphics.PathParser; - -import com.android.customization.model.ResourceConstants; -import com.android.customization.model.theme.OverlayManagerCompat; -import com.android.customization.model.theme.custom.ThemeComponentOption.ColorOption; -import com.android.wallpaper.R; - -import java.util.ArrayList; -import java.util.List; - -/** - * Implementation of {@link ThemeComponentOptionProvider} that reads {@link ColorOption}s from - * icon overlays. - */ -public class ColorOptionsProvider extends ThemeComponentOptionProvider<ColorOption> { - - private static final String TAG = "ColorOptionsProvider"; - private final CustomThemeManager mCustomThemeManager; - private final String mDefaultThemePackage; - - public ColorOptionsProvider(Context context, OverlayManagerCompat manager, - CustomThemeManager customThemeManager) { - super(context, manager, OVERLAY_CATEGORY_COLOR); - mCustomThemeManager = customThemeManager; - // System color is set with a static overlay for android.theme category, so let's try to - // find that first, and if that's not present, we'll default to System resources. - // (see #addDefault()) - List<String> themePackages = manager.getOverlayPackagesForCategory( - OVERLAY_CATEGORY_ANDROID_THEME, UserHandle.myUserId(), ANDROID_PACKAGE); - mDefaultThemePackage = themePackages.isEmpty() ? null : themePackages.get(0); - } - - @Override - protected void loadOptions() { - List<Drawable> previewIcons = new ArrayList<>(); - String iconPackage = - mCustomThemeManager.getOverlayPackages().get(OVERLAY_CATEGORY_ICON_ANDROID); - if (TextUtils.isEmpty(iconPackage)) { - iconPackage = ANDROID_PACKAGE; - } - for (String iconName : ICONS_FOR_PREVIEW) { - try { - previewIcons.add(loadIconPreviewDrawable(iconName, iconPackage)); - } catch (NameNotFoundException | NotFoundException e) { - Log.w(TAG, String.format("Couldn't load icon in %s for color preview, will skip it", - iconPackage), e); - } - } - String shapePackage = mCustomThemeManager.getOverlayPackages().get(OVERLAY_CATEGORY_SHAPE); - if (TextUtils.isEmpty(shapePackage)) { - shapePackage = ANDROID_PACKAGE; - } - Drawable shape = loadShape(shapePackage); - addDefault(previewIcons, shape); - for (String overlayPackage : mOverlayPackages) { - try { - Resources overlayRes = getOverlayResources(overlayPackage); - int lightColor = overlayRes.getColor( - overlayRes.getIdentifier(ACCENT_COLOR_LIGHT_NAME, "color", overlayPackage), - null); - int darkColor = overlayRes.getColor( - overlayRes.getIdentifier(ACCENT_COLOR_DARK_NAME, "color", overlayPackage), - null); - PackageManager pm = mContext.getPackageManager(); - String label = pm.getApplicationInfo(overlayPackage, 0).loadLabel(pm).toString(); - ColorOption option = new ColorOption(overlayPackage, label, lightColor, darkColor); - option.setPreviewIcons(previewIcons); - option.setShapeDrawable(shape); - mOptions.add(option); - } catch (NameNotFoundException | NotFoundException e) { - Log.w(TAG, String.format("Couldn't load color overlay %s, will skip it", - overlayPackage), e); - } - } - } - - private void addDefault(List<Drawable> previewIcons, Drawable shape) { - int lightColor, darkColor; - Resources system = Resources.getSystem(); - try { - Resources r = getOverlayResources(mDefaultThemePackage); - lightColor = r.getColor( - r.getIdentifier(ACCENT_COLOR_LIGHT_NAME, "color", mDefaultThemePackage), - null); - darkColor = r.getColor( - r.getIdentifier(ACCENT_COLOR_DARK_NAME, "color", mDefaultThemePackage), - null); - } catch (NotFoundException | NameNotFoundException e) { - Log.d(TAG, "Didn't find default color, will use system option", e); - - lightColor = system.getColor( - system.getIdentifier(ACCENT_COLOR_LIGHT_NAME, "color", ANDROID_PACKAGE), null); - - darkColor = system.getColor( - system.getIdentifier(ACCENT_COLOR_DARK_NAME, "color", ANDROID_PACKAGE), null); - } - ColorOption option = new ColorOption(null, - mContext.getString(R.string.default_theme_title), lightColor, darkColor); - option.setPreviewIcons(previewIcons); - option.setShapeDrawable(shape); - mOptions.add(option); - } - - private Drawable loadIconPreviewDrawable(String drawableName, String packageName) - throws NameNotFoundException, NotFoundException { - - Resources overlayRes = getOverlayResources(packageName); - return overlayRes.getDrawable( - overlayRes.getIdentifier(drawableName, "drawable", packageName), null); - } - - private Drawable loadShape(String packageName) { - String path = null; - try { - Resources r = getOverlayResources(packageName); - - path = ResourceConstants.getIconMask(r, packageName); - } catch (NameNotFoundException e) { - Log.d(TAG, String.format("Couldn't load shape icon for %s, skipping.", packageName), e); - } - ShapeDrawable shapeDrawable = null; - if (!TextUtils.isEmpty(path)) { - PathShape shape = new PathShape(PathParser.createPathFromPathData(path), - PATH_SIZE, PATH_SIZE); - shapeDrawable = new ShapeDrawable(shape); - shapeDrawable.setIntrinsicHeight((int) PATH_SIZE); - shapeDrawable.setIntrinsicWidth((int) PATH_SIZE); - } - return shapeDrawable; - } - -} diff --git a/src/com/android/customization/model/theme/custom/CustomTheme.java b/src/com/android/customization/model/theme/custom/CustomTheme.java deleted file mode 100644 index a1ee1066..00000000 --- a/src/com/android/customization/model/theme/custom/CustomTheme.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2019 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.customization.model.theme.custom; - -import android.content.Context; -import android.view.View; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.customization.model.CustomizationManager; -import com.android.customization.model.theme.ThemeBundle; -import com.android.wallpaper.R; - -import java.util.Map; -import java.util.UUID; - -public class CustomTheme extends ThemeBundle { - - public static String newId() { - return UUID.randomUUID().toString(); - } - - /** - * Used to uniquely identify a custom theme since names can change. - */ - private final String mId; - - private CustomTheme(@NonNull String id, String title, Map<String, String> overlayPackages, - @Nullable PreviewInfo previewInfo) { - super(title, overlayPackages, false, previewInfo); - mId = id; - } - - public String getId() { - return mId; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof CustomTheme)) { - return false; - } - CustomTheme other = (CustomTheme) obj; - return mId.equals(other.mId); - } - - @Override - public int hashCode() { - return mId.hashCode(); - } - - @Override - public void bindThumbnailTile(View view) { - if (isDefined()) { - super.bindThumbnailTile(view); - } - } - - @Override - public int getLayoutResId() { - return isDefined() ? R.layout.theme_option : R.layout.custom_theme_option; - } - - @Override - public boolean isActive(CustomizationManager<ThemeBundle> manager) { - return isDefined() && super.isActive(manager); - } - - @Override - public boolean isEquivalent(ThemeBundle other) { - return isDefined() && super.isEquivalent(other); - } - - public boolean isDefined() { - return getPreviewInfo() != null; - } - - public static class Builder extends ThemeBundle.Builder { - private String mId; - - @Override - public CustomTheme build(Context context) { - return new CustomTheme(mId, mTitle, mPackages, - mPackages.isEmpty() ? null : createPreviewInfo(context)); - } - - public Builder setId(String id) { - mId = id; - return this; - } - } -} diff --git a/src/com/android/customization/model/theme/custom/CustomThemeManager.java b/src/com/android/customization/model/theme/custom/CustomThemeManager.java deleted file mode 100644 index 42d73e60..00000000 --- a/src/com/android/customization/model/theme/custom/CustomThemeManager.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2019 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.customization.model.theme.custom; - -import android.content.Context; -import android.os.Bundle; -import android.text.TextUtils; -import android.util.Log; - -import androidx.annotation.Nullable; - -import com.android.customization.model.CustomizationManager; -import com.android.customization.model.theme.ThemeBundle.PreviewInfo; -import com.android.customization.model.theme.ThemeBundleProvider; -import com.android.customization.model.theme.ThemeManager; -import com.android.customization.model.theme.custom.CustomTheme.Builder; - -import org.json.JSONException; - -import java.util.Map; - -public class CustomThemeManager implements CustomizationManager<ThemeComponentOption> { - - private static final String TAG = "CustomThemeManager"; - private static final String KEY_STATE_CURRENT_SELECTION = "CustomThemeManager.currentSelection"; - - private final CustomTheme mOriginalTheme; - private CustomTheme.Builder mBuilder; - - private CustomThemeManager(Map<String, String> overlayPackages, - @Nullable CustomTheme originalTheme) { - mBuilder = new Builder(); - overlayPackages.forEach(mBuilder::addOverlayPackage); - mOriginalTheme = originalTheme; - } - - @Override - public boolean isAvailable() { - return true; - } - - @Override - public void apply(ThemeComponentOption option, @Nullable Callback callback) { - option.buildStep(mBuilder); - if (callback != null) { - callback.onSuccess(); - } - } - - public Map<String, String> getOverlayPackages() { - return mBuilder.getPackages(); - } - - public CustomTheme buildPartialCustomTheme(Context context, String id, String title) { - return ((CustomTheme.Builder)mBuilder.setId(id).setTitle(title)).build(context); - } - - @Override - public void fetchOptions(OptionsFetchedListener<ThemeComponentOption> callback, boolean reload) { - //Unused - } - - public CustomTheme getOriginalTheme() { - return mOriginalTheme; - } - - public PreviewInfo buildCustomThemePreviewInfo(Context context) { - return mBuilder.createPreviewInfo(context); - } - - /** Saves the custom theme selections while system config changes. */ - public void saveCustomTheme(Context context, Bundle savedInstanceState) { - CustomTheme customTheme = - buildPartialCustomTheme(context, /* id= */ null, /* title= */ null); - savedInstanceState.putString(KEY_STATE_CURRENT_SELECTION, - customTheme.getSerializedPackages()); - } - - /** Reads the saved custom theme after system config changed. */ - public void readCustomTheme(ThemeBundleProvider themeBundleProvider, - Bundle savedInstanceState) { - String packages = savedInstanceState.getString(KEY_STATE_CURRENT_SELECTION); - if (!TextUtils.isEmpty(packages)) { - try { - mBuilder = themeBundleProvider.parseCustomTheme(packages); - } catch (JSONException e) { - Log.w(TAG, "Couldn't parse provided custom theme."); - } - } else { - Log.w(TAG, "No custom theme being restored."); - } - } - - public static CustomThemeManager create( - @Nullable CustomTheme customTheme, ThemeManager themeManager) { - if (customTheme != null && customTheme.isDefined()) { - return new CustomThemeManager(customTheme.getPackagesByCategory(), customTheme); - } - // Seed the first custom theme with the currently applied theme. - return new CustomThemeManager(themeManager.getCurrentOverlays(), customTheme); - } - -} diff --git a/src/com/android/customization/model/theme/custom/FontOptionsProvider.java b/src/com/android/customization/model/theme/custom/FontOptionsProvider.java deleted file mode 100644 index 53568c9f..00000000 --- a/src/com/android/customization/model/theme/custom/FontOptionsProvider.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2019 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.customization.model.theme.custom; - -import static com.android.customization.model.ResourceConstants.ANDROID_PACKAGE; -import static com.android.customization.model.ResourceConstants.CONFIG_BODY_FONT_FAMILY; -import static com.android.customization.model.ResourceConstants.CONFIG_HEADLINE_FONT_FAMILY; -import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_FONT; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; -import android.graphics.Typeface; -import android.util.Log; - -import com.android.customization.model.ResourceConstants; -import com.android.customization.model.theme.OverlayManagerCompat; -import com.android.customization.model.theme.custom.ThemeComponentOption.FontOption; -import com.android.wallpaper.R; - -/** - * Implementation of {@link ThemeComponentOptionProvider} that reads {@link FontOption}s from - * font overlays. - */ -public class FontOptionsProvider extends ThemeComponentOptionProvider<FontOption> { - - private static final String TAG = "FontOptionsProvider"; - - public FontOptionsProvider(Context context, OverlayManagerCompat manager) { - super(context, manager, OVERLAY_CATEGORY_FONT); - } - - @Override - protected void loadOptions() { - addDefault(); - for (String overlayPackage : mOverlayPackages) { - try { - Resources overlayRes = getOverlayResources(overlayPackage); - Typeface headlineFont = Typeface.create( - getFontFamily(overlayPackage, overlayRes, CONFIG_HEADLINE_FONT_FAMILY), - Typeface.NORMAL); - Typeface bodyFont = Typeface.create( - getFontFamily(overlayPackage, overlayRes, CONFIG_BODY_FONT_FAMILY), - Typeface.NORMAL); - PackageManager pm = mContext.getPackageManager(); - String label = pm.getApplicationInfo(overlayPackage, 0).loadLabel(pm).toString(); - mOptions.add(new FontOption(overlayPackage, label, headlineFont, bodyFont)); - } catch (NameNotFoundException | NotFoundException e) { - Log.w(TAG, String.format("Couldn't load font overlay %s, will skip it", - overlayPackage), e); - } - } - } - - private void addDefault() { - Resources system = Resources.getSystem(); - Typeface headlineFont = Typeface.create(system.getString(system.getIdentifier( - ResourceConstants.CONFIG_HEADLINE_FONT_FAMILY,"string", ANDROID_PACKAGE)), - Typeface.NORMAL); - Typeface bodyFont = Typeface.create(system.getString(system.getIdentifier( - ResourceConstants.CONFIG_BODY_FONT_FAMILY, - "string", ANDROID_PACKAGE)), - Typeface.NORMAL); - mOptions.add(new FontOption(null, mContext.getString(R.string.default_theme_title), - headlineFont, bodyFont)); - } - - private String getFontFamily(String overlayPackage, Resources overlayRes, String configName) { - return overlayRes.getString(overlayRes.getIdentifier(configName, "string", overlayPackage)); - } -} diff --git a/src/com/android/customization/model/theme/custom/IconOptionsProvider.java b/src/com/android/customization/model/theme/custom/IconOptionsProvider.java deleted file mode 100644 index f7b669b1..00000000 --- a/src/com/android/customization/model/theme/custom/IconOptionsProvider.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2019 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.customization.model.theme.custom; - -import static com.android.customization.model.ResourceConstants.ANDROID_PACKAGE; -import static com.android.customization.model.ResourceConstants.ICONS_FOR_PREVIEW; -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.OVERLAY_CATEGORY_ICON_THEMEPICKER; - -import android.content.Context; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; -import android.graphics.drawable.Drawable; -import android.os.UserHandle; -import android.util.Log; - -import com.android.customization.model.ResourceConstants; -import com.android.customization.model.theme.OverlayManagerCompat; -import com.android.customization.model.theme.custom.ThemeComponentOption.IconOption; -import com.android.wallpaper.R; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Implementation of {@link ThemeComponentOptionProvider} that reads {@link IconOption}s from - * icon overlays. - */ -public class IconOptionsProvider extends ThemeComponentOptionProvider<IconOption> { - - private static final String TAG = "IconOptionsProvider"; - - private final List<String> mSysUiIconsOverlayPackages = new ArrayList<>(); - private final List<String> mSettingsIconsOverlayPackages = new ArrayList<>(); - private final List<String> mLauncherIconsOverlayPackages = new ArrayList<>(); - private final List<String> mThemePickerIconsOverlayPackages = new ArrayList<>(); - - public IconOptionsProvider(Context context, OverlayManagerCompat manager) { - super(context, manager, OVERLAY_CATEGORY_ICON_ANDROID); - String[] targetPackages = ResourceConstants.getPackagesToOverlay(context); - mSysUiIconsOverlayPackages.addAll(manager.getOverlayPackagesForCategory( - OVERLAY_CATEGORY_ICON_SYSUI, UserHandle.myUserId(), targetPackages)); - mSettingsIconsOverlayPackages.addAll(manager.getOverlayPackagesForCategory( - OVERLAY_CATEGORY_ICON_SETTINGS, UserHandle.myUserId(), targetPackages)); - mLauncherIconsOverlayPackages.addAll(manager.getOverlayPackagesForCategory( - OVERLAY_CATEGORY_ICON_LAUNCHER, UserHandle.myUserId(), targetPackages)); - mThemePickerIconsOverlayPackages.addAll(manager.getOverlayPackagesForCategory( - OVERLAY_CATEGORY_ICON_THEMEPICKER, UserHandle.myUserId(), targetPackages)); - } - - @Override - protected void loadOptions() { - addDefault(); - - Map<String, IconOption> optionsByPrefix = new HashMap<>(); - for (String overlayPackage : mOverlayPackages) { - IconOption option = addOrUpdateOption(optionsByPrefix, overlayPackage, - OVERLAY_CATEGORY_ICON_ANDROID); - try{ - for (String iconName : ICONS_FOR_PREVIEW) { - option.addIcon(loadIconPreviewDrawable(iconName, overlayPackage)); - } - } catch (NotFoundException | NameNotFoundException e) { - Log.w(TAG, String.format("Couldn't load icon overlay details for %s, will skip it", - overlayPackage), e); - } - } - - for (String overlayPackage : mSysUiIconsOverlayPackages) { - addOrUpdateOption(optionsByPrefix, overlayPackage, OVERLAY_CATEGORY_ICON_SYSUI); - } - - for (String overlayPackage : mSettingsIconsOverlayPackages) { - addOrUpdateOption(optionsByPrefix, overlayPackage, OVERLAY_CATEGORY_ICON_SETTINGS); - } - - for (String overlayPackage : mLauncherIconsOverlayPackages) { - addOrUpdateOption(optionsByPrefix, overlayPackage, OVERLAY_CATEGORY_ICON_LAUNCHER); - } - - for (String overlayPackage : mThemePickerIconsOverlayPackages) { - addOrUpdateOption(optionsByPrefix, overlayPackage, OVERLAY_CATEGORY_ICON_THEMEPICKER); - } - - for (IconOption option : optionsByPrefix.values()) { - if (option.isValid(mContext)) { - mOptions.add(option); - option.setLabel(mContext.getString(R.string.icon_component_label, mOptions.size())); - } - } - } - - private IconOption addOrUpdateOption(Map<String, IconOption> optionsByPrefix, - String overlayPackage, String category) { - String prefix = overlayPackage.substring(0, overlayPackage.lastIndexOf(".")); - IconOption option; - if (!optionsByPrefix.containsKey(prefix)) { - option = new IconOption(); - optionsByPrefix.put(prefix, option); - } else { - option = optionsByPrefix.get(prefix); - } - option.addOverlayPackage(category, overlayPackage); - return option; - } - - private Drawable loadIconPreviewDrawable(String drawableName, String packageName) - throws NameNotFoundException, NotFoundException { - final Resources resources = ANDROID_PACKAGE.equals(packageName) - ? Resources.getSystem() - : mContext.getPackageManager().getResourcesForApplication(packageName); - return resources.getDrawable( - resources.getIdentifier(drawableName, "drawable", packageName), null); - } - - private void addDefault() { - IconOption option = new IconOption(); - option.setLabel(mContext.getString(R.string.default_theme_title)); - try { - for (String iconName : ICONS_FOR_PREVIEW) { - option.addIcon(loadIconPreviewDrawable(iconName, ANDROID_PACKAGE)); - } - } catch (NameNotFoundException | NotFoundException e) { - Log.w(TAG, "Didn't find SystemUi package icons, will skip option", e); - } - option.addOverlayPackage(OVERLAY_CATEGORY_ICON_ANDROID, null); - option.addOverlayPackage(OVERLAY_CATEGORY_ICON_SYSUI, null); - option.addOverlayPackage(OVERLAY_CATEGORY_ICON_SETTINGS, null); - option.addOverlayPackage(OVERLAY_CATEGORY_ICON_LAUNCHER, null); - option.addOverlayPackage(OVERLAY_CATEGORY_ICON_THEMEPICKER, null); - mOptions.add(option); - } - -} diff --git a/src/com/android/customization/model/theme/custom/ShapeOptionsProvider.java b/src/com/android/customization/model/theme/custom/ShapeOptionsProvider.java deleted file mode 100644 index f93b8920..00000000 --- a/src/com/android/customization/model/theme/custom/ShapeOptionsProvider.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2019 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.customization.model.theme.custom; - -import static com.android.customization.model.ResourceConstants.ANDROID_PACKAGE; -import static com.android.customization.model.ResourceConstants.CONFIG_CORNERRADIUS; -import static com.android.customization.model.ResourceConstants.CONFIG_ICON_MASK; -import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_SHAPE; -import static com.android.customization.model.ResourceConstants.PATH_SIZE; - -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; -import android.graphics.Path; -import android.graphics.drawable.AdaptiveIconDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.ShapeDrawable; -import android.graphics.drawable.shapes.PathShape; -import android.text.TextUtils; -import android.util.Log; - -import androidx.annotation.Dimension; -import androidx.core.graphics.PathParser; - -import com.android.customization.model.ResourceConstants; -import com.android.customization.model.theme.OverlayManagerCompat; -import com.android.customization.model.theme.ThemeBundle.PreviewInfo.ShapeAppIcon; -import com.android.customization.model.theme.custom.ThemeComponentOption.ShapeOption; -import com.android.customization.widget.DynamicAdaptiveIconDrawable; -import com.android.wallpaper.R; - -import java.util.ArrayList; -import java.util.List; - -/** - * Implementation of {@link ThemeComponentOptionProvider} that reads {@link ShapeOption}s from - * icon overlays. - */ -public class ShapeOptionsProvider extends ThemeComponentOptionProvider<ShapeOption> { - - private static final String TAG = "ShapeOptionsProvider"; - private final String[] mShapePreviewIconPackages; - private int mThumbSize; - - public ShapeOptionsProvider(Context context, OverlayManagerCompat manager) { - super(context, manager, OVERLAY_CATEGORY_SHAPE); - mShapePreviewIconPackages = context.getResources().getStringArray( - R.array.icon_shape_preview_packages); - mThumbSize = mContext.getResources().getDimensionPixelSize( - R.dimen.component_shape_thumb_size); - } - - @Override - protected void loadOptions() { - addDefault(); - for (String overlayPackage : mOverlayPackages) { - try { - Path path = loadPath(mContext.getPackageManager() - .getResourcesForApplication(overlayPackage), overlayPackage); - PackageManager pm = mContext.getPackageManager(); - String label = pm.getApplicationInfo(overlayPackage, 0).loadLabel(pm).toString(); - mOptions.add(new ShapeOption(overlayPackage, label, path, - loadCornerRadius(overlayPackage), createShapeDrawable(path), - getShapedAppIcons(path))); - } catch (NameNotFoundException | NotFoundException e) { - Log.w(TAG, String.format("Couldn't load shape overlay %s, will skip it", - overlayPackage), e); - } - } - } - - private void addDefault() { - Resources system = Resources.getSystem(); - Path path = loadPath(system, ANDROID_PACKAGE); - mOptions.add(new ShapeOption(null, mContext.getString(R.string.default_theme_title), path, - system.getDimensionPixelOffset( - system.getIdentifier(ResourceConstants.CONFIG_CORNERRADIUS, - "dimen", ResourceConstants.ANDROID_PACKAGE)), - createShapeDrawable(path), getShapedAppIcons(path))); - } - - private ShapeDrawable createShapeDrawable(Path path) { - PathShape shape = new PathShape(path, PATH_SIZE, PATH_SIZE); - ShapeDrawable shapeDrawable = new ShapeDrawable(shape); - shapeDrawable.setIntrinsicHeight(mThumbSize); - shapeDrawable.setIntrinsicWidth(mThumbSize); - return shapeDrawable; - } - - private List<ShapeAppIcon> getShapedAppIcons(Path path) { - List<ShapeAppIcon> shapedAppIcons = new ArrayList<>(); - for (String packageName : mShapePreviewIconPackages) { - Drawable icon = null; - CharSequence name = null; - try { - Drawable appIcon = mContext.getPackageManager().getApplicationIcon(packageName); - if (appIcon instanceof AdaptiveIconDrawable) { - AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) appIcon; - icon = new DynamicAdaptiveIconDrawable(adaptiveIcon.getBackground(), - adaptiveIcon.getForeground(), path); - - ApplicationInfo appInfo = mContext.getPackageManager() - .getApplicationInfo(packageName, /* flag= */ 0); - name = mContext.getPackageManager().getApplicationLabel(appInfo); - } - } catch (NameNotFoundException e) { - Log.d(TAG, "Couldn't find app " + packageName - + ", won't use it for icon shape preview"); - } finally { - if (icon != null && !TextUtils.isEmpty(name)) { - shapedAppIcons.add(new ShapeAppIcon(icon, name)); - } - } - } - return shapedAppIcons; - } - - private Path loadPath(Resources overlayRes, String packageName) { - String shape = overlayRes.getString(overlayRes.getIdentifier(CONFIG_ICON_MASK, "string", - packageName)); - - if (!TextUtils.isEmpty(shape)) { - return PathParser.createPathFromPathData(shape); - } - return null; - } - - @Dimension - private int loadCornerRadius(String packageName) - throws NameNotFoundException, NotFoundException { - - Resources overlayRes = - mContext.getPackageManager().getResourcesForApplication( - packageName); - return overlayRes.getDimensionPixelOffset(overlayRes.getIdentifier( - CONFIG_CORNERRADIUS, "dimen", packageName)); - } -} diff --git a/src/com/android/customization/model/theme/custom/ThemeComponentOption.java b/src/com/android/customization/model/theme/custom/ThemeComponentOption.java deleted file mode 100644 index 78be0fc0..00000000 --- a/src/com/android/customization/model/theme/custom/ThemeComponentOption.java +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Copyright (C) 2019 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.customization.model.theme.custom; - -import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_COLOR; -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.OVERLAY_CATEGORY_ICON_THEMEPICKER; -import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_SHAPE; -import static com.android.customization.model.ResourceConstants.getLauncherPackage; - -import android.content.Context; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.ColorStateList; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; -import android.content.res.Resources.Theme; -import android.content.res.TypedArray; -import android.graphics.Path; -import android.graphics.Typeface; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.graphics.drawable.ShapeDrawable; -import android.graphics.drawable.StateListDrawable; -import android.text.TextUtils; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CompoundButton; -import android.widget.ImageView; -import android.widget.SeekBar; -import android.widget.Switch; -import android.widget.TextView; - -import androidx.annotation.ColorInt; -import androidx.annotation.Dimension; -import androidx.annotation.DrawableRes; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; -import androidx.core.graphics.ColorUtils; - -import com.android.customization.model.CustomizationManager; -import com.android.customization.model.CustomizationOption; -import com.android.customization.model.ResourceConstants; -import com.android.customization.model.theme.ThemeBundle.PreviewInfo.ShapeAppIcon; -import com.android.customization.model.theme.custom.CustomTheme.Builder; -import com.android.wallpaper.R; -import com.android.wallpaper.util.ResourceUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * Represents an option of a component of a custom Theme (for example, a possible color, or font, - * shape, etc). - * Extending classes correspond to each component's options and provide the structure to bind - * preview and thumbnails. - * // TODO (santie): refactor the logic to bind preview cards to reuse between ThemeFragment and - * // here - */ -public abstract class ThemeComponentOption implements CustomizationOption<ThemeComponentOption> { - - protected final Map<String, String> mOverlayPackageNames = new HashMap<>(); - - protected void addOverlayPackage(String category, String packageName) { - mOverlayPackageNames.put(category, packageName); - } - - public Map<String, String> getOverlayPackages() { - return mOverlayPackageNames; - } - - @Override - public String getTitle() { - return null; - } - - public abstract void bindPreview(ViewGroup container); - - public Builder buildStep(Builder builder) { - getOverlayPackages().forEach(builder::addOverlayPackage); - return builder; - } - - public static class FontOption extends ThemeComponentOption { - - private final String mLabel; - private final Typeface mHeadlineFont; - private final Typeface mBodyFont; - - public FontOption(String packageName, String label, Typeface headlineFont, - Typeface bodyFont) { - addOverlayPackage(OVERLAY_CATEGORY_FONT, packageName); - mLabel = label; - mHeadlineFont = headlineFont; - mBodyFont = bodyFont; - } - - @Override - public String getTitle() { - return null; - } - - @Override - public void bindThumbnailTile(View view) { - ((TextView) view.findViewById(R.id.thumbnail_text)).setTypeface( - mHeadlineFont); - view.setContentDescription(mLabel); - } - - @Override - public boolean isActive(CustomizationManager<ThemeComponentOption> manager) { - CustomThemeManager customThemeManager = (CustomThemeManager) manager; - return Objects.equals(getOverlayPackages().get(OVERLAY_CATEGORY_FONT), - customThemeManager.getOverlayPackages().get(OVERLAY_CATEGORY_FONT)); - } - - @Override - public int getLayoutResId() { - return R.layout.theme_font_option; - } - - @Override - public void bindPreview(ViewGroup container) { - container.setContentDescription( - container.getContext().getString(R.string.font_preview_content_description)); - - bindPreviewHeader(container, R.string.preview_name_font, R.drawable.ic_font, null); - - ViewGroup cardBody = container.findViewById(R.id.theme_preview_card_body_container); - if (cardBody.getChildCount() == 0) { - LayoutInflater.from(container.getContext()).inflate( - R.layout.preview_card_font_content, - cardBody, true); - } - TextView title = container.findViewById(R.id.font_card_title); - title.setTypeface(mHeadlineFont); - TextView bodyText = container.findViewById(R.id.font_card_body); - bodyText.setTypeface(mBodyFont); - container.findViewById(R.id.font_card_divider).setBackgroundColor( - title.getCurrentTextColor()); - } - - @Override - public Builder buildStep(Builder builder) { - builder.setHeadlineFontFamily(mHeadlineFont).setBodyFontFamily(mBodyFont); - return super.buildStep(builder); - } - } - - void bindPreviewHeader(ViewGroup container, @StringRes int headerTextResId, - @DrawableRes int headerIcon, String drawableName) { - TextView header = container.findViewById(R.id.theme_preview_card_header); - header.setText(headerTextResId); - - Context context = container.getContext(); - Drawable icon; - if (!TextUtils.isEmpty(drawableName)) { - try { - Resources resources = context.getPackageManager() - .getResourcesForApplication(getLauncherPackage(context)); - icon = resources.getDrawable(resources.getIdentifier( - drawableName, "drawable", getLauncherPackage(context)), null); - } catch (NameNotFoundException | NotFoundException e) { - icon = context.getResources().getDrawable(headerIcon, context.getTheme()); - } - } else { - icon = context.getResources().getDrawable(headerIcon, context.getTheme()); - } - int size = context.getResources().getDimensionPixelSize(R.dimen.card_header_icon_size); - icon.setBounds(0, 0, size, size); - - header.setCompoundDrawables(null, icon, null, null); - header.setCompoundDrawableTintList(ColorStateList.valueOf( - header.getCurrentTextColor())); - } - - public static class IconOption extends ThemeComponentOption { - - public static final int THUMBNAIL_ICON_POSITION = 0; - private static int[] mIconIds = { - R.id.preview_icon_0, R.id.preview_icon_1, R.id.preview_icon_2, R.id.preview_icon_3, - R.id.preview_icon_4, R.id.preview_icon_5 - }; - - private List<Drawable> mIcons = new ArrayList<>(); - private String mLabel; - - @Override - public void bindThumbnailTile(View view) { - Resources res = view.getContext().getResources(); - Drawable icon = mIcons.get(THUMBNAIL_ICON_POSITION) - .getConstantState().newDrawable().mutate(); - icon.setTint(ResourceUtils.getColorAttr( - view.getContext(), android.R.attr.textColorSecondary)); - ((ImageView) view.findViewById(R.id.option_icon)).setImageDrawable( - icon); - view.setContentDescription(mLabel); - } - - @Override - public boolean isActive(CustomizationManager<ThemeComponentOption> manager) { - CustomThemeManager customThemeManager = (CustomThemeManager) manager; - Map<String, String> themePackages = customThemeManager.getOverlayPackages(); - if (getOverlayPackages().isEmpty()) { - return themePackages.get(OVERLAY_CATEGORY_ICON_SYSUI) == null && - themePackages.get(OVERLAY_CATEGORY_ICON_SETTINGS) == null && - themePackages.get(OVERLAY_CATEGORY_ICON_ANDROID) == null && - themePackages.get(OVERLAY_CATEGORY_ICON_LAUNCHER) == null && - themePackages.get(OVERLAY_CATEGORY_ICON_THEMEPICKER) == null; - } - for (Map.Entry<String, String> overlayEntry : getOverlayPackages().entrySet()) { - if(!Objects.equals(overlayEntry.getValue(), - themePackages.get(overlayEntry.getKey()))) { - return false; - } - } - return true; - } - - @Override - public int getLayoutResId() { - return R.layout.theme_icon_option; - } - - @Override - public void bindPreview(ViewGroup container) { - container.setContentDescription( - container.getContext().getString(R.string.icon_preview_content_description)); - - bindPreviewHeader(container, R.string.preview_name_icon, R.drawable.ic_widget, - "ic_widget"); - - ViewGroup cardBody = container.findViewById(R.id.theme_preview_card_body_container); - if (cardBody.getChildCount() == 0) { - LayoutInflater.from(container.getContext()).inflate( - R.layout.preview_card_icon_content, cardBody, true); - } - for (int i = 0; i < mIconIds.length && i < mIcons.size(); i++) { - ((ImageView) container.findViewById(mIconIds[i])).setImageDrawable( - mIcons.get(i)); - } - } - - public void addIcon(Drawable previewIcon) { - mIcons.add(previewIcon); - } - - /** - * @return whether this icon option has overlays and previews for all the required packages - */ - public boolean isValid(Context context) { - return getOverlayPackages().keySet().size() == - ResourceConstants.getPackagesToOverlay(context).length; - } - - public void setLabel(String label) { - mLabel = label; - } - - @Override - public Builder buildStep(Builder builder) { - for (Drawable icon : mIcons) { - builder.addIcon(icon); - } - return super.buildStep(builder); - } - } - - public static class ColorOption extends ThemeComponentOption { - - /** - * Ids of views used to represent quick setting tiles in the color preview screen - */ - private static int[] COLOR_TILE_IDS = { - R.id.preview_color_qs_0_bg, R.id.preview_color_qs_1_bg, R.id.preview_color_qs_2_bg - }; - - /** - * Ids of the views for the foreground of the icon, mapping to the corresponding index of - * the actual icon drawable. - */ - static int[][] COLOR_TILES_ICON_IDS = { - new int[]{ R.id.preview_color_qs_0_icon, 0}, - new int[]{ R.id.preview_color_qs_1_icon, 1}, - new int[] { R.id.preview_color_qs_2_icon, 3} - }; - - /** - * Ids of views used to represent control buttons in the color preview screen - */ - private static int[] COLOR_BUTTON_IDS = { - R.id.preview_check_selected, R.id.preview_radio_selected, - R.id.preview_toggle_selected - }; - - @ColorInt private int mColorAccentLight; - @ColorInt private int mColorAccentDark; - /** - * Icons shown as example of QuickSettings tiles in the color preview screen. - */ - private List<Drawable> mIcons = new ArrayList<>(); - - /** - * Drawable with the currently selected shape to be used as background of the sample - * QuickSetting icons in the color preview screen. - */ - private Drawable mShapeDrawable; - - private String mLabel; - - ColorOption(String packageName, String label, @ColorInt int lightColor, - @ColorInt int darkColor) { - addOverlayPackage(OVERLAY_CATEGORY_COLOR, packageName); - mLabel = label; - mColorAccentLight = lightColor; - mColorAccentDark = darkColor; - } - - @Override - public void bindThumbnailTile(View view) { - @ColorInt int color = resolveColor(view.getResources()); - LayerDrawable selectedOption = (LayerDrawable) view.getResources().getDrawable( - R.drawable.color_chip_hollow, view.getContext().getTheme()); - Drawable unselectedOption = view.getResources().getDrawable( - R.drawable.color_chip_filled, view.getContext().getTheme()); - - selectedOption.findDrawableByLayerId(R.id.center_fill).setTintList( - ColorStateList.valueOf(color)); - unselectedOption.setTintList(ColorStateList.valueOf(color)); - - StateListDrawable stateListDrawable = new StateListDrawable(); - stateListDrawable.addState(new int[] {android.R.attr.state_activated}, selectedOption); - stateListDrawable.addState( - new int[] {-android.R.attr.state_activated}, unselectedOption); - - ((ImageView) view.findViewById(R.id.option_tile)).setImageDrawable(stateListDrawable); - view.setContentDescription(mLabel); - } - - @ColorInt - private int resolveColor(Resources res) { - Configuration configuration = res.getConfiguration(); - return (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK) - == Configuration.UI_MODE_NIGHT_YES ? mColorAccentDark : mColorAccentLight; - } - - @Override - public boolean isActive(CustomizationManager<ThemeComponentOption> manager) { - CustomThemeManager customThemeManager = (CustomThemeManager) manager; - return Objects.equals(getOverlayPackages().get(OVERLAY_CATEGORY_COLOR), - customThemeManager.getOverlayPackages().get(OVERLAY_CATEGORY_COLOR)); - } - - @Override - public int getLayoutResId() { - return R.layout.theme_color_option; - } - - @Override - public void bindPreview(ViewGroup container) { - container.setContentDescription( - container.getContext().getString(R.string.color_preview_content_description)); - - bindPreviewHeader(container, R.string.preview_name_color, R.drawable.ic_colorize_24px, - null); - - ViewGroup cardBody = container.findViewById(R.id.theme_preview_card_body_container); - if (cardBody.getChildCount() == 0) { - LayoutInflater.from(container.getContext()).inflate( - R.layout.preview_card_color_content, cardBody, true); - } - Resources res = container.getResources(); - @ColorInt int accentColor = resolveColor(res); - @ColorInt int controlGreyColor = ResourceUtils.getColorAttr( - container.getContext(), - android.R.attr.textColorTertiary); - ColorStateList tintList = new ColorStateList( - new int[][]{ - new int[]{android.R.attr.state_selected}, - new int[]{android.R.attr.state_checked}, - new int[]{-android.R.attr.state_enabled} - }, - new int[] { - accentColor, - accentColor, - controlGreyColor - } - ); - - for (int i = 0; i < COLOR_BUTTON_IDS.length; i++) { - CompoundButton button = container.findViewById(COLOR_BUTTON_IDS[i]); - button.setButtonTintList(tintList); - } - - Switch enabledSwitch = container.findViewById(R.id.preview_toggle_selected); - enabledSwitch.setThumbTintList(tintList); - enabledSwitch.setTrackTintList(tintList); - - ColorStateList seekbarTintList = ColorStateList.valueOf(accentColor); - SeekBar seekbar = container.findViewById(R.id.preview_seekbar); - seekbar.setThumbTintList(seekbarTintList); - seekbar.setProgressTintList(seekbarTintList); - seekbar.setProgressBackgroundTintList(seekbarTintList); - // Disable seekbar - seekbar.setOnTouchListener((view, motionEvent) -> true); - - int iconFgColor = ResourceUtils.getColorAttr(container.getContext(), - android.R.attr.colorBackground); - if (!mIcons.isEmpty() && mShapeDrawable != null) { - for (int i = 0; i < COLOR_TILE_IDS.length; i++) { - Drawable icon = mIcons.get(COLOR_TILES_ICON_IDS[i][1]).getConstantState() - .newDrawable(); - icon.setTint(iconFgColor); - //TODO: load and set the shape. - Drawable bgShape = mShapeDrawable.getConstantState().newDrawable(); - bgShape.setTint(accentColor); - - ImageView bg = container.findViewById(COLOR_TILE_IDS[i]); - bg.setImageDrawable(bgShape); - ImageView fg = container.findViewById(COLOR_TILES_ICON_IDS[i][0]); - fg.setImageDrawable(icon); - } - } - } - - public void setPreviewIcons(List<Drawable> icons) { - mIcons.addAll(icons); - } - - public void setShapeDrawable(@Nullable Drawable shapeDrawable) { - mShapeDrawable = shapeDrawable; - } - - @Override - public Builder buildStep(Builder builder) { - builder.setColorAccentDark(mColorAccentDark).setColorAccentLight(mColorAccentLight); - return super.buildStep(builder); - } - } - - public static class ShapeOption extends ThemeComponentOption { - - private final LayerDrawable mShape; - private final List<ShapeAppIcon> mAppIcons; - private final String mLabel; - private final Path mPath; - private final int mCornerRadius; - private int[] mShapeIconIds = { - R.id.shape_preview_icon_0, R.id.shape_preview_icon_1, R.id.shape_preview_icon_2, - R.id.shape_preview_icon_3, R.id.shape_preview_icon_4, R.id.shape_preview_icon_5 - }; - - ShapeOption(String packageName, String label, Path path, - @Dimension int cornerRadius, Drawable shapeDrawable, - List<ShapeAppIcon> appIcons) { - addOverlayPackage(OVERLAY_CATEGORY_SHAPE, packageName); - mLabel = label; - mAppIcons = appIcons; - mPath = path; - mCornerRadius = cornerRadius; - Drawable background = shapeDrawable.getConstantState().newDrawable(); - Drawable foreground = shapeDrawable.getConstantState().newDrawable(); - mShape = new LayerDrawable(new Drawable[]{background, foreground}); - mShape.setLayerGravity(0, Gravity.CENTER); - mShape.setLayerGravity(1, Gravity.CENTER); - } - - @Override - public void bindThumbnailTile(View view) { - ImageView thumb = view.findViewById(R.id.shape_thumbnail); - Resources res = view.getResources(); - Theme theme = view.getContext().getTheme(); - int borderWidth = 2 * res.getDimensionPixelSize(R.dimen.option_border_width); - - Drawable background = mShape.getDrawable(0); - background.setTintList(res.getColorStateList(R.color.option_border_color, theme)); - - ShapeDrawable foreground = (ShapeDrawable) mShape.getDrawable(1); - - foreground.setIntrinsicHeight(background.getIntrinsicHeight() - borderWidth); - foreground.setIntrinsicWidth(background.getIntrinsicWidth() - borderWidth); - TypedArray ta = view.getContext().obtainStyledAttributes( - new int[]{android.R.attr.colorPrimary}); - int primaryColor = ta.getColor(0, 0); - ta.recycle(); - int foregroundColor = - ResourceUtils.getColorAttr(view.getContext(), android.R.attr.textColorPrimary); - - foreground.setTint(ColorUtils.blendARGB(primaryColor, foregroundColor, .05f)); - - thumb.setImageDrawable(mShape); - view.setContentDescription(mLabel); - } - - @Override - public boolean isActive(CustomizationManager<ThemeComponentOption> manager) { - CustomThemeManager customThemeManager = (CustomThemeManager) manager; - return Objects.equals(getOverlayPackages().get(OVERLAY_CATEGORY_SHAPE), - customThemeManager.getOverlayPackages().get(OVERLAY_CATEGORY_SHAPE)); - } - - @Override - public int getLayoutResId() { - return R.layout.theme_shape_option; - } - - @Override - public void bindPreview(ViewGroup container) { - container.setContentDescription( - container.getContext().getString(R.string.shape_preview_content_description)); - - bindPreviewHeader(container, R.string.preview_name_shape, R.drawable.ic_shapes_24px, - null); - - ViewGroup cardBody = container.findViewById(R.id.theme_preview_card_body_container); - if (cardBody.getChildCount() == 0) { - LayoutInflater.from(container.getContext()).inflate( - R.layout.preview_card_shape_content, cardBody, true); - } - for (int i = 0; i < mShapeIconIds.length && i < mAppIcons.size(); i++) { - ImageView iconView = cardBody.findViewById(mShapeIconIds[i]); - iconView.setBackground(mAppIcons.get(i).getDrawableCopy()); - } - } - - @Override - public Builder buildStep(Builder builder) { - builder.setShapePath(mPath) - .setBottomSheetCornerRadius(mCornerRadius) - .setShapePreviewIcons(mAppIcons); - return super.buildStep(builder); - } - } -} diff --git a/src/com/android/customization/model/theme/custom/ThemeComponentOptionProvider.java b/src/com/android/customization/model/theme/custom/ThemeComponentOptionProvider.java deleted file mode 100644 index 992c47cc..00000000 --- a/src/com/android/customization/model/theme/custom/ThemeComponentOptionProvider.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2019 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.customization.model.theme.custom; - -import android.content.Context; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; -import android.os.UserHandle; - -import com.android.customization.model.CustomizationManager.OptionsFetchedListener; -import com.android.customization.model.ResourceConstants; -import com.android.customization.model.theme.OverlayManagerCompat; - -import java.util.ArrayList; -import java.util.List; - -/** - * Base class used to retrieve Custom Theme Component options (eg, different fonts) - * from the system. - */ -public abstract class ThemeComponentOptionProvider<T extends ThemeComponentOption> { - - protected final Context mContext; - protected final List<String> mOverlayPackages; - protected List<T> mOptions; - - public ThemeComponentOptionProvider(Context context, OverlayManagerCompat manager, - String... categories) { - mContext = context; - mOverlayPackages = new ArrayList<>(); - for (String category : categories) { - mOverlayPackages.addAll(manager.getOverlayPackagesForCategory(category, - UserHandle.myUserId(), ResourceConstants.getPackagesToOverlay(mContext))); - } - } - - /** - * Returns whether there are options for this component available in the current setup. - */ - public boolean isAvailable() { - return !mOverlayPackages.isEmpty(); - } - - /** - * Retrieve the available options for this component. - * @param callback called when the themes have been retrieved (or immediately if cached) - * @param reload whether to reload themes if they're cached. - */ - public void fetch(OptionsFetchedListener<T> callback, boolean reload) { - if (mOptions == null || reload) { - mOptions = new ArrayList<>(); - loadOptions(); - } - - if(callback != null) { - callback.onOptionsLoaded(mOptions); - } - } - - protected abstract void loadOptions(); - - protected Resources getOverlayResources(String overlayPackage) throws NameNotFoundException { - return mContext.getPackageManager().getResourcesForApplication(overlayPackage); - } -} |