Remove ALS from LatinIME.

This fixes unit tests and brings us closer to a green build.

Change-Id: Iffcc392eda4a7671a238b79cc7367320ca648725
main
Dan Zivkovic 2015-03-11 16:11:50 -07:00
parent 9a289da4e6
commit 107fb4c476
21 changed files with 247 additions and 549 deletions

View File

@ -23,7 +23,6 @@ import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.common.InputPointers; import com.android.inputmethod.latin.common.InputPointers;
import com.android.inputmethod.latin.inputlogic.PrivateCommandPerformer; import com.android.inputmethod.latin.inputlogic.PrivateCommandPerformer;
import java.util.List;
import java.util.Locale; import java.util.Locale;
/** /**
@ -39,7 +38,7 @@ public class GestureConsumer {
public static GestureConsumer newInstance( public static GestureConsumer newInstance(
final EditorInfo editorInfo, final PrivateCommandPerformer commandPerformer, final EditorInfo editorInfo, final PrivateCommandPerformer commandPerformer,
final List<Locale> locales, final Keyboard keyboard) { final Locale locale, final Keyboard keyboard) {
return GestureConsumer.NULL_GESTURE_CONSUMER; return GestureConsumer.NULL_GESTURE_CONSUMER;
} }
@ -50,10 +49,10 @@ public class GestureConsumer {
return false; return false;
} }
public void onInit(final List<Locale> locales, final Keyboard keyboard) { public void onInit(final Locale locale, final Keyboard keyboard) {
} }
public void onGestureStarted(final List<Locale> locales, final Keyboard keyboard) { public void onGestureStarted(final Locale locale, final Keyboard keyboard) {
} }
public void onGestureCanceled() { public void onGestureCanceled() {

View File

@ -287,7 +287,7 @@ public class Key implements Comparable<Key> {
mLabelFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags) mLabelFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags)
| row.getDefaultKeyLabelFlags(); | row.getDefaultKeyLabelFlags();
final boolean needsToUpcase = needsToUpcase(mLabelFlags, params.mId.mElementId); 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); int actionFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
String[] moreKeys = style.getStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys); String[] moreKeys = style.getStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys);

View File

@ -164,8 +164,8 @@ public final class KeyboardId {
return InputTypeUtils.getImeOptionsActionIdFromEditorInfo(mEditorInfo); return InputTypeUtils.getImeOptionsActionIdFromEditorInfo(mEditorInfo);
} }
public Locale[] getLocales() { public Locale getLocale() {
return mSubtype.getLocales(); return mSubtype.getLocale();
} }
@Override @Override
@ -182,7 +182,7 @@ public final class KeyboardId {
public String toString() { public String toString() {
return String.format(Locale.ROOT, "[%s %s:%s %dx%d %s %s%s%s%s%s%s%s%s%s]", return String.format(Locale.ROOT, "[%s %s:%s %dx%d %s %s%s%s%s%s%s%s%s%s]",
elementIdToName(mElementId), elementIdToName(mElementId),
Arrays.deepToString(mSubtype.getLocales()), mSubtype.getLocale(),
mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET), mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET),
mWidth, mHeight, mWidth, mHeight,
modeName(mMode), modeName(mMode),

View File

@ -121,8 +121,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mKeyboardLayoutSet = builder.build(); mKeyboardLayoutSet = builder.build();
try { try {
mState.onLoadKeyboard(currentAutoCapsState, currentRecapitalizeState); mState.onLoadKeyboard(currentAutoCapsState, currentRecapitalizeState);
// TODO: revisit this for multi-lingual input mKeyboardTextsSet.setLocale(mRichImm.getCurrentSubtypeLocale(), mThemeContext);
mKeyboardTextsSet.setLocale(mRichImm.getCurrentSubtypeLocales()[0], mThemeContext);
} catch (KeyboardLayoutSetException e) { } catch (KeyboardLayoutSetException e) {
Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause()); Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause());
} }

View File

@ -843,15 +843,6 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy
// Layout language name on spacebar. // Layout language name on spacebar.
private String layoutLanguageOnSpacebar(final Paint paint, private String layoutLanguageOnSpacebar(final Paint paint,
final RichInputMethodSubtype subtype, final int width) { 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. // Choose appropriate language name to fit into the width.
if (mLanguageOnSpacebarFormatType == LanguageOnSpacebarUtils.FORMAT_TYPE_FULL_LOCALE) { if (mLanguageOnSpacebarFormatType == LanguageOnSpacebarUtils.FORMAT_TYPE_FULL_LOCALE) {
final String fullText = subtype.getFullDisplayName(); final String fullText = subtype.getFullDisplayName();

View File

@ -281,8 +281,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
params.mThemeId = keyboardAttr.getInt(R.styleable.Keyboard_themeId, 0); params.mThemeId = keyboardAttr.getInt(R.styleable.Keyboard_themeId, 0);
params.mIconsSet.loadIcons(keyboardAttr); params.mIconsSet.loadIcons(keyboardAttr);
// TODO: this needs to be revisited for multi-lingual input. params.mTextsSet.setLocale(params.mId.getLocale(), mContext);
params.mTextsSet.setLocale(params.mId.getLocales()[0], mContext);
final int resourceId = keyboardAttr.getResourceId( final int resourceId = keyboardAttr.getResourceId(
R.styleable.Keyboard_touchPositionCorrectionData, 0); R.styleable.Keyboard_touchPositionCorrectionData, 0);
@ -673,10 +672,10 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
R.styleable.Keyboard_Case_imeAction, id.imeAction()); R.styleable.Keyboard_Case_imeAction, id.imeAction());
final boolean isIconDefinedMatched = isIconDefined(caseAttr, final boolean isIconDefinedMatched = isIconDefined(caseAttr,
R.styleable.Keyboard_Case_isIconDefined, mParams.mIconsSet); R.styleable.Keyboard_Case_isIconDefined, mParams.mIconsSet);
final Locale[] locales = id.getLocales(); final Locale locale = id.getLocale();
final boolean localeCodeMatched = matchLocaleCodes(caseAttr, locales); final boolean localeCodeMatched = matchLocaleCodes(caseAttr, locale);
final boolean languageCodeMatched = matchLanguageCodes(caseAttr, locales); final boolean languageCodeMatched = matchLanguageCodes(caseAttr, locale);
final boolean countryCodeMatched = matchCountryCodes(caseAttr, locales); final boolean countryCodeMatched = matchCountryCodes(caseAttr, locale);
final boolean splitLayoutMatched = matchBoolean(caseAttr, final boolean splitLayoutMatched = matchBoolean(caseAttr,
R.styleable.Keyboard_Case_isSplitLayout, id.mIsSplitLayout); R.styleable.Keyboard_Case_isSplitLayout, id.mIsSplitLayout);
final boolean selected = keyboardLayoutSetMatched && keyboardLayoutSetElementMatched final boolean selected = keyboardLayoutSetMatched && keyboardLayoutSetElementMatched
@ -732,21 +731,16 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
} }
} }
private static boolean matchLocaleCodes(TypedArray caseAttr, final Locale[] locales) { private static boolean matchLocaleCodes(TypedArray caseAttr, final Locale locale) {
// TODO: adujst this for multilingual input return matchString(caseAttr, R.styleable.Keyboard_Case_localeCode, locale.toString());
return matchString(caseAttr, R.styleable.Keyboard_Case_localeCode, locales[0].toString());
} }
private static boolean matchLanguageCodes(TypedArray caseAttr, Locale[] locales) { private static boolean matchLanguageCodes(TypedArray caseAttr, Locale locale) {
// TODO: adujst this for multilingual input return matchString(caseAttr, R.styleable.Keyboard_Case_languageCode, locale.getLanguage());
return matchString(caseAttr, R.styleable.Keyboard_Case_languageCode,
locales[0].getLanguage());
} }
private static boolean matchCountryCodes(TypedArray caseAttr, Locale[] locales) { private static boolean matchCountryCodes(TypedArray caseAttr, Locale locale) {
// TODO: adujst this for multilingual input return matchString(caseAttr, R.styleable.Keyboard_Case_countryCode, locale.getCountry());
return matchString(caseAttr, R.styleable.Keyboard_Case_countryCode,
locales[0].getCountry());
} }
private static boolean matchInteger(final TypedArray a, final int index, final int value) { private static boolean matchInteger(final TypedArray a, final int index, final int value) {

View File

@ -72,11 +72,11 @@ public interface DictionaryFacilitator {
Dictionary.TYPE_CONTACTS}; 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. * Returns whether this facilitator is exactly for this account.
@ -91,25 +91,11 @@ public interface DictionaryFacilitator {
boolean isActive(); boolean isActive();
/** Locale getLocale();
* 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);
void resetDictionaries( void resetDictionaries(
final Context context, final Context context,
final Locale[] newLocales, final Locale newLocale,
final boolean useContactsDict, final boolean useContactsDict,
final boolean usePersonalizedDicts, final boolean usePersonalizedDicts,
final boolean forceReloadMainDictionary, final boolean forceReloadMainDictionary,
@ -120,7 +106,7 @@ public interface DictionaryFacilitator {
@UsedForTesting @UsedForTesting
void resetDictionariesForTesting( void resetDictionariesForTesting(
final Context context, final Context context,
final Locale[] locales, final Locale locale,
final ArrayList<String> dictionaryTypes, final ArrayList<String> dictionaryTypes,
final HashMap<String, File> dictionaryFiles, final HashMap<String, File> dictionaryFiles,
final Map<String, Map<String, String>> additionalDictAttributes, final Map<String, Map<String, String>> additionalDictAttributes,

View File

@ -63,12 +63,8 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
// HACK: This threshold is being used when adding a capitalized entry in the User History // HACK: This threshold is being used when adding a capitalized entry in the User History
// dictionary. // dictionary.
private static final int CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT = 140; 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 mDictionaryGroup = new DictionaryGroup();
private DictionaryGroup mMostProbableDictionaryGroup = mDictionaryGroups[0];
private volatile CountDownLatch mLatchForWaitingLoadingMainDictionaries = new CountDownLatch(0); private volatile CountDownLatch mLatchForWaitingLoadingMainDictionaries = new CountDownLatch(0);
// To synchronize assigning mDictionaryGroup to ensure closing dictionaries. // To synchronize assigning mDictionaryGroup to ensure closing dictionaries.
private final Object mLock = new Object(); private final Object mLock = new Object();
@ -86,28 +82,9 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
private static final Class<?>[] DICT_FACTORY_METHOD_ARG_TYPES = private static final Class<?>[] DICT_FACTORY_METHOD_ARG_TYPES =
new Class[] { Context.class, Locale.class, File.class, String.class, String.class }; new Class[] { Context.class, Locale.class, File.class, String.class, String.class };
/** @Override
* Returns whether this facilitator is exactly for this list of locales. public boolean isForLocale(final Locale locale) {
* return locale != null && locale.equals(mDictionaryGroup.mLocale);
* @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;
} }
/** /**
@ -116,12 +93,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
* @param account the account to test against. * @param account the account to test against.
*/ */
public boolean isForAccount(@Nullable final String account) { public boolean isForAccount(@Nullable final String account) {
for (final DictionaryGroup group : mDictionaryGroups) { return TextUtils.equals(mDictionaryGroup.mAccount, account);
if (!TextUtils.equals(group.mAccount, account)) {
return false;
}
}
return true;
} }
/** /**
@ -231,75 +203,12 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
} }
public boolean isActive() { public boolean isActive() {
return null != mDictionaryGroups[0].mLocale; return mDictionaryGroup.mLocale != null;
} }
/** @Override
* Returns the most probable locale among all currently active locales. BE CAREFUL using this. public Locale getLocale() {
* return mDictionaryGroup.mLocale;
* 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;
} }
@Nullable @Nullable
@ -325,19 +234,15 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
} }
@Nullable @Nullable
static DictionaryGroup findDictionaryGroupWithLocale(final DictionaryGroup[] dictionaryGroups, static DictionaryGroup findDictionaryGroupWithLocale(final DictionaryGroup dictionaryGroup,
final Locale locale) { final Locale locale) {
for (DictionaryGroup dictionaryGroup : dictionaryGroups) { return locale.equals(dictionaryGroup.mLocale) ? dictionaryGroup : null;
if (locale.equals(dictionaryGroup.mLocale)) {
return dictionaryGroup;
}
}
return null;
} }
@Override
public void resetDictionaries( public void resetDictionaries(
final Context context, final Context context,
final Locale[] newLocales, final Locale newLocale,
final boolean useContactsDict, final boolean useContactsDict,
final boolean usePersonalizedDicts, final boolean usePersonalizedDicts,
final boolean forceReloadMainDictionary, 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. // Gather all dictionaries. We'll remove them from the list to clean up later.
for (final Locale newLocale : newLocales) { final ArrayList<String> dictTypeForLocale = new ArrayList<>();
final ArrayList<String> dictTypeForLocale = new ArrayList<>(); existingDictionariesToCleanup.put(newLocale, dictTypeForLocale);
existingDictionariesToCleanup.put(newLocale, dictTypeForLocale); final DictionaryGroup currentDictionaryGroupForLocale =
final DictionaryGroup currentDictionaryGroupForLocale = findDictionaryGroupWithLocale(mDictionaryGroup, newLocale);
findDictionaryGroupWithLocale(mDictionaryGroups, newLocale); if (currentDictionaryGroupForLocale != null) {
if (null == currentDictionaryGroupForLocale) {
continue;
}
for (final String dictType : DYNAMIC_DICTIONARY_TYPES) { for (final String dictType : DYNAMIC_DICTIONARY_TYPES) {
if (currentDictionaryGroupForLocale.hasDict(dictType, account)) { if (currentDictionaryGroupForLocale.hasDict(dictType, account)) {
dictTypeForLocale.add(dictType); dictTypeForLocale.add(dictType);
@ -374,50 +276,46 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
} }
} }
final DictionaryGroup[] newDictionaryGroups = new DictionaryGroup[newLocales.length]; final DictionaryGroup dictionaryGroupForLocale =
for (int i = 0; i < newLocales.length; ++i) { findDictionaryGroupWithLocale(mDictionaryGroup, newLocale);
final Locale newLocale = newLocales[i]; final ArrayList<String> dictTypesToCleanupForLocale =
final DictionaryGroup dictionaryGroupForLocale = existingDictionariesToCleanup.get(newLocale);
findDictionaryGroupWithLocale(mDictionaryGroups, newLocale); final boolean noExistingDictsForThisLocale = (null == dictionaryGroupForLocale);
final ArrayList<String> dictTypesToCleanupForLocale =
existingDictionariesToCleanup.get(newLocale);
final boolean noExistingDictsForThisLocale = (null == dictionaryGroupForLocale);
final Dictionary mainDict; final Dictionary mainDict;
if (forceReloadMainDictionary || noExistingDictsForThisLocale if (forceReloadMainDictionary || noExistingDictsForThisLocale
|| !dictionaryGroupForLocale.hasDict(Dictionary.TYPE_MAIN, account)) { || !dictionaryGroupForLocale.hasDict(Dictionary.TYPE_MAIN, account)) {
mainDict = null; mainDict = null;
} else { } else {
mainDict = dictionaryGroupForLocale.getDict(Dictionary.TYPE_MAIN); mainDict = dictionaryGroupForLocale.getDict(Dictionary.TYPE_MAIN);
dictTypesToCleanupForLocale.remove(Dictionary.TYPE_MAIN); dictTypesToCleanupForLocale.remove(Dictionary.TYPE_MAIN);
}
final Map<String, ExpandableBinaryDictionary> 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 Map<String, ExpandableBinaryDictionary> 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. // Replace Dictionaries.
final DictionaryGroup[] oldDictionaryGroups; final DictionaryGroup oldDictionaryGroup;
synchronized (mLock) { synchronized (mLock) {
oldDictionaryGroups = mDictionaryGroups; oldDictionaryGroup = mDictionaryGroup;
mDictionaryGroups = newDictionaryGroups; mDictionaryGroup = newDictionaryGroup;
mMostProbableDictionaryGroup = newDictionaryGroups[0];
if (hasAtLeastOneUninitializedMainDictionary()) { if (hasAtLeastOneUninitializedMainDictionary()) {
asyncReloadUninitializedMainDictionaries(context, newLocales, listener); asyncReloadUninitializedMainDictionaries(context, newLocale, listener);
} }
} }
if (listener != null) { if (listener != null) {
@ -429,7 +327,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
final ArrayList<String> dictTypesToCleanUp = final ArrayList<String> dictTypesToCleanUp =
existingDictionariesToCleanup.get(localeToCleanUp); existingDictionariesToCleanup.get(localeToCleanUp);
final DictionaryGroup dictionarySetToCleanup = final DictionaryGroup dictionarySetToCleanup =
findDictionaryGroupWithLocale(oldDictionaryGroups, localeToCleanUp); findDictionaryGroupWithLocale(oldDictionaryGroup, localeToCleanUp);
for (final String dictType : dictTypesToCleanUp) { for (final String dictType : dictTypesToCleanUp) {
dictionarySetToCleanup.closeDict(dictType); dictionarySetToCleanup.closeDict(dictType);
} }
@ -437,123 +335,105 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
} }
private void asyncReloadUninitializedMainDictionaries(final Context context, private void asyncReloadUninitializedMainDictionaries(final Context context,
final Locale[] locales, final DictionaryInitializationListener listener) { final Locale locale, final DictionaryInitializationListener listener) {
final CountDownLatch latchForWaitingLoadingMainDictionary = new CountDownLatch(1); final CountDownLatch latchForWaitingLoadingMainDictionary = new CountDownLatch(1);
mLatchForWaitingLoadingMainDictionaries = latchForWaitingLoadingMainDictionary; mLatchForWaitingLoadingMainDictionaries = latchForWaitingLoadingMainDictionary;
ExecutorUtils.getBackgroundExecutor().execute(new Runnable() { ExecutorUtils.getBackgroundExecutor().execute(new Runnable() {
@Override @Override
public void run() { public void run() {
doReloadUninitializedMainDictionaries( 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 DictionaryInitializationListener listener,
final CountDownLatch latchForWaitingLoadingMainDictionary) { final CountDownLatch latchForWaitingLoadingMainDictionary) {
for (final Locale locale : locales) { final DictionaryGroup dictionaryGroup =
final DictionaryGroup dictionaryGroup = findDictionaryGroupWithLocale(mDictionaryGroup, locale);
findDictionaryGroupWithLocale(mDictionaryGroups, locale); if (null == dictionaryGroup) {
if (null == dictionaryGroup) { // This should never happen, but better safe than crashy
// This should never happen, but better safe than crashy Log.w(TAG, "Expected a dictionary group for " + locale + " but none found");
Log.w(TAG, "Expected a dictionary group for " + locale + " but none found"); return;
continue; }
} final Dictionary mainDict =
final Dictionary mainDict = DictionaryFactory.createMainDictionaryFromManager(context, locale);
DictionaryFactory.createMainDictionaryFromManager(context, locale); synchronized (mLock) {
synchronized (mLock) { if (locale.equals(dictionaryGroup.mLocale)) {
if (locale.equals(dictionaryGroup.mLocale)) { dictionaryGroup.setMainDict(mainDict);
dictionaryGroup.setMainDict(mainDict); } else {
} else { // Dictionary facilitator has been reset for another locale.
// Dictionary facilitator has been reset for another locale. mainDict.close();
mainDict.close();
}
} }
} }
if (listener != null) { if (listener != null) {
listener.onUpdateMainDictionaryAvailability( listener.onUpdateMainDictionaryAvailability(hasAtLeastOneInitializedMainDictionary());
hasAtLeastOneInitializedMainDictionary());
} }
latchForWaitingLoadingMainDictionary.countDown(); latchForWaitingLoadingMainDictionary.countDown();
} }
@UsedForTesting @UsedForTesting
public void resetDictionariesForTesting(final Context context, final Locale[] locales, public void resetDictionariesForTesting(final Context context, final Locale locale,
final ArrayList<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles, final ArrayList<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles,
final Map<String, Map<String, String>> additionalDictAttributes, final Map<String, Map<String, String>> additionalDictAttributes,
@Nullable final String account) { @Nullable final String account) {
Dictionary mainDictionary = null; Dictionary mainDictionary = null;
final Map<String, ExpandableBinaryDictionary> subDicts = new HashMap<>(); final Map<String, ExpandableBinaryDictionary> subDicts = new HashMap<>();
final DictionaryGroup[] dictionaryGroups = new DictionaryGroup[locales.length]; for (final String dictType : dictionaryTypes) {
for (int i = 0; i < locales.length; ++i) { if (dictType.equals(Dictionary.TYPE_MAIN)) {
final Locale locale = locales[i]; mainDictionary = DictionaryFactory.createMainDictionaryFromManager(context,
for (final String dictType : dictionaryTypes) { locale);
if (dictType.equals(Dictionary.TYPE_MAIN)) { } else {
mainDictionary = DictionaryFactory.createMainDictionaryFromManager(context, final File dictFile = dictionaryFiles.get(dictType);
locale); final ExpandableBinaryDictionary dict = getSubDict(
} else { dictType, context, locale, dictFile, "" /* dictNamePrefix */, account);
final File dictFile = dictionaryFiles.get(dictType); if (additionalDictAttributes.containsKey(dictType)) {
final ExpandableBinaryDictionary dict = getSubDict( dict.clearAndFlushDictionaryWithAdditionalAttributes(
dictType, context, locale, dictFile, "" /* dictNamePrefix */, account); additionalDictAttributes.get(dictType));
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);
} }
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; mDictionaryGroup = new DictionaryGroup(locale, mainDictionary, account, subDicts);
mMostProbableDictionaryGroup = dictionaryGroups[0];
} }
public void closeDictionaries() { public void closeDictionaries() {
final DictionaryGroup[] dictionaryGroups; final DictionaryGroup dictionaryGroupToClose;
synchronized (mLock) { synchronized (mLock) {
dictionaryGroups = mDictionaryGroups; dictionaryGroupToClose = mDictionaryGroup;
mMostProbableDictionaryGroup = new DictionaryGroup(); mDictionaryGroup = new DictionaryGroup();
mDictionaryGroups = new DictionaryGroup[] { mMostProbableDictionaryGroup };
} }
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { for (final String dictType : ALL_DICTIONARY_TYPES) {
for (final String dictType : ALL_DICTIONARY_TYPES) { dictionaryGroupToClose.closeDict(dictType);
dictionaryGroup.closeDict(dictType);
}
} }
} }
@UsedForTesting @UsedForTesting
public ExpandableBinaryDictionary getSubDictForTesting(final String dictName) { 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 // The main dictionaries are loaded asynchronously. Don't cache the return value
// of these methods. // of these methods.
public boolean hasAtLeastOneInitializedMainDictionary() { public boolean hasAtLeastOneInitializedMainDictionary() {
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; final Dictionary mainDict = mDictionaryGroup.getDict(Dictionary.TYPE_MAIN);
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { if (mainDict != null && mainDict.isInitialized()) {
final Dictionary mainDict = dictionaryGroup.getDict(Dictionary.TYPE_MAIN); return true;
if (mainDict != null && mainDict.isInitialized()) {
return true;
}
} }
return false; return false;
} }
public boolean hasAtLeastOneUninitializedMainDictionary() { public boolean hasAtLeastOneUninitializedMainDictionary() {
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; final Dictionary mainDict = mDictionaryGroup.getDict(Dictionary.TYPE_MAIN);
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { if (mainDict == null || !mainDict.isInitialized()) {
final Dictionary mainDict = dictionaryGroup.getDict(Dictionary.TYPE_MAIN); return true;
if (mainDict == null || !mainDict.isInitialized()) {
return true;
}
} }
return false; return false;
} }
@ -567,25 +447,22 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
public void waitForLoadingDictionariesForTesting(final long timeout, final TimeUnit unit) public void waitForLoadingDictionariesForTesting(final long timeout, final TimeUnit unit)
throws InterruptedException { throws InterruptedException {
waitForLoadingMainDictionaries(timeout, unit); waitForLoadingMainDictionaries(timeout, unit);
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; for (final ExpandableBinaryDictionary dict : mDictionaryGroup.mSubDictMap.values()) {
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { dict.waitAllTasksForTests();
for (final ExpandableBinaryDictionary dict : dictionaryGroup.mSubDictMap.values()) {
dict.waitAllTasksForTests();
}
} }
} }
public void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized, public void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized,
@Nonnull final NgramContext ngramContext, final long timeStampInSeconds, @Nonnull final NgramContext ngramContext, final long timeStampInSeconds,
final boolean blockPotentiallyOffensive) { final boolean blockPotentiallyOffensive) {
final DictionaryGroup dictionaryGroup = getDictionaryGroupForMostProbableLanguage();
final String[] words = suggestion.split(Constants.WORD_SEPARATOR); final String[] words = suggestion.split(Constants.WORD_SEPARATOR);
NgramContext ngramContextForCurrentWord = ngramContext; NgramContext ngramContextForCurrentWord = ngramContext;
for (int i = 0; i < words.length; i++) { for (int i = 0; i < words.length; i++) {
final String currentWord = words[i]; final String currentWord = words[i];
final boolean wasCurrentWordAutoCapitalized = (i == 0) ? wasAutoCapitalized : false; final boolean wasCurrentWordAutoCapitalized = (i == 0) ? wasAutoCapitalized : false;
addWordToUserHistory(dictionaryGroup, ngramContextForCurrentWord, currentWord, addWordToUserHistory(mDictionaryGroup, ngramContextForCurrentWord, currentWord,
wasCurrentWordAutoCapitalized, (int) timeStampInSeconds, blockPotentiallyOffensive); wasCurrentWordAutoCapitalized, (int) timeStampInSeconds,
blockPotentiallyOffensive);
ngramContextForCurrentWord = ngramContextForCurrentWord =
ngramContextForCurrentWord.getNextNgramContext(new WordInfo(currentWord)); ngramContextForCurrentWord.getNextNgramContext(new WordInfo(currentWord));
} }
@ -596,8 +473,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
final int timeStampInSeconds, final boolean blockPotentiallyOffensive) { final int timeStampInSeconds, final boolean blockPotentiallyOffensive) {
final ExpandableBinaryDictionary userHistoryDictionary = final ExpandableBinaryDictionary userHistoryDictionary =
dictionaryGroup.getSubDict(Dictionary.TYPE_USER_HISTORY); dictionaryGroup.getSubDict(Dictionary.TYPE_USER_HISTORY);
if (userHistoryDictionary == null if (userHistoryDictionary == null || !isForLocale(userHistoryDictionary.mLocale)) {
|| !isConfidentAboutCurrentLanguageBeing(userHistoryDictionary.mLocale)) {
return; return;
} }
final int maxFreq = getFrequency(word); final int maxFreq = getFrequency(word);
@ -644,8 +520,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
} }
private void removeWord(final String dictName, final String word) { private void removeWord(final String dictName, final String word) {
final ExpandableBinaryDictionary dictionary = final ExpandableBinaryDictionary dictionary = mDictionaryGroup.getSubDict(dictName);
getDictionaryGroupForMostProbableLanguage().getSubDict(dictName);
if (dictionary != null) { if (dictionary != null) {
dictionary.removeUnigramEntryDynamically(word); dictionary.removeUnigramEntryDynamically(word);
} }
@ -668,28 +543,25 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
SettingsValuesForSuggestion settingsValuesForSuggestion, int sessionId, SettingsValuesForSuggestion settingsValuesForSuggestion, int sessionId,
int inputStyle) { int inputStyle) {
long proximityInfoHandle = keyboard.getProximityInfo().getNativeProximityInfo(); long proximityInfoHandle = keyboard.getProximityInfo().getNativeProximityInfo();
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
final SuggestionResults suggestionResults = new SuggestionResults( final SuggestionResults suggestionResults = new SuggestionResults(
SuggestedWords.MAX_SUGGESTIONS, ngramContext.isBeginningOfSentenceContext(), SuggestedWords.MAX_SUGGESTIONS, ngramContext.isBeginningOfSentenceContext(),
false /* firstSuggestionExceedsConfidenceThreshold */); false /* firstSuggestionExceedsConfidenceThreshold */);
final float[] weightOfLangModelVsSpatialModel = final float[] weightOfLangModelVsSpatialModel =
new float[] { Dictionary.NOT_A_WEIGHT_OF_LANG_MODEL_VS_SPATIAL_MODEL }; 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) {
for (final String dictType : DICTIONARY_TYPES_FOR_SUGGESTIONS) { final Dictionary dictionary = mDictionaryGroup.getDict(dictType);
final Dictionary dictionary = dictionaryGroup.getDict(dictType); if (null == dictionary) continue;
if (null == dictionary) continue; final float weightForLocale = composedData.mIsBatchMode
final float weightForLocale = composedData.mIsBatchMode ? mDictionaryGroup.mWeightForGesturingInLocale
? dictionaryGroup.mWeightForGesturingInLocale : mDictionaryGroup.mWeightForTypingInLocale;
: dictionaryGroup.mWeightForTypingInLocale; final ArrayList<SuggestedWordInfo> dictionarySuggestions =
final ArrayList<SuggestedWordInfo> dictionarySuggestions = dictionary.getSuggestions(composedData, ngramContext,
dictionary.getSuggestions(composedData, ngramContext, proximityInfoHandle, settingsValuesForSuggestion, sessionId,
proximityInfoHandle, settingsValuesForSuggestion, sessionId, weightForLocale, weightOfLangModelVsSpatialModel);
weightForLocale, weightOfLangModelVsSpatialModel); if (null == dictionarySuggestions) continue;
if (null == dictionarySuggestions) continue; suggestionResults.addAll(dictionarySuggestions);
suggestionResults.addAll(dictionarySuggestions); if (null != suggestionResults.mRawSuggestions) {
if (null != suggestionResults.mRawSuggestions) { suggestionResults.mRawSuggestions.addAll(dictionarySuggestions);
suggestionResults.mRawSuggestions.addAll(dictionarySuggestions);
}
} }
} }
return suggestionResults; return suggestionResults;
@ -707,20 +579,17 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
if (TextUtils.isEmpty(word)) { if (TextUtils.isEmpty(word)) {
return false; return false;
} }
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; if (mDictionaryGroup.mLocale == null) {
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { return false;
if (dictionaryGroup.mLocale == null) { }
continue; for (final String dictType : dictionariesToCheck) {
} final Dictionary dictionary = mDictionaryGroup.getDict(dictType);
for (final String dictType : dictionariesToCheck) { // Ideally the passed map would come out of a {@link java.util.concurrent.Future} and
final Dictionary dictionary = dictionaryGroup.getDict(dictType); // would be immutable once it's finished initializing, but concretely a null test is
// Ideally the passed map would come out of a {@link java.util.concurrent.Future} and // probably good enough for the time being.
// would be immutable once it's finished initializing, but concretely a null test is if (null == dictionary) continue;
// probably good enough for the time being. if (dictionary.isValidWord(word)) {
if (null == dictionary) continue; return true;
if (dictionary.isValidWord(word)) {
return true;
}
} }
} }
return false; return false;
@ -731,27 +600,21 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
return Dictionary.NOT_A_PROBABILITY; return Dictionary.NOT_A_PROBABILITY;
} }
int maxFreq = Dictionary.NOT_A_PROBABILITY; int maxFreq = Dictionary.NOT_A_PROBABILITY;
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; for (final String dictType : ALL_DICTIONARY_TYPES) {
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { final Dictionary dictionary = mDictionaryGroup.getDict(dictType);
for (final String dictType : ALL_DICTIONARY_TYPES) { if (dictionary == null) continue;
final Dictionary dictionary = dictionaryGroup.getDict(dictType); final int tempFreq = dictionary.getFrequency(word);
if (dictionary == null) continue; if (tempFreq >= maxFreq) {
final int tempFreq = dictionary.getFrequency(word); maxFreq = tempFreq;
if (tempFreq >= maxFreq) {
maxFreq = tempFreq;
}
} }
} }
return maxFreq; return maxFreq;
} }
private void clearSubDictionary(final String dictName) { private void clearSubDictionary(final String dictName) {
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; final ExpandableBinaryDictionary dictionary = mDictionaryGroup.getSubDict(dictName);
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { if (dictionary != null) {
final ExpandableBinaryDictionary dictionary = dictionaryGroup.getSubDict(dictName); dictionary.clear();
if (dictionary != null) {
dictionary.clear();
}
} }
} }
@ -762,28 +625,22 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
@Override @Override
public void dumpDictionaryForDebug(final String dictName) { public void dumpDictionaryForDebug(final String dictName) {
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; final ExpandableBinaryDictionary dictToDump = mDictionaryGroup.getSubDict(dictName);
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { if (dictToDump == null) {
final ExpandableBinaryDictionary dictToDump = dictionaryGroup.getSubDict(dictName); Log.e(TAG, "Cannot dump " + dictName + ". "
if (dictToDump == null) { + "The dictionary is not being used for suggestion or cannot be dumped.");
Log.e(TAG, "Cannot dump " + dictName + ". " return;
+ "The dictionary is not being used for suggestion or cannot be dumped.");
return;
}
dictToDump.dumpAllWordsForDebug();
} }
dictToDump.dumpAllWordsForDebug();
} }
@Override @Override
public ArrayList<Pair<String, DictionaryStats>> getStatsOfEnabledSubDicts() { public ArrayList<Pair<String, DictionaryStats>> getStatsOfEnabledSubDicts() {
final ArrayList<Pair<String, DictionaryStats>> statsOfEnabledSubDicts = new ArrayList<>(); final ArrayList<Pair<String, DictionaryStats>> statsOfEnabledSubDicts = new ArrayList<>();
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; for (final String dictType : DYNAMIC_DICTIONARY_TYPES) {
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { final ExpandableBinaryDictionary dictionary = mDictionaryGroup.getSubDict(dictType);
for (final String dictType : DYNAMIC_DICTIONARY_TYPES) { if (dictionary == null) continue;
final ExpandableBinaryDictionary dictionary = dictionaryGroup.getSubDict(dictType); statsOfEnabledSubDicts.add(new Pair<>(dictType, dictionary.getDictionaryStats()));
if (dictionary == null) continue;
statsOfEnabledSubDicts.add(new Pair<>(dictType, dictionary.getDictionaryStats()));
}
} }
return statsOfEnabledSubDicts; return statsOfEnabledSubDicts;
} }

View File

@ -68,7 +68,7 @@ public class DictionaryFacilitatorLruCache {
// Nothing to do if the locale is null. This would be the case before any get() calls. // Nothing to do if the locale is null. This would be the case before any get() calls.
if (mLocale != null) { if (mLocale != null) {
// Note: Given that personalized dictionaries are not used here; we can pass null account. // 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 */, mUseContactsDictionary, false /* usePersonalizedDicts */,
false /* forceReloadMainDictionary */, null /* account */, false /* forceReloadMainDictionary */, null /* account */,
mDictionaryNamePrefix, null /* listener */); mDictionaryNamePrefix, null /* listener */);
@ -89,7 +89,7 @@ public class DictionaryFacilitatorLruCache {
public DictionaryFacilitator get(final Locale locale) { public DictionaryFacilitator get(final Locale locale) {
synchronized (mLock) { synchronized (mLock) {
if (!mDictionaryFacilitator.isForLocales(new Locale[]{locale})) { if (!mDictionaryFacilitator.isForLocale(locale)) {
mLocale = locale; mLocale = locale;
resetDictionariesForLocaleLocked(); resetDictionariesForLocaleLocked();
} }

View File

@ -588,19 +588,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Has to be package-visible for unit tests // Has to be package-visible for unit tests
@UsedForTesting @UsedForTesting
void loadSettings() { void loadSettings() {
final Locale[] locales = mRichImm.getCurrentSubtypeLocales(); final Locale locale = mRichImm.getCurrentSubtypeLocale();
final EditorInfo editorInfo = getCurrentInputEditorInfo(); final EditorInfo editorInfo = getCurrentInputEditorInfo();
final InputAttributes inputAttributes = new InputAttributes( final InputAttributes inputAttributes = new InputAttributes(
editorInfo, isFullscreenMode(), getPackageName()); editorInfo, isFullscreenMode(), getPackageName());
// TODO: pass the array instead mSettings.loadSettings(this, locale, inputAttributes);
mSettings.loadSettings(this, locales[0], inputAttributes);
final SettingsValues currentSettingsValues = mSettings.getCurrent(); final SettingsValues currentSettingsValues = mSettings.getCurrent();
AudioAndHapticFeedbackManager.getInstance().onSettingsChanged(currentSettingsValues); AudioAndHapticFeedbackManager.getInstance().onSettingsChanged(currentSettingsValues);
// This method is called on startup and language switch, before the new layout has // This method is called on startup and language switch, before the new layout has
// been displayed. Opening dictionaries never affects responsivity as dictionaries are // been displayed. Opening dictionaries never affects responsivity as dictionaries are
// asynchronously loaded. // asynchronously loaded.
if (!mHandler.hasPendingReopenDictionaries()) { if (!mHandler.hasPendingReopenDictionaries()) {
resetDictionaryFacilitator(locales); resetDictionaryFacilitator(locale);
} }
refreshPersonalizationDictionarySession(currentSettingsValues); refreshPersonalizationDictionarySession(currentSettingsValues);
resetDictionaryFacilitatorIfNecessary(); resetDictionaryFacilitatorIfNecessary();
@ -630,35 +629,35 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} }
void resetDictionaryFacilitatorIfNecessary() { void resetDictionaryFacilitatorIfNecessary() {
final Locale[] subtypeSwitcherLocales = mRichImm.getCurrentSubtypeLocales(); final Locale subtypeSwitcherLocale = mRichImm.getCurrentSubtypeLocale();
if (mDictionaryFacilitator.isForLocales(subtypeSwitcherLocales) final Locale subtypeLocale;
&& mDictionaryFacilitator.isForAccount(mSettings.getCurrent().mAccount)) { if (subtypeSwitcherLocale == null) {
return;
}
final Locale[] subtypeLocales;
if (0 == subtypeSwitcherLocales.length) {
// This happens in very rare corner cases - for example, immediately after a switch // 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 // 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 // case, we are about to go down but we still don't know it, however the system tells
// us there is no current subtype. // us there is no current subtype.
Log.e(TAG, "System is reporting no current subtype."); Log.e(TAG, "System is reporting no current subtype.");
subtypeLocales = new Locale[] { getResources().getConfiguration().locale }; subtypeLocale = getResources().getConfiguration().locale;
} else { } 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. * 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. // 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(); final SettingsValues settingsValues = mSettings.getCurrent();
mDictionaryFacilitator.resetDictionaries(this /* context */, locales, mDictionaryFacilitator.resetDictionaries(this /* context */, locale,
settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts, settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts,
false /* forceReloadMainDictionary */, false /* forceReloadMainDictionary */,
settingsValues.mAccount, "" /* dictNamePrefix */, settingsValues.mAccount, "" /* dictNamePrefix */,
@ -676,7 +675,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
/* package private */ void resetSuggestMainDict() { /* package private */ void resetSuggestMainDict() {
final SettingsValues settingsValues = mSettings.getCurrent(); final SettingsValues settingsValues = mSettings.getCurrent();
mDictionaryFacilitator.resetDictionaries(this /* context */, mDictionaryFacilitator.resetDictionaries(this /* context */,
mDictionaryFacilitator.getLocales(), settingsValues.mUseContactsDict, mDictionaryFacilitator.getLocale(), settingsValues.mUseContactsDict,
settingsValues.mUsePersonalizedDicts, settingsValues.mUsePersonalizedDicts,
true /* forceReloadMainDictionary */, true /* forceReloadMainDictionary */,
settingsValues.mAccount, "" /* dictNamePrefix */, 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. // Update to a gesture consumer with the current editor and IME state.
mGestureConsumer = GestureConsumer.newInstance(editorInfo, mGestureConsumer = GestureConsumer.newInstance(editorInfo,
mInputLogic.getPrivateCommandPerformer(), mInputLogic.getPrivateCommandPerformer(),
Arrays.asList(mRichImm.getCurrentSubtypeLocales()), mRichImm.getCurrentSubtypeLocale(),
switcher.getKeyboard()); switcher.getKeyboard());
// Forward this event to the accessibility utilities, if enabled. // Forward this event to the accessibility utilities, if enabled.
@ -1379,7 +1378,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void onStartBatchInput() { public void onStartBatchInput() {
mInputLogic.onStartBatchInput(mSettings.getCurrent(), mKeyboardSwitcher, mHandler); mInputLogic.onStartBatchInput(mSettings.getCurrent(), mKeyboardSwitcher, mHandler);
mGestureConsumer.onGestureStarted( mGestureConsumer.onGestureStarted(
Arrays.asList(mRichImm.getCurrentSubtypeLocales()), mRichImm.getCurrentSubtypeLocale(),
mKeyboardSwitcher.getKeyboard()); mKeyboardSwitcher.getKeyboard());
} }
@ -1767,23 +1766,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// TODO: can this be removed somehow without breaking the tests? // TODO: can this be removed somehow without breaking the tests?
@UsedForTesting @UsedForTesting
/* package for test */ SuggestedWords getSuggestedWordsForTest() { SuggestedWords getSuggestedWordsForTest() {
// You may not use this method for anything else than debug // You may not use this method for anything else than debug
return DebugFlags.DEBUG_ENABLED ? mInputLogic.mSuggestedWords : null; return DebugFlags.DEBUG_ENABLED ? mInputLogic.mSuggestedWords : null;
} }
// DO NOT USE THIS for any other purpose than testing. This is information private to LatinIME. // DO NOT USE THIS for any other purpose than testing. This is information private to LatinIME.
@UsedForTesting @UsedForTesting
/* package for test */ void waitForLoadingDictionaries(final long timeout, final TimeUnit unit) void waitForLoadingDictionaries(final long timeout, final TimeUnit unit)
throws InterruptedException { throws InterruptedException {
mDictionaryFacilitator.waitForLoadingDictionariesForTesting(timeout, unit); mDictionaryFacilitator.waitForLoadingDictionariesForTesting(timeout, unit);
} }
// DO NOT USE THIS for any other purpose than testing. This can break the keyboard badly. // DO NOT USE THIS for any other purpose than testing. This can break the keyboard badly.
@UsedForTesting @UsedForTesting
/* package for test */ void replaceDictionariesForTest(final Locale locale) { void replaceDictionariesForTest(final Locale locale) {
final SettingsValues settingsValues = mSettings.getCurrent(); final SettingsValues settingsValues = mSettings.getCurrent();
mDictionaryFacilitator.resetDictionaries(this, new Locale[] { locale }, mDictionaryFacilitator.resetDictionaries(this, locale,
settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts, settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts,
false /* forceReloadMainDictionary */, false /* forceReloadMainDictionary */,
settingsValues.mAccount, "", /* dictionaryNamePrefix */ settingsValues.mAccount, "", /* dictionaryNamePrefix */
@ -1792,12 +1791,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// DO NOT USE THIS for any other purpose than testing. // DO NOT USE THIS for any other purpose than testing.
@UsedForTesting @UsedForTesting
/* package for test */ void clearPersonalizedDictionariesForTest() { void clearPersonalizedDictionariesForTest() {
mDictionaryFacilitator.clearUserHistoryDictionary(this); mDictionaryFacilitator.clearUserHistoryDictionary(this);
} }
@UsedForTesting @UsedForTesting
/* package for test */ List<InputMethodSubtype> getEnabledSubtypesForTest() { List<InputMethodSubtype> getEnabledSubtypesForTest() {
return (mRichImm != null) ? mRichImm.getMyEnabledInputMethodSubtypeList( return (mRichImm != null) ? mRichImm.getMyEnabledInputMethodSubtypeList(
true /* allowsImplicitlySelectedSubtypes */) : new ArrayList<InputMethodSubtype>(); true /* allowsImplicitlySelectedSubtypes */) : new ArrayList<InputMethodSubtype>();
} }

View File

@ -334,11 +334,11 @@ public class RichInputMethodManager {
} }
@Nonnull @Nonnull
public Locale[] getCurrentSubtypeLocales() { public Locale getCurrentSubtypeLocale() {
if (null != sForcedSubtypeForTesting) { if (null != sForcedSubtypeForTesting) {
return sForcedSubtypeForTesting.getLocales(); return sForcedSubtypeForTesting.getLocale();
} }
return getCurrentSubtype().getLocales(); return getCurrentSubtype().getLocale();
} }
@Nonnull @Nonnull

View File

@ -26,7 +26,6 @@ import com.android.inputmethod.latin.common.Constants;
import com.android.inputmethod.latin.common.LocaleUtils; import com.android.inputmethod.latin.common.LocaleUtils;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -43,14 +42,11 @@ public final class RichInputMethodSubtype {
@Nonnull @Nonnull
private final InputMethodSubtype mSubtype; private final InputMethodSubtype mSubtype;
@Nonnull @Nonnull
private final Locale[] mLocales; private final Locale mLocale;
public RichInputMethodSubtype(@Nonnull final InputMethodSubtype subtype, public RichInputMethodSubtype(@Nonnull final InputMethodSubtype subtype) {
@Nonnull final Locale... locales) {
mSubtype = subtype; mSubtype = subtype;
mLocales = new Locale[locales.length + 1]; mLocale = LocaleUtils.constructLocaleFromString(mSubtype.getLocale());
mLocales[0] = LocaleUtils.constructLocaleFromString(mSubtype.getLocale());
System.arraycopy(locales, 0, mLocales, 1, locales.length);
} }
// Extra values are determined by the primary subtype. This is probably right, but // Extra values are determined by the primary subtype. This is probably right, but
@ -65,9 +61,6 @@ public final class RichInputMethodSubtype {
} }
public boolean isNoLanguage() { public boolean isNoLanguage() {
if (mLocales.length > 1) {
return false;
}
return SubtypeLocaleUtils.NO_LANGUAGE.equals(mSubtype.getLocale()); return SubtypeLocaleUtils.NO_LANGUAGE.equals(mSubtype.getLocale());
} }
@ -116,27 +109,27 @@ public final class RichInputMethodSubtype {
return false; return false;
} }
final RichInputMethodSubtype other = (RichInputMethodSubtype)o; 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 @Override
public int hashCode() { public int hashCode() {
return mSubtype.hashCode() + Arrays.hashCode(mLocales); return mSubtype.hashCode() + mLocale.hashCode();
} }
@Override @Override
public String toString() { public String toString() {
return "Multi-lingual subtype: " + mSubtype.toString() + ", " + Arrays.toString(mLocales); return "Multi-lingual subtype: " + mSubtype + ", " + mLocale;
} }
@Nonnull @Nonnull
public Locale[] getLocales() { public Locale getLocale() {
return mLocales; return mLocale;
} }
public boolean isRtlSubtype() { public boolean isRtlSubtype() {
// The subtype is considered RTL if the language of the main subtype is RTL. // 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 // TODO: remove this method

View File

@ -176,13 +176,13 @@ public final class Suggest {
final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults( final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults(
wordComposer.getComposedDataSnapshot(), ngramContext, keyboard, wordComposer.getComposedDataSnapshot(), ngramContext, keyboard,
settingsValuesForSuggestion, SESSION_ID_TYPING, inputStyleIfNotPrediction); settingsValuesForSuggestion, SESSION_ID_TYPING, inputStyleIfNotPrediction);
final Locale mostProbableLocale = mDictionaryFacilitator.getMostProbableLocale(); final Locale locale = mDictionaryFacilitator.getLocale();
final ArrayList<SuggestedWordInfo> suggestionsContainer = final ArrayList<SuggestedWordInfo> suggestionsContainer =
getTransformedSuggestedWordInfoList(wordComposer, suggestionResults, getTransformedSuggestedWordInfoList(wordComposer, suggestionResults,
trailingSingleQuotesCount, trailingSingleQuotesCount,
// For transforming suggestions that don't come for any dictionary, we // For transforming suggestions that don't come for any dictionary, we
// use the currently most probable locale as it's our best bet. // use the currently most probable locale as it's our best bet.
mostProbableLocale); locale);
boolean typedWordExistsInAnotherLanguage = false; boolean typedWordExistsInAnotherLanguage = false;
int qualityOfFoundSourceDictionary = QUALITY_NO_MATCH; 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 // Search for the best dictionary, defined as the first one with the highest match
// quality we can find. // quality we can find.
if (typedWordString.equals(info.mWord)) { if (typedWordString.equals(info.mWord)) {
if (mostProbableLocale.equals(info.mSourceDict.mLocale)) { if (locale.equals(info.mSourceDict.mLocale)) {
if (qualityOfFoundSourceDictionary < QUALITY_MATCH_PREFERRED_LOCALE) { if (qualityOfFoundSourceDictionary < QUALITY_MATCH_PREFERRED_LOCALE) {
// Use this source if the old match had lower quality than this match // Use this source if the old match had lower quality than this match
sourceDictionaryOfRemovedWord = info.mSourceDict; sourceDictionaryOfRemovedWord = info.mSourceDict;
@ -217,8 +217,7 @@ public final class Suggest {
getWhitelistedWordInfoOrNull(suggestionsContainer); getWhitelistedWordInfoOrNull(suggestionsContainer);
final String whitelistedWord; final String whitelistedWord;
if (null != whitelistedWordInfo && if (null != whitelistedWordInfo &&
(mDictionaryFacilitator.isConfidentAboutCurrentLanguageBeing( (mDictionaryFacilitator.isForLocale(whitelistedWordInfo.mSourceDict.mLocale)
whitelistedWordInfo.mSourceDict.mLocale)
|| (!typedWordExistsInAnotherLanguage || (!typedWordExistsInAnotherLanguage
&& !hasPlausibleCandidateInAnyOtherLanguage(suggestionsContainer, && !hasPlausibleCandidateInAnyOtherLanguage(suggestionsContainer,
consideredWord, whitelistedWordInfo)))) { consideredWord, whitelistedWordInfo)))) {
@ -351,7 +350,7 @@ public final class Suggest {
wordComposer.getComposedDataSnapshot(), ngramContext, keyboard, wordComposer.getComposedDataSnapshot(), ngramContext, keyboard,
settingsValuesForSuggestion, SESSION_ID_GESTURE, inputStyle); settingsValuesForSuggestion, SESSION_ID_GESTURE, inputStyle);
// For transforming words that don't come from a dictionary, because it's our best bet // 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<SuggestedWordInfo> suggestionsContainer = final ArrayList<SuggestedWordInfo> suggestionsContainer =
new ArrayList<>(suggestionResults); new ArrayList<>(suggestionResults);
final int suggestionsCount = suggestionsContainer.size(); final int suggestionsCount = suggestionsContainer.size();
@ -362,7 +361,7 @@ public final class Suggest {
final SuggestedWordInfo wordInfo = suggestionsContainer.get(i); final SuggestedWordInfo wordInfo = suggestionsContainer.get(i);
final Locale wordlocale = wordInfo.mSourceDict.mLocale; final Locale wordlocale = wordInfo.mSourceDict.mLocale;
final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo( final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo(
wordInfo, null == wordlocale ? defaultLocale : wordlocale, isAllUpperCase, wordInfo, null == wordlocale ? locale : wordlocale, isAllUpperCase,
isFirstCharCapitalized, 0 /* trailingSingleQuotesCount */); isFirstCharCapitalized, 0 /* trailingSingleQuotesCount */);
suggestionsContainer.set(i, transformedWordInfo); suggestionsContainer.set(i, transformedWordInfo);
} }

View File

@ -279,7 +279,6 @@ public final class InputLogic {
currentKeyboardScriptId, handler); currentKeyboardScriptId, handler);
} }
mDictionaryFacilitator.switchMostProbableLanguage(suggestionInfo.mSourceDict.mLocale);
final Event event = Event.createSuggestionPickedEvent(suggestionInfo); final Event event = Event.createSuggestionPickedEvent(suggestionInfo);
final InputTransaction inputTransaction = new InputTransaction(settingsValues, final InputTransaction inputTransaction = new InputTransaction(settingsValues,
event, SystemClock.uptimeMillis(), mSpaceState, keyboardShiftState); event, SystemClock.uptimeMillis(), mSpaceState, keyboardShiftState);
@ -2084,10 +2083,6 @@ public final class InputLogic {
final boolean isBatchMode = mWordComposer.isBatchMode(); final boolean isBatchMode = mWordComposer.isBatchMode();
commitChosenWord(settingsValues, stringToCommit, commitChosenWord(settingsValues, stringToCommit,
LastComposedWord.COMMIT_TYPE_DECIDED_WORD, separator); LastComposedWord.COMMIT_TYPE_DECIDED_WORD, separator);
if (null != autoCorrectionOrNull) {
mDictionaryFacilitator.switchMostProbableLanguage(
autoCorrectionOrNull.mSourceDict.mLocale);
}
if (!typedWord.equals(stringToCommit)) { if (!typedWord.equals(stringToCommit)) {
// This will make the correction flash for a short while as a visual clue // 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 // to the user that auto-correction happened. It has no other effect; in particular

View File

@ -33,7 +33,6 @@ public final class LanguageOnSpacebarUtils {
public static final int FORMAT_TYPE_NONE = 0; public static final int FORMAT_TYPE_NONE = 0;
public static final int FORMAT_TYPE_LANGUAGE_ONLY = 1; public static final int FORMAT_TYPE_LANGUAGE_ONLY = 1;
public static final int FORMAT_TYPE_FULL_LOCALE = 2; public static final int FORMAT_TYPE_FULL_LOCALE = 2;
public static final int FORMAT_TYPE_MULTIPLE = 3;
private static List<InputMethodSubtype> sEnabledSubtypes = Collections.emptyList(); private static List<InputMethodSubtype> sEnabledSubtypes = Collections.emptyList();
private static boolean sIsSystemLanguageSameAsInputLanguage; private static boolean sIsSystemLanguageSameAsInputLanguage;
@ -51,11 +50,11 @@ public final class LanguageOnSpacebarUtils {
if (sEnabledSubtypes.size() < 2 && sIsSystemLanguageSameAsInputLanguage) { if (sEnabledSubtypes.size() < 2 && sIsSystemLanguageSameAsInputLanguage) {
return FORMAT_TYPE_NONE; return FORMAT_TYPE_NONE;
} }
final Locale[] locales = subtype.getLocales(); final Locale locale = subtype.getLocale();
if (1 < locales.length) { if (locale == null) {
return FORMAT_TYPE_MULTIPLE; return FORMAT_TYPE_NONE;
} }
final String keyboardLanguage = locales[0].getLanguage(); final String keyboardLanguage = locale.getLanguage();
final String keyboardLayout = subtype.getKeyboardLayoutSetName(); final String keyboardLayout = subtype.getKeyboardLayoutSetName();
int sameLanguageAndLayoutCount = 0; int sameLanguageAndLayoutCount = 0;
for (final InputMethodSubtype ims : sEnabledSubtypes) { for (final InputMethodSubtype ims : sEnabledSubtypes) {
@ -77,14 +76,7 @@ public final class LanguageOnSpacebarUtils {
public static void onSubtypeChanged(@Nonnull final RichInputMethodSubtype subtype, public static void onSubtypeChanged(@Nonnull final RichInputMethodSubtype subtype,
final boolean implicitlyEnabledSubtype, @Nonnull final Locale systemLocale) { final boolean implicitlyEnabledSubtype, @Nonnull final Locale systemLocale) {
final Locale[] newLocales = subtype.getLocales(); final Locale newLocale = subtype.getLocale();
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];
if (systemLocale.equals(newLocale)) { if (systemLocale.equals(newLocale)) {
sIsSystemLanguageSameAsInputLanguage = true; sIsSystemLanguageSameAsInputLanguage = true;
return; return;

View File

@ -1102,25 +1102,4 @@ public class BinaryDictionaryTests extends AndroidTestCase {
assertEquals(bigramProbability, assertEquals(bigramProbability,
binaryDictionary.getNgramProbability(beginningOfSentenceContext, "bbb")); 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"));
}
} }

View File

@ -29,28 +29,14 @@ public class DictionaryFacilitatorLruCacheTests extends AndroidTestCase {
final DictionaryFacilitator dictionaryFacilitatorEnUs = cache.get(Locale.US); final DictionaryFacilitator dictionaryFacilitatorEnUs = cache.get(Locale.US);
assertNotNull(dictionaryFacilitatorEnUs); assertNotNull(dictionaryFacilitatorEnUs);
assertTrue(dictionaryFacilitatorEnUs.isForLocales(new Locale[] { Locale.US })); assertTrue(dictionaryFacilitatorEnUs.isForLocale(Locale.US));
final DictionaryFacilitator dictionaryFacilitatorFr = cache.get(Locale.FRENCH); final DictionaryFacilitator dictionaryFacilitatorFr = cache.get(Locale.FRENCH);
assertNotNull(dictionaryFacilitatorEnUs); assertNotNull(dictionaryFacilitatorEnUs);
assertTrue(dictionaryFacilitatorFr.isForLocales(new Locale[] { Locale.FRENCH })); assertTrue(dictionaryFacilitatorFr.isForLocale(Locale.FRENCH));
final DictionaryFacilitator dictionaryFacilitatorDe = cache.get(Locale.GERMANY); final DictionaryFacilitator dictionaryFacilitatorDe = cache.get(Locale.GERMANY);
assertNotNull(dictionaryFacilitatorDe); assertNotNull(dictionaryFacilitatorDe);
assertTrue(dictionaryFacilitatorDe.isForLocales(new Locale[] { Locale.GERMANY })); assertTrue(dictionaryFacilitatorDe.isForLocale(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));
} }
} }

View File

@ -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<String,String>()));
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"));
}
}

View File

@ -164,17 +164,12 @@ public class RichInputMethodSubtypeTests extends AndroidTestCase {
final String subtypeName = SubtypeLocaleUtils final String subtypeName = SubtypeLocaleUtils
.getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype()); .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype());
final String spacebarText = subtype.getFullDisplayName(); final String spacebarText = subtype.getFullDisplayName();
final Locale[] locales = subtype.getLocales(); final String languageName = SubtypeLocaleUtils
if (1 == locales.length) { .getSubtypeLocaleDisplayName(subtype.getLocale().toString());
final String languageName = SubtypeLocaleUtils if (subtype.isNoLanguage()) {
.getSubtypeLocaleDisplayName(locales[0].toString()); assertFalse(subtypeName, spacebarText.contains(languageName));
if (subtype.isNoLanguage()) {
assertFalse(subtypeName, spacebarText.contains(languageName));
} else {
assertTrue(subtypeName, spacebarText.contains(languageName));
}
} else { } 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) { for (final RichInputMethodSubtype subtype : mSubtypesList) {
final String subtypeName = SubtypeLocaleUtils final String subtypeName = SubtypeLocaleUtils
.getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype()); .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype());
final Locale[] locales = subtype.getLocales(); final Locale locale = subtype.getLocale();
if (locales.length > 1) {
// TODO: test multi-lingual subtype spacebar display
continue;
}
final Locale locale = locales[0];
final Locale displayLocale = SubtypeLocaleUtils.getDisplayLocaleOfSubtypeLocale( final Locale displayLocale = SubtypeLocaleUtils.getDisplayLocaleOfSubtypeLocale(
locale.toString()); locale.toString());
if (Locale.ROOT.equals(displayLocale)) { if (Locale.ROOT.equals(displayLocale)) {

View File

@ -94,7 +94,7 @@ public class LanguageOnSpacebarUtilsTests extends AndroidTestCase {
final boolean implicitlyEnabledSubtype, final Locale systemLocale, final boolean implicitlyEnabledSubtype, final Locale systemLocale,
final int expectedFormat) { final int expectedFormat) {
LanguageOnSpacebarUtils.onSubtypeChanged(subtype, implicitlyEnabledSubtype, systemLocale); LanguageOnSpacebarUtils.onSubtypeChanged(subtype, implicitlyEnabledSubtype, systemLocale);
assertEquals(subtype.getLocales()[0] + " implicitly=" + implicitlyEnabledSubtype assertEquals(subtype.getLocale() + " implicitly=" + implicitlyEnabledSubtype
+ " in " + systemLocale, expectedFormat, + " in " + systemLocale, expectedFormat,
LanguageOnSpacebarUtils.getLanguageOnSpacebarFormatType(subtype)); LanguageOnSpacebarUtils.getLanguageOnSpacebarFormatType(subtype));
} }

View File

@ -147,19 +147,14 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase {
for (final RichInputMethodSubtype subtype : mSubtypesList) { for (final RichInputMethodSubtype subtype : mSubtypesList) {
final String subtypeName = SubtypeLocaleUtils final String subtypeName = SubtypeLocaleUtils
.getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype()); .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype());
final Locale[] locales = subtype.getLocales(); if (subtype.isNoLanguage()) {
if (1 == locales.length) { final String layoutName = SubtypeLocaleUtils
if (subtype.isNoLanguage()) { .getKeyboardLayoutSetDisplayName(subtype.getRawSubtype());
final String layoutName = SubtypeLocaleUtils assertTrue(subtypeName, subtypeName.contains(layoutName));
.getKeyboardLayoutSetDisplayName(subtype.getRawSubtype());
assertTrue(subtypeName, subtypeName.contains(layoutName));
} else {
final String languageName = SubtypeLocaleUtils
.getSubtypeLocaleDisplayNameInSystemLocale(locales[0].toString());
assertTrue(subtypeName, subtypeName.contains(languageName));
}
} else { } else {
// TODO: test multi-lingual subtype spacebar display final String languageName = SubtypeLocaleUtils
.getSubtypeLocaleDisplayNameInSystemLocale(subtype.getLocale().toString());
assertTrue(subtypeName, subtypeName.contains(languageName));
} }
} }
} }