Support multiple locales in distractor filter.
Bug: 16547557 Change-Id: I4aba278eb4114e0075f3f8b38c7e132743927fa8main
parent
e59f3e4fbf
commit
fdaedb6c1d
|
@ -20,12 +20,14 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.text.InputType;
|
||||
import android.util.Log;
|
||||
import android.util.LruCache;
|
||||
import android.util.Pair;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodSubtype;
|
||||
|
||||
|
@ -49,16 +51,15 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
|
|||
DistracterFilterCheckingExactMatchesAndSuggestions.class.getSimpleName();
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final int MAX_DISTRACTERS_CACHE_SIZE = 512;
|
||||
private static final int MAX_DISTRACTERS_CACHE_SIZE = 1024;
|
||||
|
||||
private final Context mContext;
|
||||
private final Map<Locale, InputMethodSubtype> mLocaleToSubtypeMap;
|
||||
private final Map<Locale, Keyboard> mLocaleToKeyboardMap;
|
||||
private final ConcurrentHashMap<Locale, InputMethodSubtype> mLocaleToSubtypeCache;
|
||||
private final ConcurrentHashMap<Locale, Keyboard> mLocaleToKeyboardCache;
|
||||
private final DictionaryFacilitatorLruCache mDictionaryFacilitatorLruCache;
|
||||
private final LruCache<String, Boolean> mDistractersCache;
|
||||
// TODO: Remove and support multiple locales at the same time.
|
||||
private Locale mCurrentLocale;
|
||||
private Keyboard mKeyboard;
|
||||
// The key is a pair of a locale and a word. The value indicates the word is a distracter to
|
||||
// words of the locale.
|
||||
private final LruCache<Pair<Locale, String>, Boolean> mDistractersCache;
|
||||
private final Object mLock = new Object();
|
||||
|
||||
// If the score of the top suggestion exceeds this value, the tested word (e.g.,
|
||||
|
@ -78,20 +79,17 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
|
|||
public DistracterFilterCheckingExactMatchesAndSuggestions(final Context context,
|
||||
final DictionaryFacilitatorLruCache dictionaryFacilitatorLruCache) {
|
||||
mContext = context;
|
||||
mLocaleToSubtypeMap = new HashMap<>();
|
||||
mLocaleToKeyboardMap = new HashMap<>();
|
||||
mLocaleToSubtypeCache = new ConcurrentHashMap<>();
|
||||
mLocaleToKeyboardCache = new ConcurrentHashMap<>();
|
||||
mDictionaryFacilitatorLruCache = dictionaryFacilitatorLruCache;
|
||||
mDistractersCache = new LruCache<>(MAX_DISTRACTERS_CACHE_SIZE);
|
||||
mCurrentLocale = null;
|
||||
mKeyboard = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
mLocaleToKeyboardMap.clear();
|
||||
mLocaleToSubtypeCache.clear();
|
||||
mLocaleToKeyboardCache.clear();
|
||||
mDistractersCache.evictAll();
|
||||
mCurrentLocale = null;
|
||||
mKeyboard = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -108,29 +106,36 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
|
|||
newLocaleToSubtypeMap.put(locale, subtype);
|
||||
}
|
||||
}
|
||||
if (mLocaleToSubtypeMap.equals(newLocaleToSubtypeMap)) {
|
||||
if (mLocaleToSubtypeCache.equals(newLocaleToSubtypeMap)) {
|
||||
// Enabled subtypes have not been changed.
|
||||
return;
|
||||
}
|
||||
synchronized (mLock) {
|
||||
mLocaleToSubtypeMap.clear();
|
||||
mLocaleToSubtypeMap.putAll(newLocaleToSubtypeMap);
|
||||
mLocaleToKeyboardMap.clear();
|
||||
// Update subtype and keyboard map for locales that are in the current mapping.
|
||||
for (final Locale locale: mLocaleToSubtypeCache.keySet()) {
|
||||
if (newLocaleToSubtypeMap.containsKey(locale)) {
|
||||
final InputMethodSubtype newSubtype = newLocaleToSubtypeMap.remove(locale);
|
||||
if (newSubtype.equals(newLocaleToSubtypeMap.get(locale))) {
|
||||
// Mapping has not been changed.
|
||||
continue;
|
||||
}
|
||||
mLocaleToSubtypeCache.replace(locale, newSubtype);
|
||||
} else {
|
||||
mLocaleToSubtypeCache.remove(locale);
|
||||
}
|
||||
mLocaleToKeyboardCache.remove(locale);
|
||||
}
|
||||
// Add locales that are not in the current mapping.
|
||||
mLocaleToSubtypeCache.putAll(newLocaleToSubtypeMap);
|
||||
}
|
||||
|
||||
private void loadKeyboardForLocale(final Locale newLocale) {
|
||||
final Keyboard cachedKeyboard = mLocaleToKeyboardMap.get(newLocale);
|
||||
private Keyboard getKeyboardForLocale(final Locale locale) {
|
||||
final Keyboard cachedKeyboard = mLocaleToKeyboardCache.get(locale);
|
||||
if (cachedKeyboard != null) {
|
||||
mKeyboard = cachedKeyboard;
|
||||
return;
|
||||
}
|
||||
final InputMethodSubtype subtype;
|
||||
synchronized (mLock) {
|
||||
subtype = mLocaleToSubtypeMap.get(newLocale);
|
||||
return cachedKeyboard;
|
||||
}
|
||||
final InputMethodSubtype subtype = mLocaleToSubtypeCache.get(locale);
|
||||
if (subtype == null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
final EditorInfo editorInfo = new EditorInfo();
|
||||
editorInfo.inputType = InputType.TYPE_CLASS_TEXT;
|
||||
|
@ -143,7 +148,9 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
|
|||
builder.setSubtype(new RichInputMethodSubtype(subtype));
|
||||
builder.setIsSpellChecker(false /* isSpellChecker */);
|
||||
final KeyboardLayoutSet layoutSet = builder.build();
|
||||
mKeyboard = layoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
|
||||
final Keyboard newKeyboard = layoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
|
||||
mLocaleToKeyboardCache.put(locale, newKeyboard);
|
||||
return newKeyboard;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,24 +168,18 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
|
|||
if (locale == null) {
|
||||
return false;
|
||||
}
|
||||
if (!locale.equals(mCurrentLocale)) {
|
||||
synchronized (mLock) {
|
||||
if (!mLocaleToSubtypeMap.containsKey(locale)) {
|
||||
Log.e(TAG, "Locale " + locale + " is not enabled.");
|
||||
// TODO: Investigate what we should do for disabled locales.
|
||||
return false;
|
||||
}
|
||||
mCurrentLocale = locale;
|
||||
loadKeyboardForLocale(locale);
|
||||
mDistractersCache.evictAll();
|
||||
}
|
||||
if (!mLocaleToSubtypeCache.containsKey(locale)) {
|
||||
Log.e(TAG, "Locale " + locale + " is not enabled.");
|
||||
// TODO: Investigate what we should do for disabled locales.
|
||||
return false;
|
||||
}
|
||||
final DictionaryFacilitator dictionaryFacilitator =
|
||||
mDictionaryFacilitatorLruCache.get(locale);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "testedWord: " + testedWord);
|
||||
}
|
||||
final Boolean isCachedDistracter = mDistractersCache.get(testedWord);
|
||||
final Pair<Locale, String> cacheKey = new Pair<>(locale, testedWord);
|
||||
final Boolean isCachedDistracter = mDistractersCache.get(cacheKey);
|
||||
if (isCachedDistracter != null && isCachedDistracter) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "isDistracter: true (cache hit)");
|
||||
|
@ -189,8 +190,8 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
|
|||
final boolean isDistracterCheckedByGetMaxFreqencyOfExactMatches =
|
||||
checkDistracterUsingMaxFreqencyOfExactMatches(dictionaryFacilitator, testedWord);
|
||||
if (isDistracterCheckedByGetMaxFreqencyOfExactMatches) {
|
||||
// Add the word to the cache.
|
||||
mDistractersCache.put(testedWord, Boolean.TRUE);
|
||||
// Add the pair of locale and word to the cache.
|
||||
mDistractersCache.put(cacheKey, Boolean.TRUE);
|
||||
return true;
|
||||
}
|
||||
final boolean isValidWord = dictionaryFacilitator.isValidWord(testedWord,
|
||||
|
@ -203,11 +204,12 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
|
|||
return false;
|
||||
}
|
||||
|
||||
final Keyboard keyboard = getKeyboardForLocale(locale);
|
||||
final boolean isDistracterCheckedByGetSuggestion =
|
||||
checkDistracterUsingGetSuggestions(dictionaryFacilitator, testedWord);
|
||||
checkDistracterUsingGetSuggestions(dictionaryFacilitator, keyboard, testedWord);
|
||||
if (isDistracterCheckedByGetSuggestion) {
|
||||
// Add the word to the cache.
|
||||
mDistractersCache.put(testedWord, Boolean.TRUE);
|
||||
// Add the pair of locale and word to the cache.
|
||||
mDistractersCache.put(cacheKey, Boolean.TRUE);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -229,8 +231,9 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
|
|||
}
|
||||
|
||||
private boolean checkDistracterUsingGetSuggestions(
|
||||
final DictionaryFacilitator dictionaryFacilitator, final String testedWord) {
|
||||
if (mKeyboard == null) {
|
||||
final DictionaryFacilitator dictionaryFacilitator, final Keyboard keyboard,
|
||||
final String testedWord) {
|
||||
if (keyboard == null) {
|
||||
return false;
|
||||
}
|
||||
final SettingsValuesForSuggestion settingsValuesForSuggestion =
|
||||
|
@ -243,24 +246,24 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
|
|||
testedWord;
|
||||
final WordComposer composer = new WordComposer();
|
||||
final int[] codePoints = StringUtils.toCodePointArray(testedWord);
|
||||
|
||||
final int[] coordinates = keyboard.getCoordinates(codePoints);
|
||||
composer.setComposingWord(codePoints, coordinates);
|
||||
final SuggestionResults suggestionResults;
|
||||
synchronized (mLock) {
|
||||
final int[] coordinates = mKeyboard.getCoordinates(codePoints);
|
||||
composer.setComposingWord(codePoints, coordinates);
|
||||
final SuggestionResults suggestionResults = dictionaryFacilitator.getSuggestionResults(
|
||||
composer, PrevWordsInfo.EMPTY_PREV_WORDS_INFO, mKeyboard.getProximityInfo(),
|
||||
suggestionResults = dictionaryFacilitator.getSuggestionResults(
|
||||
composer, PrevWordsInfo.EMPTY_PREV_WORDS_INFO, keyboard.getProximityInfo(),
|
||||
settingsValuesForSuggestion, 0 /* sessionId */);
|
||||
if (suggestionResults.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
final SuggestedWordInfo firstSuggestion = suggestionResults.first();
|
||||
final boolean isDistractor = suggestionExceedsDistracterThreshold(
|
||||
firstSuggestion, consideredWord, DISTRACTER_WORD_SCORE_THRESHOLD);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "isDistracter: " + isDistractor);
|
||||
}
|
||||
return isDistractor;
|
||||
}
|
||||
if (suggestionResults.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
final SuggestedWordInfo firstSuggestion = suggestionResults.first();
|
||||
final boolean isDistractor = suggestionExceedsDistracterThreshold(
|
||||
firstSuggestion, consideredWord, DISTRACTER_WORD_SCORE_THRESHOLD);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "isDistracter: " + isDistractor);
|
||||
}
|
||||
return isDistractor;
|
||||
}
|
||||
|
||||
private static boolean suggestionExceedsDistracterThreshold(final SuggestedWordInfo suggestion,
|
||||
|
|
Loading…
Reference in New Issue