/* * 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 { public static final Set 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 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 callback, boolean reload) { mProvider.fetch(callback, reload); } public Map 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()); } } }