From 107fb4c476779df16be23e245547253978c197ac Mon Sep 17 00:00:00 2001 From: Dan Zivkovic Date: Wed, 11 Mar 2015 16:11:50 -0700 Subject: [PATCH] Remove ALS from LatinIME. This fixes unit tests and brings us closer to a green build. Change-Id: Iffcc392eda4a7671a238b79cc7367320ca648725 --- .../touchinputconsumer/GestureConsumer.java | 7 +- .../com/android/inputmethod/keyboard/Key.java | 2 +- .../inputmethod/keyboard/KeyboardId.java | 6 +- .../keyboard/KeyboardSwitcher.java | 3 +- .../keyboard/MainKeyboardView.java | 9 - .../keyboard/internal/KeyboardBuilder.java | 28 +- .../latin/DictionaryFacilitator.java | 26 +- .../latin/DictionaryFacilitatorImpl.java | 451 ++++++------------ .../latin/DictionaryFacilitatorLruCache.java | 4 +- .../android/inputmethod/latin/LatinIME.java | 53 +- .../latin/RichInputMethodManager.java | 6 +- .../latin/RichInputMethodSubtype.java | 25 +- .../android/inputmethod/latin/Suggest.java | 13 +- .../latin/inputlogic/InputLogic.java | 5 - .../latin/utils/LanguageOnSpacebarUtils.java | 18 +- .../latin/BinaryDictionaryTests.java | 21 - .../DictionaryFacilitatorLruCacheTests.java | 20 +- .../latin/FusionDictionaryTests.java | 56 --- .../latin/RichInputMethodSubtypeTests.java | 22 +- .../utils/LanguageOnSpacebarUtilsTests.java | 2 +- .../latin/utils/SubtypeLocaleUtilsTests.java | 19 +- 21 files changed, 247 insertions(+), 549 deletions(-) delete mode 100644 tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java diff --git a/java-overridable/src/com/android/inputmethod/latin/touchinputconsumer/GestureConsumer.java b/java-overridable/src/com/android/inputmethod/latin/touchinputconsumer/GestureConsumer.java index 4a44aaa94..7a5d2e68f 100644 --- a/java-overridable/src/com/android/inputmethod/latin/touchinputconsumer/GestureConsumer.java +++ b/java-overridable/src/com/android/inputmethod/latin/touchinputconsumer/GestureConsumer.java @@ -23,7 +23,6 @@ import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.common.InputPointers; import com.android.inputmethod.latin.inputlogic.PrivateCommandPerformer; -import java.util.List; import java.util.Locale; /** @@ -39,7 +38,7 @@ public class GestureConsumer { public static GestureConsumer newInstance( final EditorInfo editorInfo, final PrivateCommandPerformer commandPerformer, - final List locales, final Keyboard keyboard) { + final Locale locale, final Keyboard keyboard) { return GestureConsumer.NULL_GESTURE_CONSUMER; } @@ -50,10 +49,10 @@ public class GestureConsumer { return false; } - public void onInit(final List locales, final Keyboard keyboard) { + public void onInit(final Locale locale, final Keyboard keyboard) { } - public void onGestureStarted(final List locales, final Keyboard keyboard) { + public void onGestureStarted(final Locale locale, final Keyboard keyboard) { } public void onGestureCanceled() { diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index d1db3d4c5..299d1b7c5 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -287,7 +287,7 @@ public class Key implements Comparable { mLabelFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags) | row.getDefaultKeyLabelFlags(); final boolean needsToUpcase = needsToUpcase(mLabelFlags, params.mId.mElementId); - final Locale localeForUpcasing = params.mId.getLocales()[0]; + final Locale localeForUpcasing = params.mId.getLocale(); int actionFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyActionFlags); String[] moreKeys = style.getStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys); diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index d43bf37cb..a1f7bf0e1 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -164,8 +164,8 @@ public final class KeyboardId { return InputTypeUtils.getImeOptionsActionIdFromEditorInfo(mEditorInfo); } - public Locale[] getLocales() { - return mSubtype.getLocales(); + public Locale getLocale() { + return mSubtype.getLocale(); } @Override @@ -182,7 +182,7 @@ public final class KeyboardId { public String toString() { return String.format(Locale.ROOT, "[%s %s:%s %dx%d %s %s%s%s%s%s%s%s%s%s]", elementIdToName(mElementId), - Arrays.deepToString(mSubtype.getLocales()), + mSubtype.getLocale(), mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET), mWidth, mHeight, modeName(mMode), diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index fca5ecbc0..92e5dfceb 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -121,8 +121,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { mKeyboardLayoutSet = builder.build(); try { mState.onLoadKeyboard(currentAutoCapsState, currentRecapitalizeState); - // TODO: revisit this for multi-lingual input - mKeyboardTextsSet.setLocale(mRichImm.getCurrentSubtypeLocales()[0], mThemeContext); + mKeyboardTextsSet.setLocale(mRichImm.getCurrentSubtypeLocale(), mThemeContext); } catch (KeyboardLayoutSetException e) { Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause()); } diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index ce4bb7454..00d4fa236 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -843,15 +843,6 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy // Layout language name on spacebar. private String layoutLanguageOnSpacebar(final Paint paint, final RichInputMethodSubtype subtype, final int width) { - if (mLanguageOnSpacebarFormatType == LanguageOnSpacebarUtils.FORMAT_TYPE_MULTIPLE) { - final Locale[] locales = subtype.getLocales(); - final String[] languages = new String[locales.length]; - for (int i = 0; i < locales.length; ++i) { - languages[i] = locales[i].getLanguage().toUpperCase(Locale.ROOT); - } - return TextUtils.join(" / ", languages); - } - // Choose appropriate language name to fit into the width. if (mLanguageOnSpacebarFormatType == LanguageOnSpacebarUtils.FORMAT_TYPE_FULL_LOCALE) { final String fullText = subtype.getFullDisplayName(); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java index 2b07e1d46..0eabf6cc9 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java @@ -281,8 +281,7 @@ public class KeyboardBuilder { params.mThemeId = keyboardAttr.getInt(R.styleable.Keyboard_themeId, 0); params.mIconsSet.loadIcons(keyboardAttr); - // TODO: this needs to be revisited for multi-lingual input. - params.mTextsSet.setLocale(params.mId.getLocales()[0], mContext); + params.mTextsSet.setLocale(params.mId.getLocale(), mContext); final int resourceId = keyboardAttr.getResourceId( R.styleable.Keyboard_touchPositionCorrectionData, 0); @@ -673,10 +672,10 @@ public class KeyboardBuilder { R.styleable.Keyboard_Case_imeAction, id.imeAction()); final boolean isIconDefinedMatched = isIconDefined(caseAttr, R.styleable.Keyboard_Case_isIconDefined, mParams.mIconsSet); - final Locale[] locales = id.getLocales(); - final boolean localeCodeMatched = matchLocaleCodes(caseAttr, locales); - final boolean languageCodeMatched = matchLanguageCodes(caseAttr, locales); - final boolean countryCodeMatched = matchCountryCodes(caseAttr, locales); + final Locale locale = id.getLocale(); + final boolean localeCodeMatched = matchLocaleCodes(caseAttr, locale); + final boolean languageCodeMatched = matchLanguageCodes(caseAttr, locale); + final boolean countryCodeMatched = matchCountryCodes(caseAttr, locale); final boolean splitLayoutMatched = matchBoolean(caseAttr, R.styleable.Keyboard_Case_isSplitLayout, id.mIsSplitLayout); final boolean selected = keyboardLayoutSetMatched && keyboardLayoutSetElementMatched @@ -732,21 +731,16 @@ public class KeyboardBuilder { } } - private static boolean matchLocaleCodes(TypedArray caseAttr, final Locale[] locales) { - // TODO: adujst this for multilingual input - return matchString(caseAttr, R.styleable.Keyboard_Case_localeCode, locales[0].toString()); + private static boolean matchLocaleCodes(TypedArray caseAttr, final Locale locale) { + return matchString(caseAttr, R.styleable.Keyboard_Case_localeCode, locale.toString()); } - private static boolean matchLanguageCodes(TypedArray caseAttr, Locale[] locales) { - // TODO: adujst this for multilingual input - return matchString(caseAttr, R.styleable.Keyboard_Case_languageCode, - locales[0].getLanguage()); + private static boolean matchLanguageCodes(TypedArray caseAttr, Locale locale) { + return matchString(caseAttr, R.styleable.Keyboard_Case_languageCode, locale.getLanguage()); } - private static boolean matchCountryCodes(TypedArray caseAttr, Locale[] locales) { - // TODO: adujst this for multilingual input - return matchString(caseAttr, R.styleable.Keyboard_Case_countryCode, - locales[0].getCountry()); + private static boolean matchCountryCodes(TypedArray caseAttr, Locale locale) { + return matchString(caseAttr, R.styleable.Keyboard_Case_countryCode, locale.getCountry()); } private static boolean matchInteger(final TypedArray a, final int index, final int value) { diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java index b65888997..5f981a009 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java @@ -72,11 +72,11 @@ public interface DictionaryFacilitator { Dictionary.TYPE_CONTACTS}; /** - * Returns whether this facilitator is exactly for this list of locales. + * Returns whether this facilitator is exactly for this locale. * - * @param locales the list of locales to test against + * @param locale the locale to test against */ - boolean isForLocales(final Locale[] locales); + boolean isForLocale(final Locale locale); /** * Returns whether this facilitator is exactly for this account. @@ -91,25 +91,11 @@ public interface DictionaryFacilitator { boolean isActive(); - /** - * Returns the most probable locale among all currently active locales. BE CAREFUL using this. - * - * DO NOT USE THIS just because it's convenient. Use it when it's correct, for example when - * choosing what dictionary to put a word in, or when changing the capitalization of a typed - * string. - * @return the most probable locale - */ - Locale getMostProbableLocale(); - - Locale[] getLocales(); - - void switchMostProbableLanguage(@Nullable final Locale locale); - - boolean isConfidentAboutCurrentLanguageBeing(final Locale mLocale); + Locale getLocale(); void resetDictionaries( final Context context, - final Locale[] newLocales, + final Locale newLocale, final boolean useContactsDict, final boolean usePersonalizedDicts, final boolean forceReloadMainDictionary, @@ -120,7 +106,7 @@ public interface DictionaryFacilitator { @UsedForTesting void resetDictionariesForTesting( final Context context, - final Locale[] locales, + final Locale locale, final ArrayList dictionaryTypes, final HashMap dictionaryFiles, final Map> additionalDictAttributes, diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java index e0b0b2b7e..2f3c58251 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java @@ -63,12 +63,8 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { // HACK: This threshold is being used when adding a capitalized entry in the User History // dictionary. private static final int CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT = 140; - // How many words we need to type in a row ({@see mConfidenceInMostProbableLanguage}) to - // declare we are confident the user is typing in the most probable language. - private static final int CONFIDENCE_THRESHOLD = 3; - private DictionaryGroup[] mDictionaryGroups = new DictionaryGroup[] { new DictionaryGroup() }; - private DictionaryGroup mMostProbableDictionaryGroup = mDictionaryGroups[0]; + private DictionaryGroup mDictionaryGroup = new DictionaryGroup(); private volatile CountDownLatch mLatchForWaitingLoadingMainDictionaries = new CountDownLatch(0); // To synchronize assigning mDictionaryGroup to ensure closing dictionaries. private final Object mLock = new Object(); @@ -86,28 +82,9 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { private static final Class[] DICT_FACTORY_METHOD_ARG_TYPES = new Class[] { Context.class, Locale.class, File.class, String.class, String.class }; - /** - * Returns whether this facilitator is exactly for this list of locales. - * - * @param locales the list of locales to test against - */ - public boolean isForLocales(final Locale[] locales) { - if (locales.length != mDictionaryGroups.length) { - return false; - } - for (final Locale locale : locales) { - boolean found = false; - for (final DictionaryGroup group : mDictionaryGroups) { - if (locale.equals(group.mLocale)) { - found = true; - break; - } - } - if (!found) { - return false; - } - } - return true; + @Override + public boolean isForLocale(final Locale locale) { + return locale != null && locale.equals(mDictionaryGroup.mLocale); } /** @@ -116,12 +93,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { * @param account the account to test against. */ public boolean isForAccount(@Nullable final String account) { - for (final DictionaryGroup group : mDictionaryGroups) { - if (!TextUtils.equals(group.mAccount, account)) { - return false; - } - } - return true; + return TextUtils.equals(mDictionaryGroup.mAccount, account); } /** @@ -231,75 +203,12 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { } public boolean isActive() { - return null != mDictionaryGroups[0].mLocale; + return mDictionaryGroup.mLocale != null; } - /** - * Returns the most probable locale among all currently active locales. BE CAREFUL using this. - * - * DO NOT USE THIS just because it's convenient. Use it when it's correct, for example when - * choosing what dictionary to put a word in, or when changing the capitalization of a typed - * string. - * @return the most probable locale - */ - public Locale getMostProbableLocale() { - return getDictionaryGroupForMostProbableLanguage().mLocale; - } - - public Locale[] getLocales() { - final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; - final Locale[] locales = new Locale[dictionaryGroups.length]; - for (int i = 0; i < dictionaryGroups.length; ++i) { - locales[i] = dictionaryGroups[i].mLocale; - } - return locales; - } - - private DictionaryGroup getDictionaryGroupForMostProbableLanguage() { - return mMostProbableDictionaryGroup; - } - - public void switchMostProbableLanguage(@Nullable final Locale locale) { - if (null == locale) { - // In many cases, there is no locale to a committed word. For example, a typed word - // that is in none of the currently active dictionaries but still does not - // auto-correct to anything has no locale. In this case we simply do not change - // the most probable language and do not touch confidence. - return; - } - final DictionaryGroup newMostProbableDictionaryGroup = - findDictionaryGroupWithLocale(mDictionaryGroups, locale); - if (null == newMostProbableDictionaryGroup) { - // It seems this may happen as a race condition; pressing the globe key and space - // in quick succession could commit a word out of a dictionary that's not in the - // facilitator any more. In this case, just not changing things is fine. - return; - } - if (newMostProbableDictionaryGroup == mMostProbableDictionaryGroup) { - ++newMostProbableDictionaryGroup.mConfidence; - } else { - mMostProbableDictionaryGroup.mWeightForTypingInLocale = - DictionaryGroup.WEIGHT_FOR_TYPING_IN_NOT_MOST_PROBABLE_LANGUAGE; - mMostProbableDictionaryGroup.mWeightForGesturingInLocale = - DictionaryGroup.WEIGHT_FOR_GESTURING_IN_NOT_MOST_PROBABLE_LANGUAGE; - mMostProbableDictionaryGroup.mConfidence = 0; - newMostProbableDictionaryGroup.mWeightForTypingInLocale = - DictionaryGroup.WEIGHT_FOR_MOST_PROBABLE_LANGUAGE; - newMostProbableDictionaryGroup.mWeightForGesturingInLocale = - DictionaryGroup.WEIGHT_FOR_MOST_PROBABLE_LANGUAGE; - mMostProbableDictionaryGroup = newMostProbableDictionaryGroup; - } - } - - public boolean isConfidentAboutCurrentLanguageBeing(final Locale mLocale) { - final DictionaryGroup mostProbableDictionaryGroup = mMostProbableDictionaryGroup; - if (!mostProbableDictionaryGroup.mLocale.equals(mLocale)) { - return false; - } - if (mDictionaryGroups.length <= 1) { - return true; - } - return mostProbableDictionaryGroup.mConfidence >= CONFIDENCE_THRESHOLD; + @Override + public Locale getLocale() { + return mDictionaryGroup.mLocale; } @Nullable @@ -325,19 +234,15 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { } @Nullable - static DictionaryGroup findDictionaryGroupWithLocale(final DictionaryGroup[] dictionaryGroups, + static DictionaryGroup findDictionaryGroupWithLocale(final DictionaryGroup dictionaryGroup, final Locale locale) { - for (DictionaryGroup dictionaryGroup : dictionaryGroups) { - if (locale.equals(dictionaryGroup.mLocale)) { - return dictionaryGroup; - } - } - return null; + return locale.equals(dictionaryGroup.mLocale) ? dictionaryGroup : null; } + @Override public void resetDictionaries( final Context context, - final Locale[] newLocales, + final Locale newLocale, final boolean useContactsDict, final boolean usePersonalizedDicts, final boolean forceReloadMainDictionary, @@ -356,14 +261,11 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { } // Gather all dictionaries. We'll remove them from the list to clean up later. - for (final Locale newLocale : newLocales) { - final ArrayList dictTypeForLocale = new ArrayList<>(); - existingDictionariesToCleanup.put(newLocale, dictTypeForLocale); - final DictionaryGroup currentDictionaryGroupForLocale = - findDictionaryGroupWithLocale(mDictionaryGroups, newLocale); - if (null == currentDictionaryGroupForLocale) { - continue; - } + final ArrayList dictTypeForLocale = new ArrayList<>(); + existingDictionariesToCleanup.put(newLocale, dictTypeForLocale); + final DictionaryGroup currentDictionaryGroupForLocale = + findDictionaryGroupWithLocale(mDictionaryGroup, newLocale); + if (currentDictionaryGroupForLocale != null) { for (final String dictType : DYNAMIC_DICTIONARY_TYPES) { if (currentDictionaryGroupForLocale.hasDict(dictType, account)) { dictTypeForLocale.add(dictType); @@ -374,50 +276,46 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { } } - final DictionaryGroup[] newDictionaryGroups = new DictionaryGroup[newLocales.length]; - for (int i = 0; i < newLocales.length; ++i) { - final Locale newLocale = newLocales[i]; - final DictionaryGroup dictionaryGroupForLocale = - findDictionaryGroupWithLocale(mDictionaryGroups, newLocale); - final ArrayList dictTypesToCleanupForLocale = - existingDictionariesToCleanup.get(newLocale); - final boolean noExistingDictsForThisLocale = (null == dictionaryGroupForLocale); + final DictionaryGroup dictionaryGroupForLocale = + findDictionaryGroupWithLocale(mDictionaryGroup, newLocale); + final ArrayList dictTypesToCleanupForLocale = + existingDictionariesToCleanup.get(newLocale); + final boolean noExistingDictsForThisLocale = (null == dictionaryGroupForLocale); - final Dictionary mainDict; - if (forceReloadMainDictionary || noExistingDictsForThisLocale - || !dictionaryGroupForLocale.hasDict(Dictionary.TYPE_MAIN, account)) { - mainDict = null; - } else { - mainDict = dictionaryGroupForLocale.getDict(Dictionary.TYPE_MAIN); - dictTypesToCleanupForLocale.remove(Dictionary.TYPE_MAIN); - } - - final Map subDicts = new HashMap<>(); - for (final String subDictType : subDictTypesToUse) { - final ExpandableBinaryDictionary subDict; - if (noExistingDictsForThisLocale - || !dictionaryGroupForLocale.hasDict(subDictType, account)) { - // Create a new dictionary. - subDict = getSubDict(subDictType, context, newLocale, null /* dictFile */, - dictNamePrefix, account); - } else { - // Reuse the existing dictionary, and don't close it at the end - subDict = dictionaryGroupForLocale.getSubDict(subDictType); - dictTypesToCleanupForLocale.remove(subDictType); - } - subDicts.put(subDictType, subDict); - } - newDictionaryGroups[i] = new DictionaryGroup(newLocale, mainDict, account, subDicts); + final Dictionary mainDict; + if (forceReloadMainDictionary || noExistingDictsForThisLocale + || !dictionaryGroupForLocale.hasDict(Dictionary.TYPE_MAIN, account)) { + mainDict = null; + } else { + mainDict = dictionaryGroupForLocale.getDict(Dictionary.TYPE_MAIN); + dictTypesToCleanupForLocale.remove(Dictionary.TYPE_MAIN); } + final Map subDicts = new HashMap<>(); + for (final String subDictType : subDictTypesToUse) { + final ExpandableBinaryDictionary subDict; + if (noExistingDictsForThisLocale + || !dictionaryGroupForLocale.hasDict(subDictType, account)) { + // Create a new dictionary. + subDict = getSubDict(subDictType, context, newLocale, null /* dictFile */, + dictNamePrefix, account); + } else { + // Reuse the existing dictionary, and don't close it at the end + subDict = dictionaryGroupForLocale.getSubDict(subDictType); + dictTypesToCleanupForLocale.remove(subDictType); + } + subDicts.put(subDictType, subDict); + } + DictionaryGroup newDictionaryGroup = + new DictionaryGroup(newLocale, mainDict, account, subDicts); + // Replace Dictionaries. - final DictionaryGroup[] oldDictionaryGroups; + final DictionaryGroup oldDictionaryGroup; synchronized (mLock) { - oldDictionaryGroups = mDictionaryGroups; - mDictionaryGroups = newDictionaryGroups; - mMostProbableDictionaryGroup = newDictionaryGroups[0]; + oldDictionaryGroup = mDictionaryGroup; + mDictionaryGroup = newDictionaryGroup; if (hasAtLeastOneUninitializedMainDictionary()) { - asyncReloadUninitializedMainDictionaries(context, newLocales, listener); + asyncReloadUninitializedMainDictionaries(context, newLocale, listener); } } if (listener != null) { @@ -429,7 +327,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { final ArrayList dictTypesToCleanUp = existingDictionariesToCleanup.get(localeToCleanUp); final DictionaryGroup dictionarySetToCleanup = - findDictionaryGroupWithLocale(oldDictionaryGroups, localeToCleanUp); + findDictionaryGroupWithLocale(oldDictionaryGroup, localeToCleanUp); for (final String dictType : dictTypesToCleanUp) { dictionarySetToCleanup.closeDict(dictType); } @@ -437,123 +335,105 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { } private void asyncReloadUninitializedMainDictionaries(final Context context, - final Locale[] locales, final DictionaryInitializationListener listener) { + final Locale locale, final DictionaryInitializationListener listener) { final CountDownLatch latchForWaitingLoadingMainDictionary = new CountDownLatch(1); mLatchForWaitingLoadingMainDictionaries = latchForWaitingLoadingMainDictionary; ExecutorUtils.getBackgroundExecutor().execute(new Runnable() { @Override public void run() { doReloadUninitializedMainDictionaries( - context, locales, listener, latchForWaitingLoadingMainDictionary); + context, locale, listener, latchForWaitingLoadingMainDictionary); } }); } - void doReloadUninitializedMainDictionaries(final Context context, final Locale[] locales, + void doReloadUninitializedMainDictionaries(final Context context, final Locale locale, final DictionaryInitializationListener listener, final CountDownLatch latchForWaitingLoadingMainDictionary) { - for (final Locale locale : locales) { - final DictionaryGroup dictionaryGroup = - findDictionaryGroupWithLocale(mDictionaryGroups, locale); - if (null == dictionaryGroup) { - // This should never happen, but better safe than crashy - Log.w(TAG, "Expected a dictionary group for " + locale + " but none found"); - continue; - } - final Dictionary mainDict = - DictionaryFactory.createMainDictionaryFromManager(context, locale); - synchronized (mLock) { - if (locale.equals(dictionaryGroup.mLocale)) { - dictionaryGroup.setMainDict(mainDict); - } else { - // Dictionary facilitator has been reset for another locale. - mainDict.close(); - } + final DictionaryGroup dictionaryGroup = + findDictionaryGroupWithLocale(mDictionaryGroup, locale); + if (null == dictionaryGroup) { + // This should never happen, but better safe than crashy + Log.w(TAG, "Expected a dictionary group for " + locale + " but none found"); + return; + } + final Dictionary mainDict = + DictionaryFactory.createMainDictionaryFromManager(context, locale); + synchronized (mLock) { + if (locale.equals(dictionaryGroup.mLocale)) { + dictionaryGroup.setMainDict(mainDict); + } else { + // Dictionary facilitator has been reset for another locale. + mainDict.close(); } } if (listener != null) { - listener.onUpdateMainDictionaryAvailability( - hasAtLeastOneInitializedMainDictionary()); + listener.onUpdateMainDictionaryAvailability(hasAtLeastOneInitializedMainDictionary()); } latchForWaitingLoadingMainDictionary.countDown(); } @UsedForTesting - public void resetDictionariesForTesting(final Context context, final Locale[] locales, + public void resetDictionariesForTesting(final Context context, final Locale locale, final ArrayList dictionaryTypes, final HashMap dictionaryFiles, final Map> additionalDictAttributes, @Nullable final String account) { Dictionary mainDictionary = null; final Map subDicts = new HashMap<>(); - final DictionaryGroup[] dictionaryGroups = new DictionaryGroup[locales.length]; - for (int i = 0; i < locales.length; ++i) { - final Locale locale = locales[i]; - for (final String dictType : dictionaryTypes) { - if (dictType.equals(Dictionary.TYPE_MAIN)) { - mainDictionary = DictionaryFactory.createMainDictionaryFromManager(context, - locale); - } else { - final File dictFile = dictionaryFiles.get(dictType); - final ExpandableBinaryDictionary dict = getSubDict( - dictType, context, locale, dictFile, "" /* dictNamePrefix */, account); - if (additionalDictAttributes.containsKey(dictType)) { - dict.clearAndFlushDictionaryWithAdditionalAttributes( - additionalDictAttributes.get(dictType)); - } - if (dict == null) { - throw new RuntimeException("Unknown dictionary type: " + dictType); - } - dict.reloadDictionaryIfRequired(); - dict.waitAllTasksForTests(); - subDicts.put(dictType, dict); + for (final String dictType : dictionaryTypes) { + if (dictType.equals(Dictionary.TYPE_MAIN)) { + mainDictionary = DictionaryFactory.createMainDictionaryFromManager(context, + locale); + } else { + final File dictFile = dictionaryFiles.get(dictType); + final ExpandableBinaryDictionary dict = getSubDict( + dictType, context, locale, dictFile, "" /* dictNamePrefix */, account); + if (additionalDictAttributes.containsKey(dictType)) { + dict.clearAndFlushDictionaryWithAdditionalAttributes( + additionalDictAttributes.get(dictType)); } + if (dict == null) { + throw new RuntimeException("Unknown dictionary type: " + dictType); + } + dict.reloadDictionaryIfRequired(); + dict.waitAllTasksForTests(); + subDicts.put(dictType, dict); } - dictionaryGroups[i] = new DictionaryGroup(locale, mainDictionary, account, subDicts); } - mDictionaryGroups = dictionaryGroups; - mMostProbableDictionaryGroup = dictionaryGroups[0]; + mDictionaryGroup = new DictionaryGroup(locale, mainDictionary, account, subDicts); } public void closeDictionaries() { - final DictionaryGroup[] dictionaryGroups; + final DictionaryGroup dictionaryGroupToClose; synchronized (mLock) { - dictionaryGroups = mDictionaryGroups; - mMostProbableDictionaryGroup = new DictionaryGroup(); - mDictionaryGroups = new DictionaryGroup[] { mMostProbableDictionaryGroup }; + dictionaryGroupToClose = mDictionaryGroup; + mDictionaryGroup = new DictionaryGroup(); } - for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - for (final String dictType : ALL_DICTIONARY_TYPES) { - dictionaryGroup.closeDict(dictType); - } + for (final String dictType : ALL_DICTIONARY_TYPES) { + dictionaryGroupToClose.closeDict(dictType); } } @UsedForTesting public ExpandableBinaryDictionary getSubDictForTesting(final String dictName) { - return mMostProbableDictionaryGroup.getSubDict(dictName); + return mDictionaryGroup.getSubDict(dictName); } // The main dictionaries are loaded asynchronously. Don't cache the return value // of these methods. public boolean hasAtLeastOneInitializedMainDictionary() { - final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; - for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - final Dictionary mainDict = dictionaryGroup.getDict(Dictionary.TYPE_MAIN); - if (mainDict != null && mainDict.isInitialized()) { - return true; - } + final Dictionary mainDict = mDictionaryGroup.getDict(Dictionary.TYPE_MAIN); + if (mainDict != null && mainDict.isInitialized()) { + return true; } return false; } public boolean hasAtLeastOneUninitializedMainDictionary() { - final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; - for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - final Dictionary mainDict = dictionaryGroup.getDict(Dictionary.TYPE_MAIN); - if (mainDict == null || !mainDict.isInitialized()) { - return true; - } + final Dictionary mainDict = mDictionaryGroup.getDict(Dictionary.TYPE_MAIN); + if (mainDict == null || !mainDict.isInitialized()) { + return true; } return false; } @@ -567,25 +447,22 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { public void waitForLoadingDictionariesForTesting(final long timeout, final TimeUnit unit) throws InterruptedException { waitForLoadingMainDictionaries(timeout, unit); - final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; - for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - for (final ExpandableBinaryDictionary dict : dictionaryGroup.mSubDictMap.values()) { - dict.waitAllTasksForTests(); - } + for (final ExpandableBinaryDictionary dict : mDictionaryGroup.mSubDictMap.values()) { + dict.waitAllTasksForTests(); } } public void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized, @Nonnull final NgramContext ngramContext, final long timeStampInSeconds, final boolean blockPotentiallyOffensive) { - final DictionaryGroup dictionaryGroup = getDictionaryGroupForMostProbableLanguage(); final String[] words = suggestion.split(Constants.WORD_SEPARATOR); NgramContext ngramContextForCurrentWord = ngramContext; for (int i = 0; i < words.length; i++) { final String currentWord = words[i]; final boolean wasCurrentWordAutoCapitalized = (i == 0) ? wasAutoCapitalized : false; - addWordToUserHistory(dictionaryGroup, ngramContextForCurrentWord, currentWord, - wasCurrentWordAutoCapitalized, (int) timeStampInSeconds, blockPotentiallyOffensive); + addWordToUserHistory(mDictionaryGroup, ngramContextForCurrentWord, currentWord, + wasCurrentWordAutoCapitalized, (int) timeStampInSeconds, + blockPotentiallyOffensive); ngramContextForCurrentWord = ngramContextForCurrentWord.getNextNgramContext(new WordInfo(currentWord)); } @@ -596,8 +473,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { final int timeStampInSeconds, final boolean blockPotentiallyOffensive) { final ExpandableBinaryDictionary userHistoryDictionary = dictionaryGroup.getSubDict(Dictionary.TYPE_USER_HISTORY); - if (userHistoryDictionary == null - || !isConfidentAboutCurrentLanguageBeing(userHistoryDictionary.mLocale)) { + if (userHistoryDictionary == null || !isForLocale(userHistoryDictionary.mLocale)) { return; } final int maxFreq = getFrequency(word); @@ -644,8 +520,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { } private void removeWord(final String dictName, final String word) { - final ExpandableBinaryDictionary dictionary = - getDictionaryGroupForMostProbableLanguage().getSubDict(dictName); + final ExpandableBinaryDictionary dictionary = mDictionaryGroup.getSubDict(dictName); if (dictionary != null) { dictionary.removeUnigramEntryDynamically(word); } @@ -668,28 +543,25 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { SettingsValuesForSuggestion settingsValuesForSuggestion, int sessionId, int inputStyle) { long proximityInfoHandle = keyboard.getProximityInfo().getNativeProximityInfo(); - final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; final SuggestionResults suggestionResults = new SuggestionResults( SuggestedWords.MAX_SUGGESTIONS, ngramContext.isBeginningOfSentenceContext(), false /* firstSuggestionExceedsConfidenceThreshold */); final float[] weightOfLangModelVsSpatialModel = new float[] { Dictionary.NOT_A_WEIGHT_OF_LANG_MODEL_VS_SPATIAL_MODEL }; - for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - for (final String dictType : DICTIONARY_TYPES_FOR_SUGGESTIONS) { - final Dictionary dictionary = dictionaryGroup.getDict(dictType); - if (null == dictionary) continue; - final float weightForLocale = composedData.mIsBatchMode - ? dictionaryGroup.mWeightForGesturingInLocale - : dictionaryGroup.mWeightForTypingInLocale; - final ArrayList dictionarySuggestions = - dictionary.getSuggestions(composedData, ngramContext, - proximityInfoHandle, settingsValuesForSuggestion, sessionId, - weightForLocale, weightOfLangModelVsSpatialModel); - if (null == dictionarySuggestions) continue; - suggestionResults.addAll(dictionarySuggestions); - if (null != suggestionResults.mRawSuggestions) { - suggestionResults.mRawSuggestions.addAll(dictionarySuggestions); - } + for (final String dictType : DICTIONARY_TYPES_FOR_SUGGESTIONS) { + final Dictionary dictionary = mDictionaryGroup.getDict(dictType); + if (null == dictionary) continue; + final float weightForLocale = composedData.mIsBatchMode + ? mDictionaryGroup.mWeightForGesturingInLocale + : mDictionaryGroup.mWeightForTypingInLocale; + final ArrayList dictionarySuggestions = + dictionary.getSuggestions(composedData, ngramContext, + proximityInfoHandle, settingsValuesForSuggestion, sessionId, + weightForLocale, weightOfLangModelVsSpatialModel); + if (null == dictionarySuggestions) continue; + suggestionResults.addAll(dictionarySuggestions); + if (null != suggestionResults.mRawSuggestions) { + suggestionResults.mRawSuggestions.addAll(dictionarySuggestions); } } return suggestionResults; @@ -707,20 +579,17 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { if (TextUtils.isEmpty(word)) { return false; } - final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; - for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - if (dictionaryGroup.mLocale == null) { - continue; - } - for (final String dictType : dictionariesToCheck) { - final Dictionary dictionary = dictionaryGroup.getDict(dictType); - // Ideally the passed map would come out of a {@link java.util.concurrent.Future} and - // would be immutable once it's finished initializing, but concretely a null test is - // probably good enough for the time being. - if (null == dictionary) continue; - if (dictionary.isValidWord(word)) { - return true; - } + if (mDictionaryGroup.mLocale == null) { + return false; + } + for (final String dictType : dictionariesToCheck) { + final Dictionary dictionary = mDictionaryGroup.getDict(dictType); + // Ideally the passed map would come out of a {@link java.util.concurrent.Future} and + // would be immutable once it's finished initializing, but concretely a null test is + // probably good enough for the time being. + if (null == dictionary) continue; + if (dictionary.isValidWord(word)) { + return true; } } return false; @@ -731,27 +600,21 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { return Dictionary.NOT_A_PROBABILITY; } int maxFreq = Dictionary.NOT_A_PROBABILITY; - final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; - for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - for (final String dictType : ALL_DICTIONARY_TYPES) { - final Dictionary dictionary = dictionaryGroup.getDict(dictType); - if (dictionary == null) continue; - final int tempFreq = dictionary.getFrequency(word); - if (tempFreq >= maxFreq) { - maxFreq = tempFreq; - } + for (final String dictType : ALL_DICTIONARY_TYPES) { + final Dictionary dictionary = mDictionaryGroup.getDict(dictType); + if (dictionary == null) continue; + final int tempFreq = dictionary.getFrequency(word); + if (tempFreq >= maxFreq) { + maxFreq = tempFreq; } } return maxFreq; } private void clearSubDictionary(final String dictName) { - final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; - for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - final ExpandableBinaryDictionary dictionary = dictionaryGroup.getSubDict(dictName); - if (dictionary != null) { - dictionary.clear(); - } + final ExpandableBinaryDictionary dictionary = mDictionaryGroup.getSubDict(dictName); + if (dictionary != null) { + dictionary.clear(); } } @@ -762,28 +625,22 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { @Override public void dumpDictionaryForDebug(final String dictName) { - final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; - for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - final ExpandableBinaryDictionary dictToDump = dictionaryGroup.getSubDict(dictName); - if (dictToDump == null) { - Log.e(TAG, "Cannot dump " + dictName + ". " - + "The dictionary is not being used for suggestion or cannot be dumped."); - return; - } - dictToDump.dumpAllWordsForDebug(); + final ExpandableBinaryDictionary dictToDump = mDictionaryGroup.getSubDict(dictName); + if (dictToDump == null) { + Log.e(TAG, "Cannot dump " + dictName + ". " + + "The dictionary is not being used for suggestion or cannot be dumped."); + return; } + dictToDump.dumpAllWordsForDebug(); } @Override public ArrayList> getStatsOfEnabledSubDicts() { final ArrayList> statsOfEnabledSubDicts = new ArrayList<>(); - final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; - for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - for (final String dictType : DYNAMIC_DICTIONARY_TYPES) { - final ExpandableBinaryDictionary dictionary = dictionaryGroup.getSubDict(dictType); - if (dictionary == null) continue; - statsOfEnabledSubDicts.add(new Pair<>(dictType, dictionary.getDictionaryStats())); - } + for (final String dictType : DYNAMIC_DICTIONARY_TYPES) { + final ExpandableBinaryDictionary dictionary = mDictionaryGroup.getSubDict(dictType); + if (dictionary == null) continue; + statsOfEnabledSubDicts.add(new Pair<>(dictType, dictionary.getDictionaryStats())); } return statsOfEnabledSubDicts; } diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java index 2a1ae3684..cbaf6ea4e 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java @@ -68,7 +68,7 @@ public class DictionaryFacilitatorLruCache { // Nothing to do if the locale is null. This would be the case before any get() calls. if (mLocale != null) { // Note: Given that personalized dictionaries are not used here; we can pass null account. - mDictionaryFacilitator.resetDictionaries(mContext, new Locale[]{mLocale}, + mDictionaryFacilitator.resetDictionaries(mContext, mLocale, mUseContactsDictionary, false /* usePersonalizedDicts */, false /* forceReloadMainDictionary */, null /* account */, mDictionaryNamePrefix, null /* listener */); @@ -89,7 +89,7 @@ public class DictionaryFacilitatorLruCache { public DictionaryFacilitator get(final Locale locale) { synchronized (mLock) { - if (!mDictionaryFacilitator.isForLocales(new Locale[]{locale})) { + if (!mDictionaryFacilitator.isForLocale(locale)) { mLocale = locale; resetDictionariesForLocaleLocked(); } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 4ae47f377..a0e55c65f 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -588,19 +588,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Has to be package-visible for unit tests @UsedForTesting void loadSettings() { - final Locale[] locales = mRichImm.getCurrentSubtypeLocales(); + final Locale locale = mRichImm.getCurrentSubtypeLocale(); final EditorInfo editorInfo = getCurrentInputEditorInfo(); final InputAttributes inputAttributes = new InputAttributes( editorInfo, isFullscreenMode(), getPackageName()); - // TODO: pass the array instead - mSettings.loadSettings(this, locales[0], inputAttributes); + mSettings.loadSettings(this, locale, inputAttributes); final SettingsValues currentSettingsValues = mSettings.getCurrent(); AudioAndHapticFeedbackManager.getInstance().onSettingsChanged(currentSettingsValues); // This method is called on startup and language switch, before the new layout has // been displayed. Opening dictionaries never affects responsivity as dictionaries are // asynchronously loaded. if (!mHandler.hasPendingReopenDictionaries()) { - resetDictionaryFacilitator(locales); + resetDictionaryFacilitator(locale); } refreshPersonalizationDictionarySession(currentSettingsValues); resetDictionaryFacilitatorIfNecessary(); @@ -630,35 +629,35 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } void resetDictionaryFacilitatorIfNecessary() { - final Locale[] subtypeSwitcherLocales = mRichImm.getCurrentSubtypeLocales(); - if (mDictionaryFacilitator.isForLocales(subtypeSwitcherLocales) - && mDictionaryFacilitator.isForAccount(mSettings.getCurrent().mAccount)) { - return; - } - final Locale[] subtypeLocales; - if (0 == subtypeSwitcherLocales.length) { + final Locale subtypeSwitcherLocale = mRichImm.getCurrentSubtypeLocale(); + final Locale subtypeLocale; + if (subtypeSwitcherLocale == null) { // This happens in very rare corner cases - for example, immediately after a switch // to LatinIME has been requested, about a frame later another switch happens. In this // case, we are about to go down but we still don't know it, however the system tells // us there is no current subtype. Log.e(TAG, "System is reporting no current subtype."); - subtypeLocales = new Locale[] { getResources().getConfiguration().locale }; + subtypeLocale = getResources().getConfiguration().locale; } else { - subtypeLocales = subtypeSwitcherLocales; + subtypeLocale = subtypeSwitcherLocale; } - resetDictionaryFacilitator(subtypeLocales); + if (mDictionaryFacilitator.isForLocale(subtypeLocale) + && mDictionaryFacilitator.isForAccount(mSettings.getCurrent().mAccount)) { + return; + } + resetDictionaryFacilitator(subtypeLocale); } /** - * Reset the facilitator by loading dictionaries for the locales and + * Reset the facilitator by loading dictionaries for the given locale and * the current settings values. * - * @param locales the locales + * @param locale the locale */ // TODO: make sure the current settings always have the right locales, and read from them. - private void resetDictionaryFacilitator(final Locale[] locales) { + private void resetDictionaryFacilitator(final Locale locale) { final SettingsValues settingsValues = mSettings.getCurrent(); - mDictionaryFacilitator.resetDictionaries(this /* context */, locales, + mDictionaryFacilitator.resetDictionaries(this /* context */, locale, settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts, false /* forceReloadMainDictionary */, settingsValues.mAccount, "" /* dictNamePrefix */, @@ -676,7 +675,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen /* package private */ void resetSuggestMainDict() { final SettingsValues settingsValues = mSettings.getCurrent(); mDictionaryFacilitator.resetDictionaries(this /* context */, - mDictionaryFacilitator.getLocales(), settingsValues.mUseContactsDict, + mDictionaryFacilitator.getLocale(), settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts, true /* forceReloadMainDictionary */, settingsValues.mAccount, "" /* dictNamePrefix */, @@ -843,7 +842,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Update to a gesture consumer with the current editor and IME state. mGestureConsumer = GestureConsumer.newInstance(editorInfo, mInputLogic.getPrivateCommandPerformer(), - Arrays.asList(mRichImm.getCurrentSubtypeLocales()), + mRichImm.getCurrentSubtypeLocale(), switcher.getKeyboard()); // Forward this event to the accessibility utilities, if enabled. @@ -1379,7 +1378,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void onStartBatchInput() { mInputLogic.onStartBatchInput(mSettings.getCurrent(), mKeyboardSwitcher, mHandler); mGestureConsumer.onGestureStarted( - Arrays.asList(mRichImm.getCurrentSubtypeLocales()), + mRichImm.getCurrentSubtypeLocale(), mKeyboardSwitcher.getKeyboard()); } @@ -1767,23 +1766,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // TODO: can this be removed somehow without breaking the tests? @UsedForTesting - /* package for test */ SuggestedWords getSuggestedWordsForTest() { + SuggestedWords getSuggestedWordsForTest() { // You may not use this method for anything else than debug return DebugFlags.DEBUG_ENABLED ? mInputLogic.mSuggestedWords : null; } // DO NOT USE THIS for any other purpose than testing. This is information private to LatinIME. @UsedForTesting - /* package for test */ void waitForLoadingDictionaries(final long timeout, final TimeUnit unit) + void waitForLoadingDictionaries(final long timeout, final TimeUnit unit) throws InterruptedException { mDictionaryFacilitator.waitForLoadingDictionariesForTesting(timeout, unit); } // DO NOT USE THIS for any other purpose than testing. This can break the keyboard badly. @UsedForTesting - /* package for test */ void replaceDictionariesForTest(final Locale locale) { + void replaceDictionariesForTest(final Locale locale) { final SettingsValues settingsValues = mSettings.getCurrent(); - mDictionaryFacilitator.resetDictionaries(this, new Locale[] { locale }, + mDictionaryFacilitator.resetDictionaries(this, locale, settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts, false /* forceReloadMainDictionary */, settingsValues.mAccount, "", /* dictionaryNamePrefix */ @@ -1792,12 +1791,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // DO NOT USE THIS for any other purpose than testing. @UsedForTesting - /* package for test */ void clearPersonalizedDictionariesForTest() { + void clearPersonalizedDictionariesForTest() { mDictionaryFacilitator.clearUserHistoryDictionary(this); } @UsedForTesting - /* package for test */ List getEnabledSubtypesForTest() { + List getEnabledSubtypesForTest() { return (mRichImm != null) ? mRichImm.getMyEnabledInputMethodSubtypeList( true /* allowsImplicitlySelectedSubtypes */) : new ArrayList(); } diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java index 602205b59..ef946c8bc 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java @@ -334,11 +334,11 @@ public class RichInputMethodManager { } @Nonnull - public Locale[] getCurrentSubtypeLocales() { + public Locale getCurrentSubtypeLocale() { if (null != sForcedSubtypeForTesting) { - return sForcedSubtypeForTesting.getLocales(); + return sForcedSubtypeForTesting.getLocale(); } - return getCurrentSubtype().getLocales(); + return getCurrentSubtype().getLocale(); } @Nonnull diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java b/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java index 8734e5925..c7bd88933 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java @@ -26,7 +26,6 @@ import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.common.LocaleUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; -import java.util.Arrays; import java.util.Locale; import javax.annotation.Nonnull; @@ -43,14 +42,11 @@ public final class RichInputMethodSubtype { @Nonnull private final InputMethodSubtype mSubtype; @Nonnull - private final Locale[] mLocales; + private final Locale mLocale; - public RichInputMethodSubtype(@Nonnull final InputMethodSubtype subtype, - @Nonnull final Locale... locales) { + public RichInputMethodSubtype(@Nonnull final InputMethodSubtype subtype) { mSubtype = subtype; - mLocales = new Locale[locales.length + 1]; - mLocales[0] = LocaleUtils.constructLocaleFromString(mSubtype.getLocale()); - System.arraycopy(locales, 0, mLocales, 1, locales.length); + mLocale = LocaleUtils.constructLocaleFromString(mSubtype.getLocale()); } // Extra values are determined by the primary subtype. This is probably right, but @@ -65,9 +61,6 @@ public final class RichInputMethodSubtype { } public boolean isNoLanguage() { - if (mLocales.length > 1) { - return false; - } return SubtypeLocaleUtils.NO_LANGUAGE.equals(mSubtype.getLocale()); } @@ -116,27 +109,27 @@ public final class RichInputMethodSubtype { return false; } final RichInputMethodSubtype other = (RichInputMethodSubtype)o; - return mSubtype.equals(other.mSubtype) && Arrays.equals(mLocales, other.mLocales); + return mSubtype.equals(other.mSubtype) && mLocale.equals(other.mLocale); } @Override public int hashCode() { - return mSubtype.hashCode() + Arrays.hashCode(mLocales); + return mSubtype.hashCode() + mLocale.hashCode(); } @Override public String toString() { - return "Multi-lingual subtype: " + mSubtype.toString() + ", " + Arrays.toString(mLocales); + return "Multi-lingual subtype: " + mSubtype + ", " + mLocale; } @Nonnull - public Locale[] getLocales() { - return mLocales; + public Locale getLocale() { + return mLocale; } public boolean isRtlSubtype() { // The subtype is considered RTL if the language of the main subtype is RTL. - return LocaleUtils.isRtlLanguage(mLocales[0]); + return LocaleUtils.isRtlLanguage(mLocale); } // TODO: remove this method diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index f4680fc88..6a0d6be9c 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -176,13 +176,13 @@ public final class Suggest { final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults( wordComposer.getComposedDataSnapshot(), ngramContext, keyboard, settingsValuesForSuggestion, SESSION_ID_TYPING, inputStyleIfNotPrediction); - final Locale mostProbableLocale = mDictionaryFacilitator.getMostProbableLocale(); + final Locale locale = mDictionaryFacilitator.getLocale(); final ArrayList suggestionsContainer = getTransformedSuggestedWordInfoList(wordComposer, suggestionResults, trailingSingleQuotesCount, // For transforming suggestions that don't come for any dictionary, we // use the currently most probable locale as it's our best bet. - mostProbableLocale); + locale); boolean typedWordExistsInAnotherLanguage = false; int qualityOfFoundSourceDictionary = QUALITY_NO_MATCH; @@ -191,7 +191,7 @@ public final class Suggest { // Search for the best dictionary, defined as the first one with the highest match // quality we can find. if (typedWordString.equals(info.mWord)) { - if (mostProbableLocale.equals(info.mSourceDict.mLocale)) { + if (locale.equals(info.mSourceDict.mLocale)) { if (qualityOfFoundSourceDictionary < QUALITY_MATCH_PREFERRED_LOCALE) { // Use this source if the old match had lower quality than this match sourceDictionaryOfRemovedWord = info.mSourceDict; @@ -217,8 +217,7 @@ public final class Suggest { getWhitelistedWordInfoOrNull(suggestionsContainer); final String whitelistedWord; if (null != whitelistedWordInfo && - (mDictionaryFacilitator.isConfidentAboutCurrentLanguageBeing( - whitelistedWordInfo.mSourceDict.mLocale) + (mDictionaryFacilitator.isForLocale(whitelistedWordInfo.mSourceDict.mLocale) || (!typedWordExistsInAnotherLanguage && !hasPlausibleCandidateInAnyOtherLanguage(suggestionsContainer, consideredWord, whitelistedWordInfo)))) { @@ -351,7 +350,7 @@ public final class Suggest { wordComposer.getComposedDataSnapshot(), ngramContext, keyboard, settingsValuesForSuggestion, SESSION_ID_GESTURE, inputStyle); // For transforming words that don't come from a dictionary, because it's our best bet - final Locale defaultLocale = mDictionaryFacilitator.getMostProbableLocale(); + final Locale locale = mDictionaryFacilitator.getLocale(); final ArrayList suggestionsContainer = new ArrayList<>(suggestionResults); final int suggestionsCount = suggestionsContainer.size(); @@ -362,7 +361,7 @@ public final class Suggest { final SuggestedWordInfo wordInfo = suggestionsContainer.get(i); final Locale wordlocale = wordInfo.mSourceDict.mLocale; final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo( - wordInfo, null == wordlocale ? defaultLocale : wordlocale, isAllUpperCase, + wordInfo, null == wordlocale ? locale : wordlocale, isAllUpperCase, isFirstCharCapitalized, 0 /* trailingSingleQuotesCount */); suggestionsContainer.set(i, transformedWordInfo); } diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 934da7ac7..de812dae5 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -279,7 +279,6 @@ public final class InputLogic { currentKeyboardScriptId, handler); } - mDictionaryFacilitator.switchMostProbableLanguage(suggestionInfo.mSourceDict.mLocale); final Event event = Event.createSuggestionPickedEvent(suggestionInfo); final InputTransaction inputTransaction = new InputTransaction(settingsValues, event, SystemClock.uptimeMillis(), mSpaceState, keyboardShiftState); @@ -2084,10 +2083,6 @@ public final class InputLogic { final boolean isBatchMode = mWordComposer.isBatchMode(); commitChosenWord(settingsValues, stringToCommit, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, separator); - if (null != autoCorrectionOrNull) { - mDictionaryFacilitator.switchMostProbableLanguage( - autoCorrectionOrNull.mSourceDict.mLocale); - } if (!typedWord.equals(stringToCommit)) { // This will make the correction flash for a short while as a visual clue // to the user that auto-correction happened. It has no other effect; in particular diff --git a/java/src/com/android/inputmethod/latin/utils/LanguageOnSpacebarUtils.java b/java/src/com/android/inputmethod/latin/utils/LanguageOnSpacebarUtils.java index fa1583b7a..a5a1ea921 100644 --- a/java/src/com/android/inputmethod/latin/utils/LanguageOnSpacebarUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/LanguageOnSpacebarUtils.java @@ -33,7 +33,6 @@ public final class LanguageOnSpacebarUtils { public static final int FORMAT_TYPE_NONE = 0; public static final int FORMAT_TYPE_LANGUAGE_ONLY = 1; public static final int FORMAT_TYPE_FULL_LOCALE = 2; - public static final int FORMAT_TYPE_MULTIPLE = 3; private static List sEnabledSubtypes = Collections.emptyList(); private static boolean sIsSystemLanguageSameAsInputLanguage; @@ -51,11 +50,11 @@ public final class LanguageOnSpacebarUtils { if (sEnabledSubtypes.size() < 2 && sIsSystemLanguageSameAsInputLanguage) { return FORMAT_TYPE_NONE; } - final Locale[] locales = subtype.getLocales(); - if (1 < locales.length) { - return FORMAT_TYPE_MULTIPLE; + final Locale locale = subtype.getLocale(); + if (locale == null) { + return FORMAT_TYPE_NONE; } - final String keyboardLanguage = locales[0].getLanguage(); + final String keyboardLanguage = locale.getLanguage(); final String keyboardLayout = subtype.getKeyboardLayoutSetName(); int sameLanguageAndLayoutCount = 0; for (final InputMethodSubtype ims : sEnabledSubtypes) { @@ -77,14 +76,7 @@ public final class LanguageOnSpacebarUtils { public static void onSubtypeChanged(@Nonnull final RichInputMethodSubtype subtype, final boolean implicitlyEnabledSubtype, @Nonnull final Locale systemLocale) { - final Locale[] newLocales = subtype.getLocales(); - if (newLocales.length > 1) { - // In multi-locales mode, the system language is never the same as the input language - // because there is no single input language. - sIsSystemLanguageSameAsInputLanguage = false; - return; - } - final Locale newLocale = newLocales[0]; + final Locale newLocale = subtype.getLocale(); if (systemLocale.equals(newLocale)) { sIsSystemLanguageSameAsInputLanguage = true; return; diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java index 7eccd4d5f..9da1e9470 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java @@ -1102,25 +1102,4 @@ public class BinaryDictionaryTests extends AndroidTestCase { assertEquals(bigramProbability, binaryDictionary.getNgramProbability(beginningOfSentenceContext, "bbb")); } - - public void testGetMaxFrequencyOfExactMatches() { - for (final int formatVersion : DICT_FORMAT_VERSIONS) { - testGetMaxFrequencyOfExactMatches(formatVersion); - } - } - - private void testGetMaxFrequencyOfExactMatches(final int formatVersion) { - final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion); - addUnigramWord(binaryDictionary, "abc", 10); - addUnigramWord(binaryDictionary, "aBc", 15); - assertEquals(15, binaryDictionary.getMaxFrequencyOfExactMatches("abc")); - addUnigramWord(binaryDictionary, "ab'c", 20); - assertEquals(20, binaryDictionary.getMaxFrequencyOfExactMatches("abc")); - addUnigramWord(binaryDictionary, "a-b-c", 25); - assertEquals(25, binaryDictionary.getMaxFrequencyOfExactMatches("abc")); - addUnigramWord(binaryDictionary, "ab-'-'-'-c", 30); - assertEquals(30, binaryDictionary.getMaxFrequencyOfExactMatches("abc")); - addUnigramWord(binaryDictionary, "ab c", 255); - assertEquals(30, binaryDictionary.getMaxFrequencyOfExactMatches("abc")); - } } diff --git a/tests/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCacheTests.java b/tests/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCacheTests.java index 4f924abc7..6b0bbc279 100644 --- a/tests/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCacheTests.java +++ b/tests/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCacheTests.java @@ -29,28 +29,14 @@ public class DictionaryFacilitatorLruCacheTests extends AndroidTestCase { final DictionaryFacilitator dictionaryFacilitatorEnUs = cache.get(Locale.US); assertNotNull(dictionaryFacilitatorEnUs); - assertTrue(dictionaryFacilitatorEnUs.isForLocales(new Locale[] { Locale.US })); + assertTrue(dictionaryFacilitatorEnUs.isForLocale(Locale.US)); final DictionaryFacilitator dictionaryFacilitatorFr = cache.get(Locale.FRENCH); assertNotNull(dictionaryFacilitatorEnUs); - assertTrue(dictionaryFacilitatorFr.isForLocales(new Locale[] { Locale.FRENCH })); + assertTrue(dictionaryFacilitatorFr.isForLocale(Locale.FRENCH)); final DictionaryFacilitator dictionaryFacilitatorDe = cache.get(Locale.GERMANY); assertNotNull(dictionaryFacilitatorDe); - assertTrue(dictionaryFacilitatorDe.isForLocales(new Locale[] { Locale.GERMANY })); - } - - public void testSetUseContactsDictionary() { - final DictionaryFacilitatorLruCache cache = - new DictionaryFacilitatorLruCache(getContext(), ""); - - assertNull(cache.get(Locale.US).getSubDictForTesting(Dictionary.TYPE_CONTACTS)); - cache.setUseContactsDictionary(true /* useContactsDictionary */); - assertNotNull(cache.get(Locale.US).getSubDictForTesting(Dictionary.TYPE_CONTACTS)); - assertNotNull(cache.get(Locale.FRENCH).getSubDictForTesting(Dictionary.TYPE_CONTACTS)); - assertNotNull(cache.get(Locale.GERMANY).getSubDictForTesting(Dictionary.TYPE_CONTACTS)); - cache.setUseContactsDictionary(false /* useContactsDictionary */); - assertNull(cache.get(Locale.GERMANY).getSubDictForTesting(Dictionary.TYPE_CONTACTS)); - assertNull(cache.get(Locale.US).getSubDictForTesting(Dictionary.TYPE_CONTACTS)); + assertTrue(dictionaryFacilitatorDe.isForLocale(Locale.GERMANY)); } } diff --git a/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java b/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java deleted file mode 100644 index 6c6f62872..000000000 --- a/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2012 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.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; -import com.android.inputmethod.latin.makedict.FusionDictionary; -import com.android.inputmethod.latin.makedict.ProbabilityInfo; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; - -import java.util.HashMap; - -/** - * Unit test for FusionDictionary - */ -@SmallTest -public class FusionDictionaryTests extends AndroidTestCase { - public void testFindWordInTree() { - FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new DictionaryOptions(new HashMap())); - - dict.add("abc", new ProbabilityInfo(10), false /* isNotAWord */, - false /* isPossiblyOffensive */); - assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa")); - assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "abc")); - - dict.add("aa", new ProbabilityInfo(10), false /* isNotAWord */, - false /* isPossiblyOffensive */); - assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa")); - assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aa")); - - dict.add("babcd", new ProbabilityInfo(10), false /* isNotAWord */, - false /* isPossiblyOffensive */); - dict.add("bacde", new ProbabilityInfo(10), false /* isNotAWord */, - false /* isPossiblyOffensive */); - assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "ba")); - assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "babcd")); - assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "bacde")); - } -} diff --git a/tests/src/com/android/inputmethod/latin/RichInputMethodSubtypeTests.java b/tests/src/com/android/inputmethod/latin/RichInputMethodSubtypeTests.java index d59890a96..af94be664 100644 --- a/tests/src/com/android/inputmethod/latin/RichInputMethodSubtypeTests.java +++ b/tests/src/com/android/inputmethod/latin/RichInputMethodSubtypeTests.java @@ -164,17 +164,12 @@ public class RichInputMethodSubtypeTests extends AndroidTestCase { final String subtypeName = SubtypeLocaleUtils .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype()); final String spacebarText = subtype.getFullDisplayName(); - final Locale[] locales = subtype.getLocales(); - if (1 == locales.length) { - final String languageName = SubtypeLocaleUtils - .getSubtypeLocaleDisplayName(locales[0].toString()); - if (subtype.isNoLanguage()) { - assertFalse(subtypeName, spacebarText.contains(languageName)); - } else { - assertTrue(subtypeName, spacebarText.contains(languageName)); - } + final String languageName = SubtypeLocaleUtils + .getSubtypeLocaleDisplayName(subtype.getLocale().toString()); + if (subtype.isNoLanguage()) { + assertFalse(subtypeName, spacebarText.contains(languageName)); } else { - // TODO: test multi-lingual subtype spacebar display + assertTrue(subtypeName, spacebarText.contains(languageName)); } } } @@ -183,12 +178,7 @@ public class RichInputMethodSubtypeTests extends AndroidTestCase { for (final RichInputMethodSubtype subtype : mSubtypesList) { final String subtypeName = SubtypeLocaleUtils .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype()); - final Locale[] locales = subtype.getLocales(); - if (locales.length > 1) { - // TODO: test multi-lingual subtype spacebar display - continue; - } - final Locale locale = locales[0]; + final Locale locale = subtype.getLocale(); final Locale displayLocale = SubtypeLocaleUtils.getDisplayLocaleOfSubtypeLocale( locale.toString()); if (Locale.ROOT.equals(displayLocale)) { diff --git a/tests/src/com/android/inputmethod/latin/utils/LanguageOnSpacebarUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/LanguageOnSpacebarUtilsTests.java index 7f7f493b1..e4b6a668c 100644 --- a/tests/src/com/android/inputmethod/latin/utils/LanguageOnSpacebarUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/LanguageOnSpacebarUtilsTests.java @@ -94,7 +94,7 @@ public class LanguageOnSpacebarUtilsTests extends AndroidTestCase { final boolean implicitlyEnabledSubtype, final Locale systemLocale, final int expectedFormat) { LanguageOnSpacebarUtils.onSubtypeChanged(subtype, implicitlyEnabledSubtype, systemLocale); - assertEquals(subtype.getLocales()[0] + " implicitly=" + implicitlyEnabledSubtype + assertEquals(subtype.getLocale() + " implicitly=" + implicitlyEnabledSubtype + " in " + systemLocale, expectedFormat, LanguageOnSpacebarUtils.getLanguageOnSpacebarFormatType(subtype)); } diff --git a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java index b5232a3da..2297cacf8 100644 --- a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java @@ -147,19 +147,14 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { for (final RichInputMethodSubtype subtype : mSubtypesList) { final String subtypeName = SubtypeLocaleUtils .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype()); - final Locale[] locales = subtype.getLocales(); - if (1 == locales.length) { - if (subtype.isNoLanguage()) { - final String layoutName = SubtypeLocaleUtils - .getKeyboardLayoutSetDisplayName(subtype.getRawSubtype()); - assertTrue(subtypeName, subtypeName.contains(layoutName)); - } else { - final String languageName = SubtypeLocaleUtils - .getSubtypeLocaleDisplayNameInSystemLocale(locales[0].toString()); - assertTrue(subtypeName, subtypeName.contains(languageName)); - } + if (subtype.isNoLanguage()) { + final String layoutName = SubtypeLocaleUtils + .getKeyboardLayoutSetDisplayName(subtype.getRawSubtype()); + assertTrue(subtypeName, subtypeName.contains(layoutName)); } else { - // TODO: test multi-lingual subtype spacebar display + final String languageName = SubtypeLocaleUtils + .getSubtypeLocaleDisplayNameInSystemLocale(subtype.getLocale().toString()); + assertTrue(subtypeName, subtypeName.contains(languageName)); } } }