Merge "Remove SuggestionsGatherer."
commit
b7ecb258dc
|
@ -155,6 +155,10 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
|
||||||
onSharedPreferenceChanged(prefs, PREF_USE_CONTACTS_KEY);
|
onSharedPreferenceChanged(prefs, PREF_USE_CONTACTS_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getRecommendedThreshold() {
|
||||||
|
return mRecommendedThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
private static String getKeyboardLayoutNameForScript(final int script) {
|
private static String getKeyboardLayoutNameForScript(final int script) {
|
||||||
switch (script) {
|
switch (script) {
|
||||||
case ScriptUtils.SCRIPT_LATIN:
|
case ScriptUtils.SCRIPT_LATIN:
|
||||||
|
@ -214,95 +218,6 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
|
||||||
EMPTY_STRING_ARRAY);
|
EMPTY_STRING_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SuggestionsGatherer newSuggestionsGatherer(final String text, int maxLength) {
|
|
||||||
return new SuggestionsGatherer(text, mRecommendedThreshold, maxLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: remove this class and replace it by storage local to the session.
|
|
||||||
public static final class SuggestionsGatherer {
|
|
||||||
public static final class Result {
|
|
||||||
public final String[] mSuggestions;
|
|
||||||
public final boolean mHasRecommendedSuggestions;
|
|
||||||
public Result(final String[] gatheredSuggestions,
|
|
||||||
final boolean hasRecommendedSuggestions) {
|
|
||||||
mSuggestions = gatheredSuggestions;
|
|
||||||
mHasRecommendedSuggestions = hasRecommendedSuggestions;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ArrayList<String> mSuggestions;
|
|
||||||
private final ArrayList<Integer> mScores;
|
|
||||||
private final String mOriginalText;
|
|
||||||
private final float mRecommendedThreshold;
|
|
||||||
private final int mMaxLength;
|
|
||||||
|
|
||||||
SuggestionsGatherer(final String originalText, final float recommendedThreshold,
|
|
||||||
final int maxLength) {
|
|
||||||
mOriginalText = originalText;
|
|
||||||
mRecommendedThreshold = recommendedThreshold;
|
|
||||||
mMaxLength = maxLength;
|
|
||||||
mSuggestions = new ArrayList<>();
|
|
||||||
mScores = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addResults(final SuggestionResults suggestionResults) {
|
|
||||||
if (suggestionResults == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// suggestionResults is sorted.
|
|
||||||
for (final SuggestedWordInfo suggestedWordInfo : suggestionResults) {
|
|
||||||
mSuggestions.add(suggestedWordInfo.mWord);
|
|
||||||
mScores.add(suggestedWordInfo.mScore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result getResults(final int capitalizeType, final Locale locale) {
|
|
||||||
final String[] gatheredSuggestions;
|
|
||||||
final boolean hasRecommendedSuggestions;
|
|
||||||
if (mSuggestions.isEmpty()) {
|
|
||||||
gatheredSuggestions = null;
|
|
||||||
hasRecommendedSuggestions = false;
|
|
||||||
} else {
|
|
||||||
if (DBG) {
|
|
||||||
for (int i = 0; i < mSuggestions.size(); i++) {
|
|
||||||
Log.i(TAG, "" + mScores.get(i) + " " + mSuggestions.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StringUtils.removeDupes(mSuggestions);
|
|
||||||
if (StringUtils.CAPITALIZE_ALL == capitalizeType) {
|
|
||||||
for (int i = 0; i < mSuggestions.size(); ++i) {
|
|
||||||
// get(i) returns a CharSequence which is actually a String so .toString()
|
|
||||||
// should return the same object.
|
|
||||||
mSuggestions.set(i, mSuggestions.get(i).toString().toUpperCase(locale));
|
|
||||||
}
|
|
||||||
} else if (StringUtils.CAPITALIZE_FIRST == capitalizeType) {
|
|
||||||
for (int i = 0; i < mSuggestions.size(); ++i) {
|
|
||||||
// Likewise
|
|
||||||
mSuggestions.set(i, StringUtils.capitalizeFirstCodePoint(
|
|
||||||
mSuggestions.get(i).toString(), locale));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// This returns a String[], while toArray() returns an Object[] which cannot be cast
|
|
||||||
// into a String[].
|
|
||||||
gatheredSuggestions = mSuggestions.toArray(EMPTY_STRING_ARRAY);
|
|
||||||
|
|
||||||
final int bestScore = mScores.get(0);
|
|
||||||
final String bestSuggestion = mSuggestions.get(0);
|
|
||||||
final float normalizedScore =
|
|
||||||
BinaryDictionaryUtils.calcNormalizedScore(
|
|
||||||
mOriginalText, bestSuggestion.toString(), bestScore);
|
|
||||||
hasRecommendedSuggestions = (normalizedScore > mRecommendedThreshold);
|
|
||||||
if (DBG) {
|
|
||||||
Log.i(TAG, "Best suggestion : " + bestSuggestion + ", score " + bestScore);
|
|
||||||
Log.i(TAG, "Normalized score = " + normalizedScore
|
|
||||||
+ " (threshold " + mRecommendedThreshold
|
|
||||||
+ ") => hasRecommendedSuggestions = " + hasRecommendedSuggestions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new Result(gatheredSuggestions, hasRecommendedSuggestions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isValidWord(final Locale locale, final String word) {
|
public boolean isValidWord(final Locale locale, final String word) {
|
||||||
mSemaphore.acquireUninterruptibly();
|
mSemaphore.acquireUninterruptibly();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -32,7 +32,6 @@ import java.util.Locale;
|
||||||
public final class AndroidSpellCheckerSession extends AndroidWordLevelSpellCheckerSession {
|
public final class AndroidSpellCheckerSession extends AndroidWordLevelSpellCheckerSession {
|
||||||
private static final String TAG = AndroidSpellCheckerSession.class.getSimpleName();
|
private static final String TAG = AndroidSpellCheckerSession.class.getSimpleName();
|
||||||
private static final boolean DBG = false;
|
private static final boolean DBG = false;
|
||||||
private final static String[] EMPTY_STRING_ARRAY = new String[0];
|
|
||||||
private final Resources mResources;
|
private final Resources mResources;
|
||||||
private SentenceLevelAdapter mSentenceLevelAdapter;
|
private SentenceLevelAdapter mSentenceLevelAdapter;
|
||||||
|
|
||||||
|
|
|
@ -34,20 +34,22 @@ import com.android.inputmethod.latin.Constants;
|
||||||
import com.android.inputmethod.latin.PrevWordsInfo;
|
import com.android.inputmethod.latin.PrevWordsInfo;
|
||||||
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
||||||
import com.android.inputmethod.latin.WordComposer;
|
import com.android.inputmethod.latin.WordComposer;
|
||||||
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
|
import com.android.inputmethod.latin.utils.BinaryDictionaryUtils;
|
||||||
import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService.SuggestionsGatherer;
|
|
||||||
import com.android.inputmethod.latin.utils.CoordinateUtils;
|
import com.android.inputmethod.latin.utils.CoordinateUtils;
|
||||||
import com.android.inputmethod.latin.utils.LocaleUtils;
|
import com.android.inputmethod.latin.utils.LocaleUtils;
|
||||||
import com.android.inputmethod.latin.utils.ScriptUtils;
|
import com.android.inputmethod.latin.utils.ScriptUtils;
|
||||||
import com.android.inputmethod.latin.utils.StringUtils;
|
import com.android.inputmethod.latin.utils.StringUtils;
|
||||||
import com.android.inputmethod.latin.utils.SuggestionResults;
|
import com.android.inputmethod.latin.utils.SuggestionResults;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public abstract class AndroidWordLevelSpellCheckerSession extends Session {
|
public abstract class AndroidWordLevelSpellCheckerSession extends Session {
|
||||||
private static final String TAG = AndroidWordLevelSpellCheckerSession.class.getSimpleName();
|
private static final String TAG = AndroidWordLevelSpellCheckerSession.class.getSimpleName();
|
||||||
private static final boolean DBG = false;
|
private static final boolean DBG = false;
|
||||||
|
|
||||||
|
public final static String[] EMPTY_STRING_ARRAY = new String[0];
|
||||||
|
|
||||||
// Immutable, but not available in the constructor.
|
// Immutable, but not available in the constructor.
|
||||||
private Locale mLocale;
|
private Locale mLocale;
|
||||||
// Cache this for performance
|
// Cache this for performance
|
||||||
|
@ -279,14 +281,11 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
|
||||||
proximityInfo = keyboard.getProximityInfo();
|
proximityInfo = keyboard.getProximityInfo();
|
||||||
}
|
}
|
||||||
composer.setComposingWord(codePoints, coordinates);
|
composer.setComposingWord(codePoints, coordinates);
|
||||||
|
// TODO: Don't gather suggestions if the limit is <= 0 unless necessary
|
||||||
final SuggestionResults suggestionResults = mService.getSuggestionResults(
|
final SuggestionResults suggestionResults = mService.getSuggestionResults(
|
||||||
mLocale, composer, prevWordsInfo, proximityInfo);
|
mLocale, composer, prevWordsInfo, proximityInfo);
|
||||||
// TODO: Don't gather suggestions if the limit is <= 0 unless necessary
|
final Result result = getResult(capitalizeType, mLocale, suggestionsLimit,
|
||||||
final SuggestionsGatherer suggestionsGatherer = mService.newSuggestionsGatherer(
|
mService.getRecommendedThreshold(), text, suggestionResults);
|
||||||
text, suggestionsLimit);
|
|
||||||
suggestionsGatherer.addResults(suggestionResults);
|
|
||||||
final SuggestionsGatherer.Result result = suggestionsGatherer.getResults(
|
|
||||||
capitalizeType, mLocale);
|
|
||||||
isInDict = isInDictForAnyCapitalization(text, capitalizeType);
|
isInDict = isInDictForAnyCapitalization(text, capitalizeType);
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
Log.i(TAG, "Spell checking results for " + text + " with suggestion limit "
|
Log.i(TAG, "Spell checking results for " + text + " with suggestion limit "
|
||||||
|
@ -324,6 +323,62 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class Result {
|
||||||
|
public final String[] mSuggestions;
|
||||||
|
public final boolean mHasRecommendedSuggestions;
|
||||||
|
public Result(final String[] gatheredSuggestions,
|
||||||
|
final boolean hasRecommendedSuggestions) {
|
||||||
|
mSuggestions = gatheredSuggestions;
|
||||||
|
mHasRecommendedSuggestions = hasRecommendedSuggestions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Result getResult(final int capitalizeType, final Locale locale,
|
||||||
|
final int suggestionsLimit, final float recommendedThreshold, final String originalText,
|
||||||
|
final SuggestionResults suggestionResults) {
|
||||||
|
if (suggestionResults.isEmpty() || suggestionsLimit <= 0) {
|
||||||
|
return new Result(null /* gatheredSuggestions */,
|
||||||
|
false /* hasRecommendedSuggestions */);
|
||||||
|
}
|
||||||
|
if (DBG) {
|
||||||
|
for (final SuggestedWordInfo suggestedWordInfo : suggestionResults) {
|
||||||
|
Log.i(TAG, "" + suggestedWordInfo.mScore + " " + suggestedWordInfo.mWord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final ArrayList<String> suggestions = new ArrayList<>();
|
||||||
|
for (final SuggestedWordInfo suggestedWordInfo : suggestionResults) {
|
||||||
|
final String suggestion;
|
||||||
|
if (StringUtils.CAPITALIZE_ALL == capitalizeType) {
|
||||||
|
suggestion = suggestedWordInfo.mWord.toUpperCase(locale);
|
||||||
|
} else if (StringUtils.CAPITALIZE_FIRST == capitalizeType) {
|
||||||
|
suggestion = StringUtils.capitalizeFirstCodePoint(
|
||||||
|
suggestedWordInfo.mWord, locale);
|
||||||
|
} else {
|
||||||
|
suggestion = suggestedWordInfo.mWord;
|
||||||
|
}
|
||||||
|
suggestions.add(suggestion);
|
||||||
|
}
|
||||||
|
StringUtils.removeDupes(suggestions);
|
||||||
|
// This returns a String[], while toArray() returns an Object[] which cannot be cast
|
||||||
|
// into a String[].
|
||||||
|
final String[] gatheredSuggestions =
|
||||||
|
suggestions.subList(0, Math.min(suggestions.size(), suggestionsLimit))
|
||||||
|
.toArray(EMPTY_STRING_ARRAY);
|
||||||
|
|
||||||
|
final int bestScore = suggestionResults.first().mScore;
|
||||||
|
final String bestSuggestion = suggestions.get(0);
|
||||||
|
final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore(
|
||||||
|
originalText, bestSuggestion.toString(), bestScore);
|
||||||
|
final boolean hasRecommendedSuggestions = (normalizedScore > recommendedThreshold);
|
||||||
|
if (DBG) {
|
||||||
|
Log.i(TAG, "Best suggestion : " + bestSuggestion + ", score " + bestScore);
|
||||||
|
Log.i(TAG, "Normalized score = " + normalizedScore
|
||||||
|
+ " (threshold " + recommendedThreshold
|
||||||
|
+ ") => hasRecommendedSuggestions = " + hasRecommendedSuggestions);
|
||||||
|
}
|
||||||
|
return new Result(gatheredSuggestions, hasRecommendedSuggestions);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The spell checker acts on its own behalf. That is needed, in particular, to be able to
|
* The spell checker acts on its own behalf. That is needed, in particular, to be able to
|
||||||
* access the dictionary files, which the provider restricts to the identity of Latin IME.
|
* access the dictionary files, which the provider restricts to the identity of Latin IME.
|
||||||
|
|
Loading…
Reference in New Issue