content: package com.android.setupwizardlib.util;
  
  import android.app.Activity;
  import android.content.Intent;
  import androidx.annotation.Nullable;
  import androidx.annotation.StyleRes;
  import com.android.setupwizardlib.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 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.SuwThemeGlif_DayNight)
                .setUseDayNight(true)
                .build();
      }
      return defaultResolver;
    }
  
    private ThemeResolver(
        int defaultTheme, @Nullable String oldestSupportedTheme, boolean useDayNight) {
      this.defaultTheme = defaultTheme;
      this.oldestSupportedTheme = oldestSupportedTheme;
      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.isSetupWizardIntent(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.
     */
    @StyleRes
    public int resolve(@Nullable String theme) {
      return resolve(theme, /* suppressDayNight= */ false);
    }
  
    @StyleRes
    private int resolve(@Nullable String theme, boolean suppressDayNight) {
      int 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 WizardManagerHelper#THEME_GLIF_LIGHT} will return
     * {@code @style/SuwThemeGlif.DayNight}.
     */
    @StyleRes
    private static int getDayNightThemeRes(@Nullable String theme) {
      if (theme != null) {
        switch (theme) {
          case WizardManagerHelper.THEME_GLIF_V3_LIGHT:
          case WizardManagerHelper.THEME_GLIF_V3:
            return R.style.SuwThemeGlifV3_DayNight;
          case WizardManagerHelper.THEME_GLIF_V2_LIGHT:
          case WizardManagerHelper.THEME_GLIF_V2:
            return R.style.SuwThemeGlifV2_DayNight;
          case WizardManagerHelper.THEME_GLIF_LIGHT:
          case WizardManagerHelper.THEME_GLIF:
            return R.style.SuwThemeGlif_DayNight;
          case WizardManagerHelper.THEME_MATERIAL_LIGHT:
          case WizardManagerHelper.THEME_MATERIAL:
            return R.style.SuwThemeMaterial_DayNight;
          default:
            // fall through
        }
      }
      return 0;
    }
  
    /**
     * Returns the theme resource ID for the given string theme. For example, the string {@link
     * WizardManagerHelper#THEME_GLIF_LIGHT} will return {@code @style/SuwThemeGlif.Light}.
     */
    @StyleRes
    private static int getThemeRes(@Nullable String theme) {
      if (theme != null) {
        switch (theme) {
          case WizardManagerHelper.THEME_GLIF_V3_LIGHT:
            return R.style.SuwThemeGlifV3_Light;
          case WizardManagerHelper.THEME_GLIF_V3:
            return R.style.SuwThemeGlifV3;
          case WizardManagerHelper.THEME_GLIF_V2_LIGHT:
            return R.style.SuwThemeGlifV2_Light;
          case WizardManagerHelper.THEME_GLIF_V2:
            return R.style.SuwThemeGlifV2;
          case WizardManagerHelper.THEME_GLIF_LIGHT:
            return R.style.SuwThemeGlif_Light;
          case WizardManagerHelper.THEME_GLIF:
            return R.style.SuwThemeGlif;
          case WizardManagerHelper.THEME_MATERIAL_LIGHT:
            return R.style.SuwThemeMaterial_Light;
          case WizardManagerHelper.THEME_MATERIAL:
            return R.style.SuwThemeMaterial;
          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 WizardManagerHelper.THEME_GLIF_V3_LIGHT:
          case WizardManagerHelper.THEME_GLIF_V3:
            return 4;
          case WizardManagerHelper.THEME_GLIF_V2_LIGHT:
          case WizardManagerHelper.THEME_GLIF_V2:
            return 3;
          case WizardManagerHelper.THEME_GLIF_LIGHT:
          case WizardManagerHelper.THEME_GLIF:
            return 2;
          case WizardManagerHelper.THEME_MATERIAL_LIGHT:
          case WizardManagerHelper.THEME_MATERIAL:
            return 1;
          default:
            // fall through
        }
      }
      return -1;
    }
  
    /** Builder class for {@link ThemeResolver}. */
    public static class Builder {
      @StyleRes private int defaultTheme = R.style.SuwThemeGlif_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 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, useDayNight);
      }
    }
  }
  