[tor-commits] [orbot/master] improvements to Locale changing in app

n8fr8 at torproject.org n8fr8 at torproject.org
Mon Jan 25 17:08:43 UTC 2016


commit 6eb0a93dd86a207d51f73136cf616ca96e268959
Author: Nathan Freitas <nathan at freitas.net>
Date:   Wed Jan 20 16:52:59 2016 -0500

    improvements to Locale changing in app
---
 src/info/guardianproject/util/Languages.java       |  150 +++++++++++++++-----
 src/org/torproject/android/OrbotApp.java           |   40 +-----
 .../android/settings/SettingsPreferences.java      |    4 +-
 3 files changed, 120 insertions(+), 74 deletions(-)

diff --git a/src/info/guardianproject/util/Languages.java b/src/info/guardianproject/util/Languages.java
index b776f75..6219661 100644
--- a/src/info/guardianproject/util/Languages.java
+++ b/src/info/guardianproject/util/Languages.java
@@ -1,10 +1,14 @@
-
 package info.guardianproject.util;
 
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
 import android.app.Activity;
+import android.content.ContextWrapper;
+import android.content.Intent;
 import android.content.res.AssetManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.os.Build;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 
@@ -16,11 +20,9 @@ import java.util.Set;
 import java.util.TreeMap;
 
 public class Languages {
-    private static final String TAG = "Languages";
-    private static Languages singleton;
-    private static Map<String, String> tmpMap = new TreeMap<String, String>();
-    private static Map<String, String> nameMap;
-    public static final String USE_SYSTEM_DEFAULT = "";
+    public static final String TAG = "Languages";
+
+    public static final Locale defaultLocale;
     public static final Locale TIBETAN = new Locale("bo");
     static final Locale localesToTest[] = {
             Locale.ENGLISH, Locale.FRENCH, Locale.GERMAN,
@@ -50,68 +52,142 @@ public class Languages {
             new Locale("uz"), new Locale("vi"), new Locale("zu"),
     };
 
-    private Languages(Activity activity, int resId, String defaultString) {
+    private static final String USE_SYSTEM_DEFAULT = "";
+    private static final String defaultString = "Use System Default";
+
+    private static Locale locale;
+    private static Languages singleton;
+    private static Class<?> clazz;
+    private static int resId;
+    private static Map<String, String> tmpMap = new TreeMap<String, String>();
+    private static Map<String, String> nameMap;
+
+    static {
+        defaultLocale = Locale.getDefault();
+    }
+
+    private Languages(Activity activity) {
         AssetManager assets = activity.getAssets();
         Configuration config = activity.getResources().getConfiguration();
-        DisplayMetrics metrics = new DisplayMetrics();
-        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        // Resources() requires DisplayMetrics, but they are only needed for drawables
+        DisplayMetrics ignored = new DisplayMetrics();
+        activity.getWindowManager().getDefaultDisplay().getMetrics(ignored);
         Resources resources;
         Set<Locale> localeSet = new LinkedHashSet<Locale>();
         for (Locale locale : localesToTest) {
             config.locale = locale;
-            resources = new Resources(assets, metrics, config);
+            resources = new Resources(assets, ignored, config);
             if (!TextUtils.equals(defaultString, resources.getString(resId))
                     || locale.equals(Locale.ENGLISH))
                 localeSet.add(locale);
         }
         for (Locale locale : localeSet) {
             if (locale.equals(TIBETAN)) {
-                // include English name for devices that don't support Tibetan
-                // font
+                // include English name for devices without Tibetan font support
                 tmpMap.put(TIBETAN.getLanguage(), "Tibetan བོད་སྐད།"); // Tibetan
             } else if (locale.equals(Locale.SIMPLIFIED_CHINESE)) {
-                tmpMap.put(Locale.SIMPLIFIED_CHINESE.toString(), "中文 (中国)"); // Chinese
-                                                                             // (China)
+                tmpMap.put(Locale.SIMPLIFIED_CHINESE.toString(), "中文 (中国)"); // Chinese (China)
             } else if (locale.equals(Locale.TRADITIONAL_CHINESE)) {
-                tmpMap.put(Locale.TRADITIONAL_CHINESE.toString(), "中文 (台灣)"); // Chinese
-                                                                              // (Taiwan)
+                tmpMap.put(Locale.TRADITIONAL_CHINESE.toString(), "中文 (台灣)"); // Chinese (Taiwan)
             } else {
                 tmpMap.put(locale.getLanguage(), locale.getDisplayLanguage(locale));
             }
         }
-        // TODO implement this completely, the menu item works, but doesn't work
-        // properly
+
         /* USE_SYSTEM_DEFAULT is a fake one for displaying in a chooser menu. */
-        // localeSet.add(null);
-        // tmpMap.put(USE_SYSTEM_DEFAULT,
-        // activity.getString(R.string.use_system_default));
+        localeSet.add(null);
+        tmpMap.put(USE_SYSTEM_DEFAULT, activity.getString(resId));
         nameMap = Collections.unmodifiableMap(tmpMap);
     }
 
     /**
      * Get the instance of {@link Languages} to work with, providing the
-     * {@link Activity} that is will be working as part of. This uses the
-     * provided string resource {@code resId} find the supported translations:
-     * if an included translation has a translated string that matches that
-     * {@code resId}, i.e. {@code R.string.menu_settings}, then that language
-     * will be included as a supported language.
-     * 
+     * {@link Activity} that is will be working as part of, as well as the
+     * {@code resId} that has the exact string "Use System Default",
+     * i.e. {@code R.string.use_system_default}.
+     * <p/>
+     * That string resource {@code resId} is also used to find the supported
+     * translations: if an included translation has a translated string that
+     * matches that {@code resId}, then that language will be included as a
+     * supported language.
+     *
+     * @param clazz the {@link Class} of the default {@code Activity},
+     *              usually the main {@code Activity} from where the
+     *              Settings is launched from.
+     * @param resId the string resource ID to for the string "Use System Default",
+     *              e.g. {@code R.string.use_system_default}
+     * @return
+     */
+    public static void setup(Class<?> clazz, int resId) {
+        if (Languages.clazz == null) {
+            Languages.clazz = clazz;
+            Languages.resId = resId;
+        } else {
+            throw new RuntimeException("Languages singleton was already initialized, duplicate call to Languages.setup()!");
+        }
+    }
+
+    /**
+     * Get the singleton to work with.
+     *
      * @param activity the {@link Activity} this is working as part of
-     * @param resId the string resource ID to test, e.g.
-     *            {@code R.string.menu_settings}
-     * @param defaultString the string resource in the default language, e.g.
-     *            {@code "Settings"}
      * @return
      */
-    public static Languages get(Activity activity, int resId, String defaultString) {
-        if (singleton == null)
-            singleton = new Languages(activity, resId, defaultString);
+    public static Languages get(Activity activity) {
+        if (singleton == null) {
+            singleton = new Languages(activity);
+        }
         return singleton;
     }
 
+    //@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+    @SuppressLint("NewApi")
+	public static void setLanguage(final ContextWrapper contextWrapper, String language, boolean refresh) {
+        if (locale != null && TextUtils.equals(locale.getLanguage(), language) && (!refresh)) {
+            return; // already configured
+        } else if (language == null || language == USE_SYSTEM_DEFAULT) {
+            locale = defaultLocale;
+        } else {
+            /* handle locales with the country in it, i.e. zh_CN, zh_TW, etc */
+            String localeSplit[] = language.split("_");
+            if (localeSplit.length > 1) {
+                locale = new Locale(localeSplit[0], localeSplit[1]);
+            } else {
+                locale = new Locale(language);
+            }
+        }
+
+        final Resources resources = contextWrapper.getBaseContext().getResources();
+        Configuration config = resources.getConfiguration();
+        if (Build.VERSION.SDK_INT >= 17) {
+            config.setLocale(locale);
+        } else {
+            config.locale = locale;
+        }
+        resources.updateConfiguration(config, resources.getDisplayMetrics());
+        Locale.setDefault(locale);
+
+    }
+
+    /**
+     * Force reload the {@link Activity to make language changes take effect.}
+     *
+     * @param activity the {@code Activity} to force reload
+     */
+    public static void forceChangeLanguage(Activity activity) {
+        Intent intent = activity.getIntent();
+        if (intent == null) // when launched as LAUNCHER
+            return;
+        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+        activity.finish();
+        activity.overridePendingTransition(0, 0);
+        activity.startActivity(intent);
+        activity.overridePendingTransition(0, 0);
+    }
+
     /**
      * Return the name of the language based on the locale.
-     * 
+     *
      * @param locale
      * @return
      */
@@ -127,7 +203,7 @@ public class Languages {
     /**
      * Return an array of the names of all the supported languages, sorted to
      * match what is returned by {@link Languages#getSupportedLocales()}.
-     * 
+     *
      * @return
      */
     public String[] getAllNames() {
@@ -147,7 +223,7 @@ public class Languages {
 
     /**
      * Get sorted list of supported locales.
-     * 
+     *
      * @return
      */
     public String[] getSupportedLocales() {
diff --git a/src/org/torproject/android/OrbotApp.java b/src/org/torproject/android/OrbotApp.java
index 25818fa..021336d 100644
--- a/src/org/torproject/android/OrbotApp.java
+++ b/src/org/torproject/android/OrbotApp.java
@@ -39,7 +39,8 @@ public class OrbotApp extends Application implements OrbotConstants
         super.onCreate();
         Prefs.setContext(this);
 
-        setNewLocale(Prefs.getDefaultLocale());
+        Languages.setup(OrbotMainActivity.class, R.string.menu_settings);
+        Languages.setLanguage(this, Prefs.getDefaultLocale(), true);
 
         appBinHome = getDir(TorServiceConstants.DIRECTORY_TOR_BINARY,Application.MODE_PRIVATE);
         appCacheHome = getDir(TorServiceConstants.DIRECTORY_TOR_DATA,Application.MODE_PRIVATE);
@@ -60,40 +61,9 @@ public class OrbotApp extends Application implements OrbotConstants
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         Log.i(TAG, "onConfigurationChanged " + newConfig.locale.getLanguage());
-        setNewLocale(Prefs.getDefaultLocale());
+        Languages.setLanguage(this, Prefs.getDefaultLocale(), true);
     }
-
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
-    public void setNewLocale(String language) {
-        if (TextUtils.isEmpty(language))
-            return;
-
-        if (locale != null && TextUtils.equals(locale.getLanguage(), language))
-            return; // already configured
-
-        /* handle locales with the country in it, i.e. zh_CN, zh_TW, etc */
-        String localeSplit[] = language.split("_");
-        if (localeSplit.length > 1)
-            locale = new Locale(localeSplit[0], localeSplit[1]);
-        else
-            locale = new Locale(language);
-        Configuration config = getResources().getConfiguration();
-        if (Build.VERSION.SDK_INT >= 17)
-            config.setLocale(locale);
-        else
-            config.locale = locale;
-        getResources().updateConfiguration(config, getResources().getDisplayMetrics());
-
-        /*
-         * Set the preference after setting the locale in case something goes
-         * wrong. If setting the locale causes an Exception, it should be set in
-         * the preferences, otherwise ChatSecure will be stuck in a crash loop.
-         */
-        Prefs.setDefaultLocale(language);
-        Log.i(TAG, "setNewLocale complete: locale: " + locale.getLanguage()
-                + " Locale.getDefault: " + Locale.getDefault().getLanguage());
-    }
-
+	
     public static void forceChangeLanguage(Activity activity) {
         Intent intent = activity.getIntent();
         if (intent == null) // when launched as LAUNCHER
@@ -106,6 +76,6 @@ public class OrbotApp extends Application implements OrbotConstants
     }
 
     public static Languages getLanguages(Activity activity) {
-        return Languages.get(activity, R.string.menu_settings, "Settings");
+        return Languages.get(activity);
     }
 }
diff --git a/src/org/torproject/android/settings/SettingsPreferences.java b/src/org/torproject/android/settings/SettingsPreferences.java
index d7a976f..8d861f4 100644
--- a/src/org/torproject/android/settings/SettingsPreferences.java
+++ b/src/org/torproject/android/settings/SettingsPreferences.java
@@ -56,7 +56,7 @@ public class SettingsPreferences
 
         prefLocale = (ListPreference) findPreference("pref_default_locale");
         prefLocale.setOnPreferenceClickListener(this);
-        Languages languages = Languages.get(this, R.string.menu_settings, "Settings");
+        Languages languages = Languages.get(this);
         prefLocale.setEntries(languages.getAllNames());
         prefLocale.setEntryValues(languages.getSupportedLocales());
         prefLocale.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@@ -71,7 +71,7 @@ public class SettingsPreferences
                     String lang = settings.getString("pref_default_locale",
                             Locale.getDefault().getLanguage());
                     OrbotApp app = (OrbotApp) getApplication();
-                    app.setNewLocale(language);
+                    Languages.setLanguage(app, language, true);
                     lang = settings.getString("pref_default_locale",
                             Locale.getDefault().getLanguage());
                     OrbotApp.forceChangeLanguage(SettingsPreferences.this);





More information about the tor-commits mailing list