diff options
6 files changed, 140 insertions, 14 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index f7e67673a..813f7d32f 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -42,6 +42,7 @@ public class BinaryDictionary extends Dictionary { private static final int TYPED_LETTER_MULTIPLIER = 2; + private static final BinaryDictionary sInstance = new BinaryDictionary(); private int mDicTypeId; private int mNativeDict; private long mDictLength; @@ -59,16 +60,24 @@ public class BinaryDictionary extends Dictionary { } } + private BinaryDictionary() { + } + /** - * Create a dictionary from a raw resource file + * Initialize a dictionary from a raw resource file * @param context application context for reading resources * @param resId the resource containing the raw binary dictionary + * @return initialized instance of BinaryDictionary */ - public BinaryDictionary(Context context, int resId, int dicTypeId) { - if (resId != 0) { - loadDictionary(context, resId); + public static BinaryDictionary initDictionary(Context context, int resId, int dicTypeId) { + synchronized (sInstance) { + sInstance.closeInternal(); + if (resId != 0) { + sInstance.loadDictionary(context, resId); + sInstance.mDicTypeId = dicTypeId; + } } - mDicTypeId = dicTypeId; + return sInstance; } private native int openNative(String sourceDir, long dictOffset, long dictSize, @@ -104,6 +113,8 @@ public class BinaryDictionary extends Dictionary { @Override public void getBigrams(final WordComposer codes, final CharSequence previousWord, final WordCallback callback, int[] nextLettersFrequencies) { + if (mNativeDict == 0) return; + char[] chars = previousWord.toString().toCharArray(); Arrays.fill(mOutputChars_bigrams, (char) 0); Arrays.fill(mFrequencies_bigrams, 0); @@ -135,6 +146,8 @@ public class BinaryDictionary extends Dictionary { @Override public void getWords(final WordComposer codes, final WordCallback callback, int[] nextLettersFrequencies) { + if (mNativeDict == 0) return; + final int codesSize = codes.size(); // Won't deal with really long words. if (codesSize > MAX_WORD_LENGTH - 1) return; @@ -179,6 +192,10 @@ public class BinaryDictionary extends Dictionary { @Override public synchronized void close() { + closeInternal(); + } + + private void closeInternal() { if (mNativeDict != 0) { closeNative(mNativeDict); mNativeDict = 0; @@ -188,7 +205,10 @@ public class BinaryDictionary extends Dictionary { @Override protected void finalize() throws Throwable { - close(); - super.finalize(); + try { + closeInternal(); + } finally { + super.finalize(); + } } } diff --git a/java/src/com/android/inputmethod/latin/InputLanguageSelection.java b/java/src/com/android/inputmethod/latin/InputLanguageSelection.java index faee38eda..a9f2c2c22 100644 --- a/java/src/com/android/inputmethod/latin/InputLanguageSelection.java +++ b/java/src/com/android/inputmethod/latin/InputLanguageSelection.java @@ -107,7 +107,7 @@ public class InputLanguageSelection extends PreferenceActivity { res.updateConfiguration(conf, res.getDisplayMetrics()); int mainDicResId = LatinIME.getMainDictionaryResourceId(res); - BinaryDictionary bd = new BinaryDictionary(this, mainDicResId, Suggest.DIC_MAIN); + BinaryDictionary bd = BinaryDictionary.initDictionary(this, mainDicResId, Suggest.DIC_MAIN); // Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of // 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words. diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index f04f3efe7..968495b8e 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -134,7 +134,7 @@ public class SubtypeSwitcher { private void updateEnabledSubtypes() { boolean foundCurrentSubtypeBecameDisabled = true; mAllEnabledSubtypesOfCurrentInputMethod = mImm.getEnabledInputMethodSubtypeList( - null, false); + null, true); mEnabledLanguagesOfCurrentInputMethod.clear(); mEnabledKeyboardSubtypesOfCurrentInputMethod.clear(); for (InputMethodSubtype ims: mAllEnabledSubtypesOfCurrentInputMethod) { diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 9ea9c2f3e..a8454b23e 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -103,7 +103,7 @@ public class Suggest implements Dictionary.WordCallback { private int mCorrectionMode = CORRECTION_BASIC; public Suggest(Context context, int dictionaryResId) { - mMainDict = new BinaryDictionary(context, dictionaryResId, DIC_MAIN); + mMainDict = BinaryDictionary.initDictionary(context, dictionaryResId, DIC_MAIN); initPool(); } @@ -127,7 +127,7 @@ public class Suggest implements Dictionary.WordCallback { } public boolean hasMainDictionary() { - return mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD; + return mMainDict != null && mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD; } public int getApproxMaxWordLength() { @@ -276,7 +276,7 @@ public class Suggest implements Dictionary.WordCallback { mHaveCorrection = true; } } - mMainDict.getWords(wordComposer, this, mNextLettersFrequencies); + if (mMainDict != null) mMainDict.getWords(wordComposer, this, mNextLettersFrequencies); if ((mCorrectionMode == CORRECTION_FULL || mCorrectionMode == CORRECTION_FULL_BIGRAM) && mSuggestions.size() > 0 && mPriorities.length > 0) { // TODO: when the normalized score of the first suggestion is nearly equals to @@ -496,7 +496,7 @@ public class Suggest implements Dictionary.WordCallback { } public boolean isValidWord(final CharSequence word) { - if (word == null || word.length() == 0) { + if (word == null || word.length() == 0 || mMainDict == null) { return false; } return mMainDict.isValidWord(word) diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 6e4e97138..25580f4b1 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -89,7 +89,7 @@ static jint latinime_BinaryDictionary_open(JNIEnv *env, jobject object, return 0; } dictBuf = malloc(sizeof(char) * dictSize); - if (dictBuf == NULL) { + if (!dictBuf) { LOGE("DICT: Can't allocate memory region for dictionary. errno=%d", errno); return 0; } diff --git a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java new file mode 100644 index 000000000..004ddb61a --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +import android.content.Context; +import android.content.res.Resources; +import android.test.AndroidTestCase; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public class SubtypeLocaleTests extends AndroidTestCase { + private static final String PACKAGE = LatinIME.class.getPackage().getName(); + + private Resources mRes; + private List<InputMethodSubtype> mKeyboardSubtypes; + + public interface Predicator<T> { + public boolean evaluate(T object); + } + + private static <T> List<T> filter(List<T> source, Predicator<? super T> predicator) { + final ArrayList<T> filtered = new ArrayList<T>(); + for (final T element : source) { + if (predicator.evaluate(element)) + filtered.add(element); + } + return filtered; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + final Context context = getContext(); + mRes = context.getResources(); + + SubtypeLocale.init(context); + + final InputMethodManager imm = (InputMethodManager) context.getSystemService( + Context.INPUT_METHOD_SERVICE); + for (final InputMethodInfo imi : imm.getInputMethodList()) { + if (imi.getPackageName().equals(PACKAGE)) { + mKeyboardSubtypes = filter(imi.getSubtypes(), + new Predicator<InputMethodSubtype>() { + @Override + public boolean evaluate(InputMethodSubtype ims) { + return ims.getMode().equals("keyboard"); + } + }); + break; + } + } + assertNotNull("Can not find input method " + PACKAGE, mKeyboardSubtypes); + assertTrue("Can not find keyboard subtype", mKeyboardSubtypes.size() > 0); + } + + // Copied from {@link java.junit.Assert#format(String, Object, Object)} + private static String format(String message, Object expected, Object actual) { + return message + " expected:<" + expected + "> but was:<" + actual + ">"; + } + + private String getStringWithLocale(int resId, Locale locale) { + final Locale savedLocale = Locale.getDefault(); + try { + Locale.setDefault(locale); + return mRes.getString(resId); + } finally { + Locale.setDefault(savedLocale); + } + } + + public void testSubtypeLocale() { + for (final InputMethodSubtype subtype : mKeyboardSubtypes) { + final String localeCode = subtype.getLocale(); + final Locale locale = new Locale(localeCode); + // The locale name which will be displayed on spacebar. For example 'English (US)' or + // 'Francais (Canada)'. (c=\u008d) + final String displayName = SubtypeLocale.getFullDisplayName(locale); + // The subtype name in its locale. For example 'English (US) Keyboard' or + // 'Clavier Francais (Canada)'. (c=\u008d) + final String subtypeName = getStringWithLocale(subtype.getNameResId(), locale); + assertTrue( + format("subtype display name of " + localeCode + ":", subtypeName, displayName), + subtypeName.contains(displayName)); + } + } +} |