aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin/Suggest.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/latin/Suggest.java')
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java109
1 files changed, 100 insertions, 9 deletions
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 4df1d6505..0bf0f687a 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -32,6 +32,9 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
/**
* This class loads a dictionary and provides a list of suggestions for a given sequence of
* characters. This includes corrections and completions.
@@ -62,15 +65,30 @@ public final class Suggest {
}
private float mAutoCorrectionThreshold;
+ private float mPlausibilityThreshold;
public Suggest(final DictionaryFacilitator dictionaryFacilitator) {
mDictionaryFacilitator = dictionaryFacilitator;
}
+ /**
+ * Set the normalized-score threshold for a suggestion to be considered strong enough that we
+ * will auto-correct to this.
+ * @param threshold the threshold
+ */
public void setAutoCorrectionThreshold(final float threshold) {
mAutoCorrectionThreshold = threshold;
}
+ /**
+ * Set the normalized-score threshold for what we consider a "plausible" suggestion, in
+ * the same dimension as the auto-correction threshold.
+ * @param threshold the threshold
+ */
+ public void setPlausibilityThreshold(final float threshold) {
+ mPlausibilityThreshold = threshold;
+ }
+
public interface OnGetSuggestedWordsCallback {
public void onGetSuggestedWords(final SuggestedWords suggestedWords);
}
@@ -115,7 +133,8 @@ public final class Suggest {
return suggestionsContainer;
}
- private static String getWhitelistedWordOrNull(final ArrayList<SuggestedWordInfo> suggestions) {
+ private static SuggestedWordInfo getWhitelistedWordInfoOrNull(
+ @Nonnull final ArrayList<SuggestedWordInfo> suggestions) {
if (suggestions.isEmpty()) {
return null;
}
@@ -123,9 +142,21 @@ public final class Suggest {
if (!firstSuggestedWordInfo.isKindOf(SuggestedWordInfo.KIND_WHITELIST)) {
return null;
}
- return firstSuggestedWordInfo.mWord;
+ return firstSuggestedWordInfo;
}
+ // Quality constants for dictionary match
+ // In increasing order of quality
+ // This source dictionary does not match the typed word.
+ private static final int QUALITY_NO_MATCH = 0;
+ // This source dictionary has a null locale, and the preferred locale is also null.
+ private static final int QUALITY_MATCH_NULL = 1;
+ // This source dictionary has a non-null locale different from the preferred locale. The
+ // preferred locale may be null : this is still better than MATCH_NULL.
+ private static final int QUALITY_MATCH_OTHER_LOCALE = 2;
+ // This source dictionary matches the preferred locale.
+ private static final int QUALITY_MATCH_PREFERRED_LOCALE = 3;
+
// Retrieves suggestions for non-batch input (typing, recorrection, predictions...)
// and calls the callback function with the suggestions.
private void getSuggestedWordsForNonBatchInput(final WordComposer wordComposer,
@@ -143,22 +174,67 @@ public final class Suggest {
final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults(
wordComposer, ngramContext, proximityInfo.getNativeProximityInfo(),
settingsValuesForSuggestion, SESSION_ID_TYPING);
+ final Locale mostProbableLocale = mDictionaryFacilitator.getMostProbableLocale();
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.
- mDictionaryFacilitator.getMostProbableLocale());
- final boolean didRemoveTypedWord =
- SuggestedWordInfo.removeDups(wordComposer.getTypedWord(), suggestionsContainer);
+ mostProbableLocale);
+
+ boolean typedWordExistsInAnotherLanguage = false;
+ int qualityOfFoundSourceDictionary = QUALITY_NO_MATCH;
+ @Nullable Dictionary sourceDictionaryOfRemovedWord = null;
+ for (final SuggestedWordInfo info : suggestionsContainer) {
+ // 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 (qualityOfFoundSourceDictionary < QUALITY_MATCH_PREFERRED_LOCALE) {
+ // Use this source if the old match had lower quality than this match
+ sourceDictionaryOfRemovedWord = info.mSourceDict;
+ qualityOfFoundSourceDictionary = QUALITY_MATCH_PREFERRED_LOCALE;
+ }
+ } else {
+ final int matchQuality = (null == info.mSourceDict.mLocale)
+ ? QUALITY_MATCH_NULL : QUALITY_MATCH_OTHER_LOCALE;
+ if (qualityOfFoundSourceDictionary < matchQuality) {
+ // Use this source if the old match had lower quality than this match
+ sourceDictionaryOfRemovedWord = info.mSourceDict;
+ qualityOfFoundSourceDictionary = matchQuality;
+ }
+ typedWordExistsInAnotherLanguage = true;
+ }
+ }
+ }
- final String whitelistedWord = getWhitelistedWordOrNull(suggestionsContainer);
+ SuggestedWordInfo.removeDups(typedWordString, suggestionsContainer);
+
+ final SuggestedWordInfo whitelistedWordInfo =
+ getWhitelistedWordInfoOrNull(suggestionsContainer);
+ final String whitelistedWord;
+ if (null != whitelistedWordInfo &&
+ (mDictionaryFacilitator.isConfidentAboutCurrentLanguageBeing(
+ whitelistedWordInfo.mSourceDict.mLocale)
+ || (!typedWordExistsInAnotherLanguage
+ && !hasPlausibleCandidateInAnyOtherLanguage(suggestionsContainer,
+ consideredWord, whitelistedWordInfo)))) {
+ // We'll use the whitelist candidate if we are confident the user is typing in the
+ // language of the dictionary it's coming from, or if there is no plausible candidate
+ // coming from another language.
+ whitelistedWord = whitelistedWordInfo.mWord;
+ } else {
+ // If on the contrary we are not confident in the current language and we have
+ // at least a plausible candidate in any other language, then we don't use this
+ // whitelist candidate.
+ whitelistedWord = null;
+ }
final boolean resultsArePredictions = !wordComposer.isComposingWord();
// We allow auto-correction if we have a whitelisted word, or if the word had more than
// one char and was not suggested.
final boolean allowsToBeAutoCorrected = (null != whitelistedWord)
- || (consideredWord.length() > 1 && !didRemoveTypedWord);
+ || (consideredWord.length() > 1 && (null == sourceDictionaryOfRemovedWord));
final boolean hasAutoCorrection;
// If correction is not enabled, we never auto-correct. This is for example for when
@@ -194,7 +270,7 @@ public final class Suggest {
hasAutoCorrection = false;
} else {
final SuggestedWordInfo firstSuggestion = suggestionResults.first();
- if (!AutoCorrectionUtils.suggestionExceedsAutoCorrectionThreshold(
+ if (!AutoCorrectionUtils.suggestionExceedsThreshold(
firstSuggestion, consideredWord, mAutoCorrectionThreshold)) {
// Score is too low for autocorrect
hasAutoCorrection = false;
@@ -209,7 +285,8 @@ public final class Suggest {
final SuggestedWordInfo typedWordInfo = new SuggestedWordInfo(typedWordString,
SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_TYPED,
- Dictionary.DICTIONARY_USER_TYPED,
+ null == sourceDictionaryOfRemovedWord ? Dictionary.DICTIONARY_USER_TYPED
+ : sourceDictionaryOfRemovedWord,
SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
if (!TextUtils.isEmpty(typedWordString)) {
@@ -242,6 +319,20 @@ public final class Suggest {
false /* isObsoleteSuggestions */, inputStyle, sequenceNumber));
}
+ private boolean hasPlausibleCandidateInAnyOtherLanguage(
+ final ArrayList<SuggestedWordInfo> suggestionsContainer, final String consideredWord,
+ final SuggestedWordInfo whitelistedWordInfo) {
+ for (final SuggestedWordInfo info : suggestionsContainer) {
+ if (whitelistedWordInfo.mSourceDict.mLocale.equals(info.mSourceDict.mLocale)) {
+ continue;
+ }
+ return AutoCorrectionUtils.suggestionExceedsThreshold(info, consideredWord,
+ mPlausibilityThreshold);
+ }
+ // No candidate in another language
+ return false;
+ }
+
// Retrieves suggestions for the batch input
// and calls the callback function with the suggestions.
private void getSuggestedWordsForBatchInput(final WordComposer wordComposer,