Bug 970176 - Part 1: rework LocaleManager to simplify use from android-sync. r=nalexander
authorRichard Newman <rnewman@mozilla.com>
Tue, 15 Apr 2014 15:07:14 -0700
changeset 197086 4667003549589d566cd218f7aa903250d97b3cd2
parent 197085 b2c7cadebd0f57e99f00a068d997025991b3946b
child 197087 661f96cbf4cef409e3805d3dc29a418d62b87204
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnalexander
bugs970176
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 970176 - Part 1: rework LocaleManager to simplify use from android-sync. r=nalexander
mobile/android/base/BrowserLocaleManager.java
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoApplication.java
mobile/android/base/LocaleManager.java
mobile/android/base/moz.build
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/BrowserLocaleManager.java
@@ -0,0 +1,285 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.util.Log;
+
+import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * This class manages persistence, application, and otherwise handling of
+ * user-specified locales.
+ *
+ * Of note:
+ *
+ * * It's a singleton, because its scope extends to that of the application,
+ *   and definitionally all changes to the locale of the app must go through
+ *   this.
+ * * It's lazy.
+ * * It has ties into the Gecko event system, because it has to tell Gecko when
+ *   to switch locale.
+ * * It relies on using the SharedPreferences file owned by the browser (in
+ *   Fennec's case, "GeckoApp") for performance.
+ */
+public class BrowserLocaleManager implements LocaleManager {
+    private static final String LOG_TAG = "GeckoLocales";
+
+    private static final String EVENT_LOCALE_CHANGED = "Locale:Changed";
+    private static final String PREF_LOCALE = "locale";
+
+    // This is volatile because we don't impose restrictions
+    // over which thread calls our methods.
+    private volatile Locale currentLocale = null;
+
+    private AtomicBoolean inited = new AtomicBoolean(false);
+    private boolean systemLocaleDidChange = false;
+    private BroadcastReceiver receiver;
+
+    private static AtomicReference<LocaleManager> instance = new AtomicReference<LocaleManager>();
+
+    public static LocaleManager getInstance() {
+        LocaleManager localeManager = instance.get();
+        if (localeManager != null) {
+            return localeManager;
+        }
+
+        localeManager = new BrowserLocaleManager();
+        if (instance.compareAndSet(null, localeManager)) {
+            return localeManager;
+        } else {
+            return instance.get();
+        }
+    }
+
+    /**
+     * Gecko uses locale codes like "es-ES", whereas a Java {@link Locale}
+     * stringifies as "es_ES".
+     *
+     * This method approximates the Java 7 method <code>Locale#toLanguageTag()</code>.
+     *
+     * @return a locale string suitable for passing to Gecko.
+     */
+    public static String getLanguageTag(final Locale locale) {
+        // If this were Java 7:
+        // return locale.toLanguageTag();
+
+        String language = locale.getLanguage();  // Can, but should never be, an empty string.
+        // Modernize certain language codes.
+        if (language.equals("iw")) {
+            language = "he";
+        } else if (language.equals("in")) {
+            language = "id";
+        } else if (language.equals("ji")) {
+            language = "yi";
+        }
+
+        String country = locale.getCountry();    // Can be an empty string.
+        if (country.equals("")) {
+            return language;
+        }
+        return language + "-" + country;
+    }
+
+    private static Locale parseLocaleCode(final String localeCode) {
+        int index;
+        if ((index = localeCode.indexOf('-')) != -1 ||
+            (index = localeCode.indexOf('_')) != -1) {
+            final String langCode = localeCode.substring(0, index);
+            final String countryCode = localeCode.substring(index + 1);
+            return new Locale(langCode, countryCode);
+        } else {
+            return new Locale(localeCode);
+        }
+    }
+
+    /**
+     * Ensure that you call this early in your application startup,
+     * and with a context that's sufficiently long-lived (typically
+     * the application context).
+     *
+     * Calling multiple times is harmless.
+     */
+    @Override
+    public void initialize(final Context context) {
+        if (!inited.compareAndSet(false, true)) {
+            return;
+        }
+
+        receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                systemLocaleDidChange = true;
+            }
+        };
+        context.registerReceiver(receiver, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
+    }
+
+    @Override
+    public boolean systemLocaleDidChange() {
+        return systemLocaleDidChange;
+    }
+
+    /**
+     * Every time the system gives us a new configuration, it
+     * carries the external locale. Fix it.
+     */
+    @Override
+    public void correctLocale(Context context, Resources res, Configuration config) {
+        final Locale current = getCurrentLocale(context);
+        if (current == null) {
+            return;
+        }
+
+        // I know it's tempting to short-circuit here if the config seems to be
+        // up-to-date, but the rest is necessary.
+
+        config.locale = current;
+
+        // The following two lines are heavily commented in case someone
+        // decides to chase down performance improvements and decides to
+        // question what's going on here.
+        // Both lines should be cheap, *but*...
+
+        // This is unnecessary for basic string choice, but it almost
+        // certainly comes into play when rendering numbers, deciding on RTL,
+        // etc. Take it out if you can prove that's not the case.
+        Locale.setDefault(current);
+
+        // This seems to be a no-op, but every piece of documentation under the
+        // sun suggests that it's necessary, and it certainly makes sense.
+        res.updateConfiguration(config, res.getDisplayMetrics());
+    }
+
+    @Override
+    public String getAndApplyPersistedLocale(Context context) {
+        initialize(context);
+
+        final long t1 = android.os.SystemClock.uptimeMillis();
+        final String localeCode = getPersistedLocale(context);
+        if (localeCode == null) {
+            return null;
+        }
+
+        // Note that we don't tell Gecko about this. We notify Gecko when the
+        // locale is set, not when we update Java.
+        final String resultant = updateLocale(context, localeCode);
+
+        if (resultant == null) {
+            // Update the configuration anyway.
+            updateConfiguration(context, currentLocale);
+        }
+
+        final long t2 = android.os.SystemClock.uptimeMillis();
+        Log.i(LOG_TAG, "Locale read and update took: " + (t2 - t1) + "ms.");
+        return resultant;
+    }
+
+    /**
+     * Returns the set locale if it changed.
+     *
+     * Always persists and notifies Gecko.
+     */
+    @Override
+    public String setSelectedLocale(Context context, String localeCode) {
+        final String resultant = updateLocale(context, localeCode);
+
+        // We always persist and notify Gecko, even if nothing seemed to
+        // change. This might happen if you're picking a locale that's the same
+        // as the current OS locale. The OS locale might change next time we
+        // launch, and we need the Gecko pref and persisted locale to have been
+        // set by the time that happens.
+        persistLocale(context, localeCode);
+
+        // Tell Gecko.
+        GeckoEvent ev = GeckoEvent.createBroadcastEvent(EVENT_LOCALE_CHANGED, BrowserLocaleManager.getLanguageTag(getCurrentLocale(context)));
+        GeckoAppShell.sendEventToGecko(ev);
+
+        return resultant;
+    }
+
+    /**
+     * This is public to allow for an activity to force the
+     * current locale to be applied if necessary (e.g., when
+     * a new activity launches).
+     */
+    @Override
+    public void updateConfiguration(Context context, Locale locale) {
+        Resources res = context.getResources();
+        Configuration config = res.getConfiguration();
+        config.locale = locale;
+        res.updateConfiguration(config, res.getDisplayMetrics());
+    }
+
+    private SharedPreferences getSharedPreferences(Context context) {
+        return GeckoSharedPrefs.forApp(context);
+    }
+
+    private String getPersistedLocale(Context context) {
+        final SharedPreferences settings = getSharedPreferences(context);
+        final String locale = settings.getString(PREF_LOCALE, "");
+
+        if ("".equals(locale)) {
+            return null;
+        }
+        return locale;
+    }
+
+    private void persistLocale(Context context, String localeCode) {
+        final SharedPreferences settings = getSharedPreferences(context);
+        settings.edit().putString(PREF_LOCALE, localeCode).commit();
+    }
+
+    private Locale getCurrentLocale(Context context) {
+        if (currentLocale != null) {
+            return currentLocale;
+        }
+
+        final String current = getPersistedLocale(context);
+        if (current == null) {
+            return null;
+        }
+        return currentLocale = parseLocaleCode(current);
+    }
+
+    /**
+     * Updates the Java locale and the Android configuration.
+     *
+     * Returns the persisted locale if it differed.
+     *
+     * Does not notify Gecko.
+     */
+    private String updateLocale(Context context, String localeCode) {
+        // Fast path.
+        final Locale defaultLocale = Locale.getDefault();
+        if (defaultLocale.toString().equals(localeCode)) {
+            return null;
+        }
+
+        final Locale locale = parseLocaleCode(localeCode);
+
+        // Fast path.
+        if (defaultLocale.equals(locale)) {
+            return null;
+        }
+
+        Locale.setDefault(locale);
+        currentLocale = locale;
+
+        // Update resources.
+        updateConfiguration(context, locale);
+
+        return locale.toString();
+    }
+}
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -1253,17 +1253,17 @@ public abstract class GeckoApp
             Log.e(LOGTAG, "Exception starting favicon cache. Corrupt resources?", e);
         }
 
         // Did the OS locale change while we were backgrounded? If so,
         // we need to die so that Gecko will re-init add-ons that touch
         // the UI.
         // This is using a sledgehammer to crack a nut, but it'll do for
         // now.
-        if (LocaleManager.systemLocaleDidChange()) {
+        if (BrowserLocaleManager.getInstance().systemLocaleDidChange()) {
             Log.i(LOGTAG, "System locale changed. Restarting.");
             doRestart();
             GeckoAppShell.systemExit();
             return;
         }
 
         if (GeckoThread.isCreated()) {
             // This happens when the GeckoApp activity is destroyed by Android
@@ -1331,18 +1331,18 @@ public abstract class GeckoApp
 
         // Perform background initialization.
         ThreadUtils.postToBackgroundThread(new Runnable() {
             @Override
             public void run() {
                 final SharedPreferences prefs = GeckoApp.this.getSharedPreferences();
 
                 // Wait until now to set this, because we'd rather throw an exception than 
-                // have a caller of LocaleManager regress startup.
-                LocaleManager.initialize(getApplicationContext());
+                // have a caller of BrowserLocaleManager regress startup.
+                BrowserLocaleManager.getInstance().initialize(getApplicationContext());
 
                 SessionInformation previousSession = SessionInformation.fromSharedPrefs(prefs);
                 if (previousSession.wasKilled()) {
                     Telemetry.HistogramAdd("FENNEC_WAS_KILLED", 1);
                 }
 
                 SharedPreferences.Editor editor = prefs.edit();
                 editor.putBoolean(GeckoApp.PREFS_OOM_EXCEPTION, false);
@@ -1356,17 +1356,17 @@ public abstract class GeckoApp
                 // The lifecycle of mHealthRecorder is "shortly after onCreate"
                 // through "onDestroy" -- essentially the same as the lifecycle
                 // of the activity itself.
                 final String profilePath = getProfile().getDir().getAbsolutePath();
                 final EventDispatcher dispatcher = GeckoAppShell.getEventDispatcher();
                 Log.i(LOGTAG, "Creating HealthRecorder.");
 
                 final String osLocale = Locale.getDefault().toString();
-                String appLocale = LocaleManager.getAndApplyPersistedLocale(GeckoApp.this);
+                String appLocale = BrowserLocaleManager.getInstance().getAndApplyPersistedLocale(GeckoApp.this);
                 Log.d(LOGTAG, "OS locale is " + osLocale + ", app locale is " + appLocale);
 
                 if (appLocale == null) {
                     appLocale = osLocale;
                 }
 
                 mHealthRecorder = GeckoApp.this.createHealthRecorder(GeckoApp.this,
                                                                      profilePath,
@@ -2204,17 +2204,17 @@ public abstract class GeckoApp
         for (File file : files) {
             file.delete();
         }
     }
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         Log.d(LOGTAG, "onConfigurationChanged: " + newConfig.locale);
-        LocaleManager.correctLocale(this, getResources(), newConfig);
+        BrowserLocaleManager.getInstance().correctLocale(this, getResources(), newConfig);
 
         // onConfigurationChanged is not called for 180 degree orientation changes,
         // we will miss such rotations and the screen orientation will not be
         // updated.
         if (GeckoScreenOrientation.getInstance().update(newConfig.orientation)) {
             if (mFormAssistPopup != null)
                 mFormAssistPopup.hide();
             refreshChrome();
@@ -2796,24 +2796,24 @@ public abstract class GeckoApp
         // return (flags & android.content.pm.ApplicationInfo.FLAG_DEBUGGABLE) != 0;
     }
 
     // FHR reason code for a session end prior to a restart for a
     // locale change.
     private static final String SESSION_END_LOCALE_CHANGED = "L";
 
     /**
-     * Use LocaleManager to change our persisted and current locales,
+     * Use BrowserLocaleManager to change our persisted and current locales,
      * and poke HealthRecorder to tell it of our changed state.
      */
     private void setLocale(final String locale) {
         if (locale == null) {
             return;
         }
-        final String resultant = LocaleManager.setSelectedLocale(this, locale);
+        final String resultant = BrowserLocaleManager.getInstance().setSelectedLocale(this, locale);
         if (resultant == null) {
             return;
         }
 
         final boolean startNewSession = true;
         final boolean shouldRestart = false;
 
         // If the HealthRecorder is not yet initialized (unlikely), the locale change won't
--- a/mobile/android/base/GeckoApplication.java
+++ b/mobile/android/base/GeckoApplication.java
@@ -62,19 +62,19 @@ public class GeckoApplication extends Ap
         if (mInBackground) {
             super.onConfigurationChanged(config);
             return;
         }
 
         // Otherwise, correct the locale. This catches some cases that GeckoApp
         // doesn't get a chance to.
         try {
-            LocaleManager.correctLocale(this, getResources(), config);
+            BrowserLocaleManager.getInstance().correctLocale(this, getResources(), config);
         } catch (IllegalStateException ex) {
-            // GeckoApp hasn't started, so we have no ContextGetter in LocaleManager.
+            // GeckoApp hasn't started, so we have no ContextGetter in BrowserLocaleManager.
             Log.w(LOG_TAG, "Couldn't correct locale.", ex);
         }
 
         super.onConfigurationChanged(config);
     }
 
     public void onActivityPause(GeckoActivityStatus activity) {
         mInBackground = true;
--- a/mobile/android/base/LocaleManager.java
+++ b/mobile/android/base/LocaleManager.java
@@ -1,248 +1,20 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.util.Log;
-
 import java.util.Locale;
 
-/**
- * This class manages persistence, application, and otherwise handling of
- * user-specified locales.
- *
- * Of note:
- * 
- * * It's a singleton, because its scope extends to that of the application,
- *   and definitionally all changes to the locale of the app must go through
- *   this.
- * * It's lazy.
- * * It has ties into the Gecko event system, because it has to tell Gecko when
- *   to switch locale.
- * * It relies on using the SharedPreferences file owned by the browser (in
- *   Fennec's case, "GeckoApp") for performance.
- */
-public class LocaleManager {
-    private static final String LOG_TAG = "GeckoLocales";
-    private static final String PREF_LOCALE = "locale";
-
-    // This is volatile because we don't impose restrictions
-    // over which thread calls our methods.
-    private static volatile Locale currentLocale = null;
-
-    private static volatile boolean inited = false;
-    private static boolean systemLocaleDidChange = false;
-    private static BroadcastReceiver receiver;
-
-    /**
-     * Ensure that you call this early in your application startup,
-     * and with a context that's sufficiently long-lived (typically
-     * the application context).
-     *
-     * Calling multiple times is harmless.
-     */
-    public static void initialize(final Context context) {
-        if (inited) {
-            return;
-        }
-
-        receiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                systemLocaleDidChange = true;
-            }
-        };
-        context.registerReceiver(receiver, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
-        inited = true;
-    }
-
-    public static boolean systemLocaleDidChange() {
-        return systemLocaleDidChange;
-    }
-
-    /**
-     * Every time the system gives us a new configuration, it
-     * carries the external locale. Fix it.
-     */
-    public static void correctLocale(Context context, Resources res, Configuration config) {
-        final Locale current = getCurrentLocale(context);
-        if (current == null) {
-            return;
-        }
-
-        // I know it's tempting to short-circuit here if the config seems to be
-        // up-to-date, but the rest is necessary.
-
-        config.locale = current;
-
-        // The following two lines are heavily commented in case someone
-        // decides to chase down performance improvements and decides to
-        // question what's going on here.
-        // Both lines should be cheap, *but*...
-
-        // This is unnecessary for basic string choice, but it almost
-        // certainly comes into play when rendering numbers, deciding on RTL,
-        // etc. Take it out if you can prove that's not the case.
-        Locale.setDefault(current);
-
-        // This seems to be a no-op, but every piece of documentation under the
-        // sun suggests that it's necessary, and it certainly makes sense.
-        res.updateConfiguration(config, res.getDisplayMetrics());
-    }
-
-    private static Locale parseLocaleCode(final String localeCode) {
-        int index;
-        if ((index = localeCode.indexOf('-')) != -1 ||
-            (index = localeCode.indexOf('_')) != -1) {
-            final String langCode = localeCode.substring(0, index);
-            final String countryCode = localeCode.substring(index + 1);
-            return new Locale(langCode, countryCode);
-        } else {
-            return new Locale(localeCode);
-        }
-    }
-
-    /**
-     * Gecko uses locale codes like "es-ES", whereas a Java {@link Locale}
-     * stringifies as "es_ES".
-     *
-     * This method approximates the Java 7 method <code>Locale#toLanguageTag()</code>.
-     *
-     * @return a locale string suitable for passing to Gecko.
-     */
-    public static String getLanguageTag(final Locale locale) {
-        // If this were Java 7:
-        // return locale.toLanguageTag();
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
 
-        String language = locale.getLanguage();  // Can, but should never be, an empty string.
-        // Modernize certain language codes.
-        if (language.equals("iw")) {
-            language = "he";
-        } else if (language.equals("in")) {
-            language = "id";
-        } else if (language.equals("ji")) {
-            language = "yi";
-        }
-
-        String country = locale.getCountry();    // Can be an empty string.
-        if (country.equals("")) {
-            return language;
-        }
-        return language + "-" + country;
-    }
-
-    public static Locale getCurrentLocale(Context context) {
-        if (currentLocale != null) {
-            return currentLocale;
-        }
-
-        final String current = getPersistedLocale(context);
-        if (current == null) {
-            return null;
-        }
-        return currentLocale = parseLocaleCode(current);
-    }
-
-    /**
-     * Updates the Java locale and the Android configuration.
-     *
-     * Returns the persisted locale if it differed.
-     *
-     * Does not notify Gecko.
-     */
-    private static String updateLocale(Context context, String localeCode) {
-        // Fast path.
-        final Locale defaultLocale = Locale.getDefault();
-        if (defaultLocale.toString().equals(localeCode)) {
-            return null;
-        }
-
-        final Locale locale = parseLocaleCode(localeCode);
-
-        // Fast path.
-        if (defaultLocale.equals(locale)) {
-            return null;
-        }
-
-        Locale.setDefault(locale);
-        currentLocale = locale;
-
-        // Update resources.
-        Resources res = context.getResources();
-        Configuration config = res.getConfiguration();
-        config.locale = locale;
-        res.updateConfiguration(config, res.getDisplayMetrics());
-
-        return locale.toString();
-    }
-
-    public static void notifyGeckoOfLocaleChange(Locale locale) {
-        // Tell Gecko.
-        GeckoEvent ev = GeckoEvent.createBroadcastEvent("Locale:Changed", getLanguageTag(locale));
-        GeckoAppShell.sendEventToGecko(ev);
-    }
-
-    public static String getPersistedLocale(Context context) {
-        final SharedPreferences settings = getSharedPreferences(context);
-        final String locale = settings.getString(PREF_LOCALE, "");
-
-        if ("".equals(locale)) {
-            return null;
-        }
-        return locale;
-    }
-
-    private static void persistLocale(Context context, String localeCode) {
-        final SharedPreferences settings = getSharedPreferences(context);
-        settings.edit().putString(PREF_LOCALE, localeCode).commit();
-    }
-
-    private static SharedPreferences getSharedPreferences(Context context) {
-        // TODO: this should be per-profile, but we don't want to pay the price.
-        return GeckoSharedPrefs.forApp(context);
-    }
-
-    public static String getAndApplyPersistedLocale(Context context) {
-        final long t1 = android.os.SystemClock.uptimeMillis();
-        final String localeCode = getPersistedLocale(context);
-        if (localeCode == null) {
-            return null;
-        }
-
-        // Note that we don't tell Gecko about this. We notify Gecko when the
-        // locale is set, not when we update Java.
-        final String resultant = updateLocale(context, localeCode);
-
-        final long t2 = android.os.SystemClock.uptimeMillis();
-        Log.i(LOG_TAG, "Locale read and update took: " + (t2 - t1) + "ms.");
-        return resultant;
-    }
-
-    /**
-     * Returns the set locale if it changed.
-     *
-     * Always persists and notifies Gecko.
-     */
-    public static String setSelectedLocale(Context context, String localeCode) {
-        final String resultant = updateLocale(context, localeCode);
-
-        // We always persist and notify Gecko, even if nothing seemed to
-        // change. This might happen if you're picking a locale that's the same
-        // as the current OS locale. The OS locale might change next time we
-        // launch, and we need the Gecko pref and persisted locale to have been
-        // set by the time that happens.
-        persistLocale(context, localeCode);
-        notifyGeckoOfLocaleChange(getCurrentLocale(context));
-        return resultant;
-    }
+public interface LocaleManager {
+    void initialize(Context context);
+    String getAndApplyPersistedLocale(Context context);
+    void correctLocale(Context context, Resources resources, Configuration newConfig);
+    void updateConfiguration(Context context, Locale locale);
+    String setSelectedLocale(Context context, String localeCode);
+    boolean systemLocaleDidChange();
 }
-
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -113,16 +113,17 @@ gbjar.sources += [
     'animation/HeightChangeAnimation.java',
     'animation/PropertyAnimator.java',
     'animation/Rotate3DAnimation.java',
     'animation/ViewHelper.java',
     'ANRReporter.java',
     'AppNotificationClient.java',
     'BaseGeckoInterface.java',
     'BrowserApp.java',
+    'BrowserLocaleManager.java',
     'ContactService.java',
     'ContextGetter.java',
     'CustomEditText.java',
     'DataReportingNotification.java',
     'db/AbstractPerProfileDatabaseProvider.java',
     'db/AbstractTransactionalProvider.java',
     'db/BrowserContract.java',
     'db/BrowserDatabaseHelper.java',