blob: 98b88838657c0525788aca5006ec8174070b3e95 [file] [log] [blame]
/*
* Copyright (C) 2018 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.google.android.setupdesign.util;
import android.app.Activity;
import android.content.Intent;
import androidx.annotation.Nullable;
import androidx.annotation.StyleRes;
import com.google.android.setupcompat.util.WizardManagerHelper;
import com.google.android.setupdesign.R;
/**
* A resolver to resolve the theme from a string or an activity intent, setting options like the
* default theme and the oldest supported theme. Apps can share the resolver across the entire
* process by calling {@link #setDefault(ThemeResolver)} in {@link
* android.app.Application#onCreate()}. If an app needs more granular sharing of the theme default
* values, additional instances of {@link ThemeResolver} can be created using the builder.
*/
public class ThemeResolver {
@StyleRes private final int defaultTheme;
@Nullable private final String oldestSupportedTheme;
private final boolean useDayNight;
@Nullable private final ThemeSupplier defaultThemeSupplier;
@Nullable private static ThemeResolver defaultResolver;
/**
* Sets the default instance used for the whole process. Can be null to reset the default to the
* preset one.
*/
public static void setDefault(@Nullable ThemeResolver resolver) {
defaultResolver = resolver;
}
/**
* Returns the default instance, which can be changed using {@link #setDefault(ThemeResolver)}.
*/
public static ThemeResolver getDefault() {
if (defaultResolver == null) {
defaultResolver =
new ThemeResolver.Builder()
.setDefaultTheme(R.style.SudThemeGlif_DayNight)
.setUseDayNight(true)
.build();
}
return defaultResolver;
}
private ThemeResolver(
int defaultTheme,
@Nullable String oldestSupportedTheme,
@Nullable ThemeSupplier defaultThemeSupplier,
boolean useDayNight) {
this.defaultTheme = defaultTheme;
this.oldestSupportedTheme = oldestSupportedTheme;
this.defaultThemeSupplier = defaultThemeSupplier;
this.useDayNight = useDayNight;
}
/**
* Returns the style for the theme specified in the intent extra. If the specified string theme is
* older than the oldest supported theme, the default will be returned instead. Note that the
* default theme is returned without processing -- it may not be a DayNight theme even if {@link
* #useDayNight} is true.
*/
@StyleRes
public int resolve(Intent intent) {
return resolve(
intent.getStringExtra(WizardManagerHelper.EXTRA_THEME),
/* suppressDayNight= */ WizardManagerHelper.isAnySetupWizard(intent));
}
/**
* Returns the style for the given string theme. If the specified string theme is older than the
* oldest supported theme, the default will be returned instead. Note that the default theme is
* returned without processing -- it may not be a DayNight theme even if {@link #useDayNight} is
* true.
*
* @deprecated Use {@link #resolve(String, boolean)} instead
*/
@Deprecated
@StyleRes
public int resolve(@Nullable String theme) {
return resolve(theme, /* suppressDayNight= */ false);
}
/**
* Returns the style for the given string theme. If the specified string theme is older than the
* oldest supported theme, the default will be returned instead. Note that the default theme is
* returned without processing -- it may not be a DayNight theme even if {@link #useDayNight} is
* true.
*/
@StyleRes
public int resolve(@Nullable String theme, boolean suppressDayNight) {
int themeResource =
useDayNight && !suppressDayNight ? getDayNightThemeRes(theme) : getThemeRes(theme);
if (themeResource == 0) {
if (defaultThemeSupplier != null) {
theme = defaultThemeSupplier.getTheme();
themeResource =
useDayNight && !suppressDayNight ? getDayNightThemeRes(theme) : getThemeRes(theme);
}
if (themeResource == 0) {
return defaultTheme;
}
}
if (oldestSupportedTheme != null && compareThemes(theme, oldestSupportedTheme) < 0) {
return defaultTheme;
}
return themeResource;
}
/** Reads the theme from the intent, and applies the resolved theme to the activity. */
public void applyTheme(Activity activity) {
activity.setTheme(resolve(activity.getIntent()));
}
/**
* Returns the corresponding DayNight theme resource ID for the given string theme. DayNight
* themes are themes that will be either light or dark depending on the system setting. For
* example, the string {@link ThemeHelper#THEME_GLIF_LIGHT} will return
* {@code @style/SudThemeGlif.DayNight}.
*/
@StyleRes
private static int getDayNightThemeRes(@Nullable String theme) {
if (theme != null) {
switch (theme) {
case ThemeHelper.THEME_GLIF_V3_LIGHT:
case ThemeHelper.THEME_GLIF_V3:
return R.style.SudThemeGlifV3_DayNight;
case ThemeHelper.THEME_GLIF_V2_LIGHT:
case ThemeHelper.THEME_GLIF_V2:
return R.style.SudThemeGlifV2_DayNight;
case ThemeHelper.THEME_GLIF_LIGHT:
case ThemeHelper.THEME_GLIF:
return R.style.SudThemeGlif_DayNight;
case ThemeHelper.THEME_MATERIAL_LIGHT:
case ThemeHelper.THEME_MATERIAL:
return R.style.SudThemeMaterial_DayNight;
default:
// fall through
}
}
return 0;
}
/**
* Returns the theme resource ID for the given string theme. For example, the string {@link
* ThemeHelper#THEME_GLIF_LIGHT} will return {@code @style/SudThemeGlif.Light}.
*/
@StyleRes
private static int getThemeRes(@Nullable String theme) {
if (theme != null) {
switch (theme) {
case ThemeHelper.THEME_GLIF_V3_LIGHT:
return R.style.SudThemeGlifV3_Light;
case ThemeHelper.THEME_GLIF_V3:
return R.style.SudThemeGlifV3;
case ThemeHelper.THEME_GLIF_V2_LIGHT:
return R.style.SudThemeGlifV2_Light;
case ThemeHelper.THEME_GLIF_V2:
return R.style.SudThemeGlifV2;
case ThemeHelper.THEME_GLIF_LIGHT:
return R.style.SudThemeGlif_Light;
case ThemeHelper.THEME_GLIF:
return R.style.SudThemeGlif;
case ThemeHelper.THEME_MATERIAL_LIGHT:
return R.style.SudThemeMaterial_Light;
case ThemeHelper.THEME_MATERIAL:
return R.style.SudThemeMaterial;
default:
// fall through
}
}
return 0;
}
/** Compares whether the versions of {@code theme1} and {@code theme2} to check which is newer. */
private static int compareThemes(String theme1, String theme2) {
return Integer.valueOf(getThemeVersion(theme1)).compareTo(getThemeVersion(theme2));
}
/**
* Returns the version of the theme. The absolute number of the theme version is not defined, but
* a larger number in the version indicates a newer theme.
*/
private static int getThemeVersion(String theme) {
if (theme != null) {
switch (theme) {
case ThemeHelper.THEME_GLIF_V3_LIGHT:
case ThemeHelper.THEME_GLIF_V3:
return 4;
case ThemeHelper.THEME_GLIF_V2_LIGHT:
case ThemeHelper.THEME_GLIF_V2:
return 3;
case ThemeHelper.THEME_GLIF_LIGHT:
case ThemeHelper.THEME_GLIF:
return 2;
case ThemeHelper.THEME_MATERIAL_LIGHT:
case ThemeHelper.THEME_MATERIAL:
return 1;
default:
// fall through
}
}
return -1;
}
/** Builder class for {@link ThemeResolver}. */
public static class Builder {
private ThemeSupplier defaultThemeSupplier;
@StyleRes private int defaultTheme = R.style.SudThemeGlif_DayNight;
@Nullable private String oldestSupportedTheme = null;
private boolean useDayNight = true;
public Builder() {}
public Builder(ThemeResolver themeResolver) {
this.defaultTheme = themeResolver.defaultTheme;
this.oldestSupportedTheme = themeResolver.oldestSupportedTheme;
this.useDayNight = themeResolver.useDayNight;
}
public Builder setDefaultThemeSupplier(ThemeSupplier defaultThemeSupplier) {
this.defaultThemeSupplier = defaultThemeSupplier;
return this;
}
public Builder setDefaultTheme(@StyleRes int defaultTheme) {
this.defaultTheme = defaultTheme;
return this;
}
public Builder setOldestSupportedTheme(String oldestSupportedTheme) {
this.oldestSupportedTheme = oldestSupportedTheme;
return this;
}
public Builder setUseDayNight(boolean useDayNight) {
this.useDayNight = useDayNight;
return this;
}
public ThemeResolver build() {
return new ThemeResolver(
defaultTheme, oldestSupportedTheme, defaultThemeSupplier, useDayNight);
}
}
public interface ThemeSupplier {
String getTheme();
}
}