package yuku.alkitab.base.widget; import android.content.Context; import android.content.ContextWrapper; import android.content.res.Configuration; import android.os.Build; import android.os.LocaleList; import android.provider.Settings; import android.support.annotation.CheckResult; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; import yuku.afw.storage.Preferences; import yuku.alkitab.base.App; import yuku.alkitab.debug.BuildConfig; import yuku.alkitab.debug.R; import java.util.Locale; import java.util.concurrent.atomic.AtomicInteger; /** * Context wrapper for changing app-wide locale or font scale. */ public class ConfigurationWrapper extends ContextWrapper { static final String TAG = ConfigurationWrapper.class.getSimpleName(); public ConfigurationWrapper(final Context base) { super(base); } public static Context wrap(final Context base) { final Configuration config = base.getResources().getConfiguration(); final Locale prefLocale = getLocaleFromPreferences(); if (BuildConfig.DEBUG) Log.d(TAG, "@@wrap: config locale will be updated to: " + prefLocale); ConfigurationCompat.setLocale(config, prefLocale); final float fontScale = getFontScaleFromPreferences(); if (config.fontScale != fontScale) { if (BuildConfig.DEBUG) Log.d(TAG, "@@wrap: fontScale will be updated to: " + fontScale); config.fontScale = fontScale; } return new ConfigurationWrapper(ConfigurationCompat.updateConfiguration(base, config)); } private static AtomicInteger serialCounter = new AtomicInteger(); public static int getSerialCounter() { return serialCounter.get(); } public static void notifyConfigurationNeedsUpdate() { serialCounter.incrementAndGet(); } @SuppressWarnings("deprecation") public static class ConfigurationCompat { @Nullable public static Locale getLocale(Configuration config) { if (Build.VERSION.SDK_INT >= 24) { final LocaleList locales = config.getLocales(); if (locales.size() > 0) { return locales.get(0); } else { return null; } } else { return config.locale; } } public static void setLocale(Configuration config, @NonNull Locale locale) { if (Build.VERSION.SDK_INT >= 17) { config.setLocale(locale); } else { config.locale = locale; } } @CheckResult public static Context updateConfiguration(Context context, Configuration config) { if (Build.VERSION.SDK_INT >= 17) { return context.createConfigurationContext(config); } else { context.getResources().updateConfiguration(config, null); return context; } } } @NonNull public static Locale getLocaleFromPreferences() { final String lang = Preferences.getString(R.string.pref_language_key, R.string.pref_language_default); if (lang == null || "DEFAULT".equals(lang)) { return Locale.getDefault(); } if (!lang.contains("-")) { // From https://code.google.com/p/android/issues/detail?id=225679#c2 // It's not a good idea to set a locale without a country in Android. // Various parts of the system expect a country and may behave in weird ways otherwise. // So if you are setting a locale programatically, set it to "ru-RU" instead of "ru". return localeWithCountry(lang); } else { // contains "-" switch (lang) { case "zh-CN": return Locale.SIMPLIFIED_CHINESE; case "zh-TW": return Locale.TRADITIONAL_CHINESE; default: return new Locale(lang); } } } @NonNull private static Locale localeWithCountry(@NonNull final String lang) { switch (lang) { case "af": return new Locale("af", "ZA"); case "in": return new Locale("in", "ID"); case "cs": return new Locale("cs", "CZ"); case "da": return new Locale("da", "DK"); case "de": return new Locale("de", "DE"); case "en": return new Locale("en", "US"); case "es": return new Locale("es", "ES"); case "fr": return new Locale("fr", "FR"); case "lv": return new Locale("lv", "LV"); case "nl": return new Locale("nl", "NL"); case "pl": return new Locale("pl", "PL"); case "pt": return new Locale("pt", "BR"); case "ro": return new Locale("ro", "RO"); case "vi": return new Locale("vi", "VN"); case "bg": return new Locale("bg", "BG"); case "ru": return new Locale("ru", "RU"); case "uk": return new Locale("uk", "UA"); case "th": return new Locale("th", "TH"); case "ja": return new Locale("ja", "JP"); case "ko": return new Locale("ko", "KR"); default: return new Locale(lang); } } private static float getFontScaleFromPreferences() { float res = 0.f; final String forceFontScale = Preferences.getString(R.string.pref_forceFontScale_key, R.string.pref_forceFontScale_default); if (!forceFontScale.equals(Preferences.getString(R.string.pref_forceFontScale_default))) { if (forceFontScale.equals(Preferences.getString(R.string.pref_forceFontScale_value_x1_5))) { res = 1.5f; } else if (forceFontScale.equals(Preferences.getString(R.string.pref_forceFontScale_value_x1_7))) { res = 1.7f; } else if (forceFontScale.equals(Preferences.getString(R.string.pref_forceFontScale_value_x2_0))) { res = 2.0f; } } if (res == 0.f) { final float defFontScale = Settings.System.getFloat(App.context.getContentResolver(), Settings.System.FONT_SCALE, 1.f); if (BuildConfig.DEBUG) Log.d(TAG, "defFontScale: " + defFontScale); res = defFontScale; } return res; } }