aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTadashi G. Takaoka <takaoka@google.com>2012-04-03 14:28:56 +0900
committerTadashi G. Takaoka <takaoka@google.com>2012-04-03 17:43:45 +0900
commit16c6f355700ee5cdaa029f4a25b8b3d40718e6ab (patch)
treeb3863cd867379b6f3a1c15b19c16364d3b44676e
parent78e333594bbc97e56ad105ce3888192e78771626 (diff)
downloadlatinime-16c6f355700ee5cdaa029f4a25b8b3d40718e6ab.tar.gz
latinime-16c6f355700ee5cdaa029f4a25b8b3d40718e6ab.tar.xz
latinime-16c6f355700ee5cdaa029f4a25b8b3d40718e6ab.zip
Add RunInLocale class to guard locale switching
Bug: 6128216 Change-Id: I8d9c75c773c3de886183b291ada7a3836295839b
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSet.java62
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java14
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFactory.java78
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java59
-rw-r--r--java/src/com/android/inputmethod/latin/LocaleUtils.java43
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsValues.java18
-rw-r--r--java/src/com/android/inputmethod/latin/WhitelistDictionary.java14
7 files changed, 163 insertions, 125 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
index 4d0f00380..0f3ae2f07 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 1c24cd11d..e4d839690 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 77c685c50..7be374db5 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 177f5e629..1eb9c8d02 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 cf60089c5..f19c59a6a 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 f76cc7e44..f2abb9c20 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 a90ef290b..7bb307662 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) {