diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
index 4d0f003805431aea658517e79a392990c39d2f41..0f3ae2f0702dc618f68c58f2bd30ff1041ed631b 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
@@ -31,7 +31,7 @@ import com.android.inputmethod.compat.InputTypeCompatUtils;
 import com.android.inputmethod.keyboard.KeyboardSet.Params.ElementParams;
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.LatinImeLogger;
-import com.android.inputmethod.latin.LocaleUtils;
+import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.StringUtils;
 import com.android.inputmethod.latin.XmlParseUtils;
@@ -66,6 +66,7 @@ public class KeyboardSet {
 
     public static class KeyboardSetException extends RuntimeException {
         public final KeyboardId mKeyboardId;
+
         public KeyboardSetException(Throwable cause, KeyboardId keyboardId) {
             super(cause);
             mKeyboardId = keyboardId;
@@ -161,26 +162,29 @@ public class KeyboardSet {
         }
     }
 
-    private Keyboard getKeyboard(Context context, ElementParams elementParams, KeyboardId id) {
-        final Resources res = context.getResources();
+    private Keyboard getKeyboard(Context context, ElementParams elementParams,
+            final KeyboardId id) {
         final SoftReference<Keyboard> ref = sKeyboardCache.get(id);
         Keyboard keyboard = (ref == null) ? null : ref.get();
         if (keyboard == null) {
-            final Locale savedLocale = LocaleUtils.setSystemLocale(res, id.mLocale);
-            try {
-                final Keyboard.Builder<Keyboard.Params> builder =
-                        new Keyboard.Builder<Keyboard.Params>(context, new Keyboard.Params());
-                if (id.isAlphabetKeyboard()) {
-                    builder.setAutoGenerate(sKeysCache);
-                }
-                builder.load(elementParams.mKeyboardXmlId, id);
-                builder.setTouchPositionCorrectionEnabled(mParams.mTouchPositionCorrectionEnabled);
-                builder.setProximityCharsCorrectionEnabled(
-                        elementParams.mProximityCharsCorrectionEnabled);
-                keyboard = builder.build();
-            } finally {
-                LocaleUtils.setSystemLocale(res, savedLocale);
+            final Keyboard.Builder<Keyboard.Params> builder =
+                    new Keyboard.Builder<Keyboard.Params>(mContext, new Keyboard.Params());
+            if (id.isAlphabetKeyboard()) {
+                builder.setAutoGenerate(sKeysCache);
             }
+            final int keyboardXmlId = elementParams.mKeyboardXmlId;
+            final RunInLocale<Void> job = new RunInLocale<Void>() {
+                @Override
+                protected Void job(Resources res) {
+                    builder.load(keyboardXmlId, id);
+                    return null;
+                }
+            };
+            job.runInLocale(context.getResources(), id.mLocale);
+            builder.setTouchPositionCorrectionEnabled(mParams.mTouchPositionCorrectionEnabled);
+            builder.setProximityCharsCorrectionEnabled(
+                    elementParams.mProximityCharsCorrectionEnabled);
+            keyboard = builder.build();
             sKeyboardCache.put(id, new SoftReference<Keyboard>(keyboard));
 
             if (DEBUG_CACHE) {
@@ -271,16 +275,20 @@ public class KeyboardSet {
             if (mParams.mLocale == null)
                 throw new RuntimeException("KeyboardSet subtype is not specified");
 
-            final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, mParams.mLocale);
-            try {
-                parseKeyboardSet(mResources, R.xml.keyboard_set);
-            } catch (Exception e) {
-                throw new RuntimeException(e.getMessage() + " in "
-                        + mResources.getResourceName(R.xml.keyboard_set)
-                        + " of locale " + mParams.mLocale);
-            } finally {
-                LocaleUtils.setSystemLocale(mResources, savedLocale);
-            }
+            final RunInLocale<Void> job = new RunInLocale<Void>() {
+                @Override
+                protected Void job(Resources res) {
+                    try {
+                        parseKeyboardSet(res, R.xml.keyboard_set);
+                    } catch (Exception e) {
+                        throw new RuntimeException(e.getMessage() + " in "
+                                + res.getResourceName(R.xml.keyboard_set)
+                                + " of locale " + mParams.mLocale);
+                    }
+                    return null;
+                }
+            };
+            job.runInLocale(mResources, mParams.mLocale);
             return new KeyboardSet(mContext, mParams);
         }
 
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index 1c24cd11d3241892c12f077d8913a129b56ac98a..e4d839690478f9950ce248a9ba51094eaad504c2 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -23,6 +23,8 @@ import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.util.Log;
 
+import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
+
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Locale;
@@ -154,11 +156,13 @@ class BinaryDictionaryGetter {
      */
     private static AssetFileAddress loadFallbackResource(final Context context,
             final int fallbackResId, final Locale locale) {
-        final Resources res = context.getResources();
-        final Locale savedLocale = LocaleUtils.setSystemLocale(res, locale);
-        final AssetFileDescriptor afd = res.openRawResourceFd(fallbackResId);
-        LocaleUtils.setSystemLocale(res, savedLocale);
-
+        final RunInLocale<AssetFileDescriptor> job = new RunInLocale<AssetFileDescriptor>() {
+            @Override
+            protected AssetFileDescriptor job(Resources res) {
+                return res.openRawResourceFd(fallbackResId);
+            }
+        };
+        final AssetFileDescriptor afd = job.runInLocale(context.getResources(), locale);
         if (afd == null) {
             Log.e(TAG, "Found the resource but cannot read it. Is it compressed? resId="
                     + fallbackResId);
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
index 77c685c504a2847d6ab0fe5ea5cb5295f63951d3..7be374db537a612b05cbce4b2c557683f105808f 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
@@ -21,6 +21,8 @@ import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.util.Log;
 
+import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
+
 import java.io.File;
 import java.util.ArrayList;
 import java.util.LinkedList;
@@ -30,7 +32,6 @@ import java.util.Locale;
  * Factory for dictionary instances.
  */
 public class DictionaryFactory {
-
     private static String TAG = DictionaryFactory.class.getSimpleName();
 
     /**
@@ -98,14 +99,13 @@ public class DictionaryFactory {
             final int resId, final Locale locale) {
         AssetFileDescriptor afd = null;
         try {
-            final Resources res = context.getResources();
-            if (null != locale) {
-                final Locale savedLocale = LocaleUtils.setSystemLocale(res, locale);
-                afd = res.openRawResourceFd(resId);
-                LocaleUtils.setSystemLocale(res, savedLocale);
-            } else {
-                afd = res.openRawResourceFd(resId);
-            }
+            final RunInLocale<AssetFileDescriptor> job = new RunInLocale<AssetFileDescriptor>() {
+                @Override
+                protected AssetFileDescriptor job(Resources res) {
+                    return res.openRawResourceFd(resId);
+                }
+            };
+            afd = job.runInLocale(context.getResources(), locale);
             if (afd == null) {
                 Log.e(TAG, "Found the resource but it is compressed. resId=" + resId);
                 return null;
@@ -161,39 +161,41 @@ public class DictionaryFactory {
      * @return whether a (non-placeholder) dictionary is available or not.
      */
     public static boolean isDictionaryAvailable(Context context, Locale locale) {
-        final Resources res = context.getResources();
-        final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale);
-
-        final int resourceId = getMainDictionaryResourceId(res);
-        final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
-        final boolean hasDictionary = isFullDictionary(afd);
-        try {
-            if (null != afd) afd.close();
-        } catch (java.io.IOException e) {
-            /* Um, what can we do here exactly? */
-        }
-
-        LocaleUtils.setSystemLocale(res, saveLocale);
-        return hasDictionary;
+        final RunInLocale<Boolean> job = new RunInLocale<Boolean>() {
+            @Override
+            protected Boolean job(Resources res) {
+                final int resourceId = getMainDictionaryResourceId(res);
+                final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
+                final boolean hasDictionary = isFullDictionary(afd);
+                try {
+                    if (null != afd) afd.close();
+                } catch (java.io.IOException e) {
+                    /* Um, what can we do here exactly? */
+                }
+                return hasDictionary;
+            }
+        };
+        return job.runInLocale(context.getResources(), locale);
     }
 
     // TODO: Do not use the size of the dictionary as an unique dictionary ID.
     public static Long getDictionaryId(final Context context, final Locale locale) {
-        final Resources res = context.getResources();
-        final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale);
-
-        final int resourceId = getMainDictionaryResourceId(res);
-        final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
-        final Long size = (afd != null && afd.getLength() > PLACEHOLDER_LENGTH)
-                ? afd.getLength()
-                : null;
-        try {
-            if (null != afd) afd.close();
-        } catch (java.io.IOException e) {
-        }
-
-        LocaleUtils.setSystemLocale(res, saveLocale);
-        return size;
+        final RunInLocale<Long> job = new RunInLocale<Long>() {
+            @Override
+            protected Long job(Resources res) {
+                final int resourceId = getMainDictionaryResourceId(res);
+                final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
+                final Long size = (afd != null && afd.getLength() > PLACEHOLDER_LENGTH)
+                        ? afd.getLength()
+                        : null;
+                try {
+                    if (null != afd) afd.close();
+                } catch (java.io.IOException e) {
+                }
+                return size;
+            }
+        };
+        return job.runInLocale(context.getResources(), locale);
     }
 
     // TODO: Find the Right Way to find out whether the resource is a placeholder or not.
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 177f5e629f2478b2810c733582e4c92954657043..1eb9c8d02e037f091c89381f4c00e15f2d6a590b 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -64,6 +64,7 @@ import com.android.inputmethod.keyboard.KeyboardId;
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
 import com.android.inputmethod.keyboard.KeyboardView;
 import com.android.inputmethod.keyboard.LatinKeyboardView;
+import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
 import com.android.inputmethod.latin.define.ProductionFlag;
 import com.android.inputmethod.latin.suggestions.SuggestionsView;
 
@@ -478,7 +479,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     // Has to be package-visible for unit tests
     /* package */ void loadSettings() {
         if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
-        mSettingsValues = new SettingsValues(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr());
+        final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() {
+            @Override
+            protected SettingsValues job(Resources res) {
+                return new SettingsValues(mPrefs, LatinIME.this);
+            }
+        };
+        mSettingsValues = job.runInLocale(mResources, mSubtypeSwitcher.getInputLocale());
         mFeedbackManager = new AudioAndHapticFeedbackManager(this, mSettingsValues);
         resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
     }
@@ -487,33 +494,37 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
         final Locale keyboardLocale = mSubtypeSwitcher.getInputLocale();
 
-        final Resources res = mResources;
-        final Locale savedLocale = LocaleUtils.setSystemLocale(res, keyboardLocale);
-        final ContactsDictionary oldContactsDictionary;
-        if (mSuggest != null) {
-            oldContactsDictionary = mSuggest.getContactsDictionary();
-            mSuggest.close();
-        } else {
-            oldContactsDictionary = null;
-        }
-
-        int mainDicResId = DictionaryFactory.getMainDictionaryResourceId(res);
-        mSuggest = new Suggest(this, mainDicResId, keyboardLocale);
-        if (mSettingsValues.mAutoCorrectEnabled) {
-            mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
-        }
+        final Context context = this;
+        final RunInLocale<Void> job = new RunInLocale<Void>() {
+            @Override
+            protected Void job(Resources res) {
+                final ContactsDictionary oldContactsDictionary;
+                if (mSuggest != null) {
+                    oldContactsDictionary = mSuggest.getContactsDictionary();
+                    mSuggest.close();
+                } else {
+                    oldContactsDictionary = null;
+                }
 
-        mUserDictionary = new UserDictionary(this, localeStr);
-        mSuggest.setUserDictionary(mUserDictionary);
-        mIsUserDictionaryAvailable = mUserDictionary.isEnabled();
+                int mainDicResId = DictionaryFactory.getMainDictionaryResourceId(res);
+                mSuggest = new Suggest(context, mainDicResId, keyboardLocale);
+                if (mSettingsValues.mAutoCorrectEnabled) {
+                    mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
+                }
 
-        resetContactsDictionary(oldContactsDictionary);
+                mUserDictionary = new UserDictionary(context, localeStr);
+                mSuggest.setUserDictionary(mUserDictionary);
+                mIsUserDictionaryAvailable = mUserDictionary.isEnabled();
 
-        mUserHistoryDictionary
-                = new UserHistoryDictionary(this, localeStr, Suggest.DIC_USER_HISTORY);
-        mSuggest.setUserHistoryDictionary(mUserHistoryDictionary);
+                resetContactsDictionary(oldContactsDictionary);
 
-        LocaleUtils.setSystemLocale(res, savedLocale);
+                mUserHistoryDictionary
+                    = new UserHistoryDictionary(context, localeStr, Suggest.DIC_USER_HISTORY);
+                mSuggest.setUserHistoryDictionary(mUserHistoryDictionary);
+                return null;
+            }
+        };
+        job.runInLocale(mResources, keyboardLocale);
     }
 
     /**
diff --git a/java/src/com/android/inputmethod/latin/LocaleUtils.java b/java/src/com/android/inputmethod/latin/LocaleUtils.java
index cf60089c5f388eb404a2f940fab19c51fe360ea6..f19c59a6a16fa80def88f08937ef69aab92da559 100644
--- a/java/src/com/android/inputmethod/latin/LocaleUtils.java
+++ b/java/src/com/android/inputmethod/latin/LocaleUtils.java
@@ -161,21 +161,36 @@ public class LocaleUtils {
         return LOCALE_MATCH <= level;
     }
 
-    /**
-     * Sets the system locale for this process.
-     *
-     * @param res the resources to use. Pass current resources.
-     * @param newLocale the locale to change to.
-     * @return the old locale.
-     */
-    public static synchronized Locale setSystemLocale(final Resources res, final Locale newLocale) {
-        final Configuration conf = res.getConfiguration();
-        final Locale oldLocale = conf.locale;
-        if (newLocale != null && !newLocale.equals(oldLocale)) {
-            conf.locale = newLocale;
-            res.updateConfiguration(conf, res.getDisplayMetrics());
+    static final Object sLockForRunInLocale = new Object();
+
+    public abstract static class RunInLocale<T> {
+        protected abstract T job(Resources res);
+
+        /**
+         * Execute {@link #job(Resources)} method in specified system locale exclusively.
+         *
+         * @param res the resources to use. Pass current resources.
+         * @param newLocale the locale to change to
+         * @return the value returned from {@link #job(Resources)}.
+         */
+        public T runInLocale(final Resources res, final Locale newLocale) {
+            synchronized (sLockForRunInLocale) {
+                final Configuration conf = res.getConfiguration();
+                final Locale oldLocale = conf.locale;
+                try {
+                    if (newLocale != null && !newLocale.equals(oldLocale)) {
+                        conf.locale = newLocale;
+                        res.updateConfiguration(conf, res.getDisplayMetrics());
+                    }
+                    return job(res);
+                } finally {
+                    if (newLocale != null && !newLocale.equals(oldLocale)) {
+                        conf.locale = oldLocale;
+                        res.updateConfiguration(conf, res.getDisplayMetrics());
+                    }
+                }
+            }
         }
-        return oldLocale;
     }
 
     private static final HashMap<String, Locale> sLocaleCache = new HashMap<String, Locale>();
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index f76cc7e448591620b5c520589465e9cdfb309cfc..f2abb9c206f4b44c69e089672fc7622f205daf82 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -25,12 +25,14 @@ import android.view.inputmethod.EditorInfo;
 import com.android.inputmethod.compat.InputTypeCompatUtils;
 import com.android.inputmethod.keyboard.internal.KeySpecParser;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.VibratorUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Locale;
 
+/**
+ * When you call the constructor of this class, you may want to change the current system locale by
+ * using {@link LocaleUtils.RunInLocale}.
+ */
 public class SettingsValues {
     private static final String TAG = SettingsValues.class.getSimpleName();
 
@@ -78,16 +80,8 @@ public class SettingsValues {
     private final boolean mVoiceKeyEnabled;
     private final boolean mVoiceKeyOnMain;
 
-    public SettingsValues(final SharedPreferences prefs, final Context context,
-            final String localeStr) {
+    public SettingsValues(final SharedPreferences prefs, final Context context) {
         final Resources res = context.getResources();
-        final Locale savedLocale;
-        if (null != localeStr) {
-            final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr);
-            savedLocale = LocaleUtils.setSystemLocale(res, keyboardLocale);
-        } else {
-            savedLocale = null;
-        }
 
         // Get the resources
         mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions);
@@ -152,8 +146,6 @@ public class SettingsValues {
                 mAutoCorrectionThresholdRawValue);
         mVoiceKeyEnabled = mVoiceMode != null && !mVoiceMode.equals(voiceModeOff);
         mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain);
-
-        LocaleUtils.setSystemLocale(res, savedLocale);
     }
 
     // Helper functions to create member values.
diff --git a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
index a90ef290bc5169f776014c516c2c82f19fe64784..7bb30766209e6d312f3d6d609c2637010b2d8231 100644
--- a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
+++ b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
@@ -22,6 +22,8 @@ import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 
+import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
+
 import java.util.HashMap;
 import java.util.Locale;
 
@@ -36,10 +38,14 @@ public class WhitelistDictionary extends ExpandableDictionary {
     // TODO: Conform to the async load contact of ExpandableDictionary
     public WhitelistDictionary(final Context context, final Locale locale) {
         super(context, Suggest.DIC_WHITELIST);
-        final Resources res = context.getResources();
-        final Locale previousLocale = LocaleUtils.setSystemLocale(res, locale);
-        initWordlist(res.getStringArray(R.array.wordlist_whitelist));
-        LocaleUtils.setSystemLocale(res, previousLocale);
+        final RunInLocale<Void> job = new RunInLocale<Void>() {
+            @Override
+            protected Void job(Resources res) {
+                initWordlist(res.getStringArray(R.array.wordlist_whitelist));
+                return null;
+            }
+        };
+        job.runInLocale(context.getResources(), locale);
     }
 
     private void initWordlist(String[] wordlist) {