1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 package org.mozilla.gecko;
6 
7 import java.lang.reflect.Method;
8 import java.util.Locale;
9 
10 import org.mozilla.gecko.LocaleManager;
11 
12 import android.app.Activity;
13 import android.content.Context;
14 import android.os.Bundle;
15 import android.os.StrictMode;
16 import android.support.v4.app.FragmentActivity;
17 import android.support.v7.app.AppCompatActivity;
18 
19 /**
20  * This is a helper class to do typical locale switching operations without
21  * hitting StrictMode errors or adding boilerplate to common activity
22  * subclasses.
23  *
24  * Either call {@link Locales#initializeLocale(Context)} in your
25  * <code>onCreate</code> method, or inherit from
26  * <code>LocaleAwareFragmentActivity</code> or <code>LocaleAwareActivity</code>.
27  */
28 public class Locales {
getLocaleManager()29     public static LocaleManager getLocaleManager() {
30         try {
31             final Class<?> clazz = Class.forName("org.mozilla.gecko.BrowserLocaleManager");
32             final Method getInstance = clazz.getMethod("getInstance");
33             final LocaleManager localeManager = (LocaleManager) getInstance.invoke(null);
34             return localeManager;
35         } catch (Exception e) {
36           throw new RuntimeException(e);
37         }
38     }
39 
initializeLocale(Context context)40     public static void initializeLocale(Context context) {
41         final LocaleManager localeManager = getLocaleManager();
42         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
43         StrictMode.allowThreadDiskWrites();
44         try {
45             localeManager.getAndApplyPersistedLocale(context);
46         } finally {
47             StrictMode.setThreadPolicy(savedPolicy);
48         }
49     }
50 
51     public static abstract class LocaleAwareAppCompatActivity extends AppCompatActivity {
52         @Override
onCreate(Bundle savedInstanceState)53         protected void onCreate(Bundle savedInstanceState) {
54             Locales.initializeLocale(getApplicationContext());
55             super.onCreate(savedInstanceState);
56         }
57 
58     }
59     public static abstract class LocaleAwareFragmentActivity extends FragmentActivity {
60         @Override
onCreate(Bundle savedInstanceState)61         protected void onCreate(Bundle savedInstanceState) {
62             Locales.initializeLocale(getApplicationContext());
63             super.onCreate(savedInstanceState);
64         }
65     }
66 
67     public static abstract class LocaleAwareActivity extends Activity {
68         @Override
onCreate(Bundle savedInstanceState)69         protected void onCreate(Bundle savedInstanceState) {
70             Locales.initializeLocale(getApplicationContext());
71             super.onCreate(savedInstanceState);
72         }
73     }
74 
75     /**
76      * Sometimes we want just the language for a locale, not the entire language
77      * tag. But Java's .getLanguage method is wrong.
78      *
79      * This method is equivalent to the first part of
80      * {@link Locales#getLanguageTag(Locale)}.
81      *
82      * @return a language string, such as "he" for the Hebrew locales.
83      */
getLanguage(final Locale locale)84     public static String getLanguage(final Locale locale) {
85         // Can, but should never be, an empty string.
86         final String language = locale.getLanguage();
87 
88         // Modernize certain language codes.
89         if (language.equals("iw")) {
90             return "he";
91         }
92 
93         if (language.equals("in")) {
94             return "id";
95         }
96 
97         if (language.equals("ji")) {
98             return "yi";
99         }
100 
101         return language;
102     }
103 
104     /**
105      * Gecko uses locale codes like "es-ES", whereas a Java {@link Locale}
106      * stringifies as "es_ES".
107      *
108      * This method approximates the Java 7 method
109      * <code>Locale#toLanguageTag()</code>.
110      *
111      * @return a locale string suitable for passing to Gecko.
112      */
getLanguageTag(final Locale locale)113     public static String getLanguageTag(final Locale locale) {
114         // If this were Java 7:
115         // return locale.toLanguageTag();
116 
117         final String language = getLanguage(locale);
118         final String country = locale.getCountry(); // Can be an empty string.
119         if (country.equals("")) {
120             return language;
121         }
122         return language + "-" + country;
123     }
124 
parseLocaleCode(final String localeCode)125     public static Locale parseLocaleCode(final String localeCode) {
126         int index;
127         if ((index = localeCode.indexOf('-')) != -1 ||
128             (index = localeCode.indexOf('_')) != -1) {
129             final String langCode = localeCode.substring(0, index);
130             final String countryCode = localeCode.substring(index + 1);
131             return new Locale(langCode, countryCode);
132         }
133 
134         return new Locale(localeCode);
135     }
136 }
137