am 7e1dfaae: Merge "Remove ALS from LatinIME."
* commit '7e1dfaae3d6ca9aff1acfa9b358ad0b759ef0ec8': Remove ALS from LatinIME.main
commit
b724ff1d11
|
@ -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<Locale> 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<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() {
|
||||
|
|
|
@ -287,7 +287,7 @@ public class Key implements Comparable<Key> {
|
|||
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);
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -281,8 +281,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
|
|||
|
||||
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<KP extends KeyboardParams> {
|
|||
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<KP extends KeyboardParams> {
|
|||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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<String> dictionaryTypes,
|
||||
final HashMap<String, File> dictionaryFiles,
|
||||
final Map<String, Map<String, String>> additionalDictAttributes,
|
||||
|
|
|
@ -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<String> dictTypeForLocale = new ArrayList<>();
|
||||
existingDictionariesToCleanup.put(newLocale, dictTypeForLocale);
|
||||
final DictionaryGroup currentDictionaryGroupForLocale =
|
||||
findDictionaryGroupWithLocale(mDictionaryGroups, newLocale);
|
||||
if (null == currentDictionaryGroupForLocale) {
|
||||
continue;
|
||||
}
|
||||
findDictionaryGroupWithLocale(mDictionaryGroup, newLocale);
|
||||
if (currentDictionaryGroupForLocale != null) {
|
||||
for (final String dictType : DYNAMIC_DICTIONARY_TYPES) {
|
||||
if (currentDictionaryGroupForLocale.hasDict(dictType, account)) {
|
||||
dictTypeForLocale.add(dictType);
|
||||
|
@ -374,11 +276,8 @@ 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);
|
||||
findDictionaryGroupWithLocale(mDictionaryGroup, newLocale);
|
||||
final ArrayList<String> dictTypesToCleanupForLocale =
|
||||
existingDictionariesToCleanup.get(newLocale);
|
||||
final boolean noExistingDictsForThisLocale = (null == dictionaryGroupForLocale);
|
||||
|
@ -407,17 +306,16 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
|||
}
|
||||
subDicts.put(subDictType, subDict);
|
||||
}
|
||||
newDictionaryGroups[i] = new DictionaryGroup(newLocale, mainDict, account, subDicts);
|
||||
}
|
||||
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<String> dictTypesToCleanUp =
|
||||
existingDictionariesToCleanup.get(localeToCleanUp);
|
||||
final DictionaryGroup dictionarySetToCleanup =
|
||||
findDictionaryGroupWithLocale(oldDictionaryGroups, localeToCleanUp);
|
||||
findDictionaryGroupWithLocale(oldDictionaryGroup, localeToCleanUp);
|
||||
for (final String dictType : dictTypesToCleanUp) {
|
||||
dictionarySetToCleanup.closeDict(dictType);
|
||||
}
|
||||
|
@ -437,28 +335,27 @@ 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);
|
||||
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");
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
final Dictionary mainDict =
|
||||
DictionaryFactory.createMainDictionaryFromManager(context, locale);
|
||||
|
@ -470,25 +367,20 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
|||
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<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles,
|
||||
final Map<String, Map<String, String>> additionalDictAttributes,
|
||||
@Nullable final String account) {
|
||||
Dictionary mainDictionary = null;
|
||||
final Map<String, ExpandableBinaryDictionary> 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,
|
||||
|
@ -509,52 +401,40 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
|||
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);
|
||||
}
|
||||
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);
|
||||
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);
|
||||
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()) {
|
||||
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,19 +543,17 @@ 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);
|
||||
final Dictionary dictionary = mDictionaryGroup.getDict(dictType);
|
||||
if (null == dictionary) continue;
|
||||
final float weightForLocale = composedData.mIsBatchMode
|
||||
? dictionaryGroup.mWeightForGesturingInLocale
|
||||
: dictionaryGroup.mWeightForTypingInLocale;
|
||||
? mDictionaryGroup.mWeightForGesturingInLocale
|
||||
: mDictionaryGroup.mWeightForTypingInLocale;
|
||||
final ArrayList<SuggestedWordInfo> dictionarySuggestions =
|
||||
dictionary.getSuggestions(composedData, ngramContext,
|
||||
proximityInfoHandle, settingsValuesForSuggestion, sessionId,
|
||||
|
@ -691,7 +564,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
|||
suggestionResults.mRawSuggestions.addAll(dictionarySuggestions);
|
||||
}
|
||||
}
|
||||
}
|
||||
return suggestionResults;
|
||||
}
|
||||
|
||||
|
@ -707,13 +579,11 @@ 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;
|
||||
if (mDictionaryGroup.mLocale == null) {
|
||||
return false;
|
||||
}
|
||||
for (final String dictType : dictionariesToCheck) {
|
||||
final Dictionary dictionary = dictionaryGroup.getDict(dictType);
|
||||
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.
|
||||
|
@ -722,7 +592,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -731,29 +600,23 @@ 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);
|
||||
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);
|
||||
final ExpandableBinaryDictionary dictionary = mDictionaryGroup.getSubDict(dictName);
|
||||
if (dictionary != null) {
|
||||
dictionary.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearUserHistoryDictionary(final Context context) {
|
||||
|
@ -762,9 +625,7 @@ 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);
|
||||
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.");
|
||||
|
@ -772,19 +633,15 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
|||
}
|
||||
dictToDump.dumpAllWordsForDebug();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<Pair<String, DictionaryStats>> getStatsOfEnabledSubDicts() {
|
||||
final ArrayList<Pair<String, DictionaryStats>> 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);
|
||||
final ExpandableBinaryDictionary dictionary = mDictionaryGroup.getSubDict(dictType);
|
||||
if (dictionary == null) continue;
|
||||
statsOfEnabledSubDicts.add(new Pair<>(dictType, dictionary.getDictionaryStats()));
|
||||
}
|
||||
}
|
||||
return statsOfEnabledSubDicts;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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<InputMethodSubtype> getEnabledSubtypesForTest() {
|
||||
List<InputMethodSubtype> getEnabledSubtypesForTest() {
|
||||
return (mRichImm != null) ? mRichImm.getMyEnabledInputMethodSubtypeList(
|
||||
true /* allowsImplicitlySelectedSubtypes */) : new ArrayList<InputMethodSubtype>();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<SuggestedWordInfo> 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<SuggestedWordInfo> 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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -2042,10 +2041,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
|
||||
|
|
|
@ -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<InputMethodSubtype> 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;
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
|
@ -164,18 +164,13 @@ 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());
|
||||
.getSubtypeLocaleDisplayName(subtype.getLocale().toString());
|
||||
if (subtype.isNoLanguage()) {
|
||||
assertFalse(subtypeName, spacebarText.contains(languageName));
|
||||
} else {
|
||||
assertTrue(subtypeName, spacebarText.contains(languageName));
|
||||
}
|
||||
} else {
|
||||
// TODO: test multi-lingual subtype spacebar display
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -147,20 +147,15 @@ 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());
|
||||
.getSubtypeLocaleDisplayNameInSystemLocale(subtype.getLocale().toString());
|
||||
assertTrue(subtypeName, subtypeName.contains(languageName));
|
||||
}
|
||||
} else {
|
||||
// TODO: test multi-lingual subtype spacebar display
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue