Skip decoding for in-vocabulary words.

The spell checker is decoding, and getting multiple sets of suggestions, for
every word it encounters. It even does that for in-vocabulary words, though
it will not underline or show suggestions for in-vocabulary words.

Bug 19987461.

Change-Id: Ie61101fa8ab8917f3f49c77768dbcffd96c1685e
main
Dan Zivkovic 2015-04-07 10:48:36 -07:00
parent ec2891b007
commit 3e66c6357d
1 changed files with 30 additions and 36 deletions

View File

@ -35,6 +35,7 @@ import com.android.inputmethod.latin.WordComposer;
import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.common.Constants;
import com.android.inputmethod.latin.common.LocaleUtils; import com.android.inputmethod.latin.common.LocaleUtils;
import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.common.StringUtils;
import com.android.inputmethod.latin.define.DebugFlags;
import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.BinaryDictionaryUtils;
import com.android.inputmethod.latin.utils.ScriptUtils; import com.android.inputmethod.latin.utils.ScriptUtils;
import com.android.inputmethod.latin.utils.StatsUtils; import com.android.inputmethod.latin.utils.StatsUtils;
@ -46,7 +47,6 @@ 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;
public final static String[] EMPTY_STRING_ARRAY = new String[0]; public final static String[] EMPTY_STRING_ARRAY = new String[0];
@ -227,13 +227,20 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
final String inText = textInfo.getText(); final String inText = textInfo.getText();
final SuggestionsParams cachedSuggestionsParams = final SuggestionsParams cachedSuggestionsParams =
mSuggestionsCache.getSuggestionsFromCache(inText, ngramContext); mSuggestionsCache.getSuggestionsFromCache(inText, ngramContext);
if (cachedSuggestionsParams != null) { if (cachedSuggestionsParams != null) {
if (DBG) { Log.d(TAG, "onGetSuggestionsInternal() : Cache hit for [" + inText + "]");
Log.d(TAG, "Cache hit: " + inText + ", " + cachedSuggestionsParams.mFlags);
}
return new SuggestionsInfo( return new SuggestionsInfo(
cachedSuggestionsParams.mFlags, cachedSuggestionsParams.mSuggestions); cachedSuggestionsParams.mFlags, cachedSuggestionsParams.mSuggestions);
} }
// If spell checking is impossible, return early.
if (!mService.hasMainDictionaryForLocale(mLocale)) {
return AndroidSpellCheckerService.getNotInDictEmptySuggestions(
false /* reportAsTypo */);
}
// Handle special patterns like email, URI, telephone number.
final int checkability = getCheckabilityInScript(inText, mScript); final int checkability = getCheckabilityInScript(inText, mScript);
if (CHECKABILITY_CHECKABLE != checkability) { if (CHECKABILITY_CHECKABLE != checkability) {
if (CHECKABILITY_CONTAINS_PERIOD == checkability) { if (CHECKABILITY_CONTAINS_PERIOD == checkability) {
@ -257,20 +264,26 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
AndroidSpellCheckerService.getNotInDictEmptySuggestions( AndroidSpellCheckerService.getNotInDictEmptySuggestions(
CHECKABILITY_CONTAINS_PERIOD == checkability /* reportAsTypo */); CHECKABILITY_CONTAINS_PERIOD == checkability /* reportAsTypo */);
} }
// Handle normal words.
final String text = inText.replaceAll( final String text = inText.replaceAll(
AndroidSpellCheckerService.APOSTROPHE, AndroidSpellCheckerService.SINGLE_QUOTE); AndroidSpellCheckerService.APOSTROPHE, AndroidSpellCheckerService.SINGLE_QUOTE);
final int capitalizeType = StringUtils.getCapitalizationType(text); final int capitalizeType = StringUtils.getCapitalizationType(text);
if (!mService.hasMainDictionaryForLocale(mLocale)) {
return AndroidSpellCheckerService.getNotInDictEmptySuggestions( if (isInDictForAnyCapitalization(text, capitalizeType)) {
false /* reportAsTypo */); Log.i(TAG, "onGetSuggestionsInternal() : [" + text + "] is a valid word");
return AndroidSpellCheckerService.getInDictEmptySuggestions();
} }
Log.i(TAG, "onGetSuggestionsInternal() : [" + text + "] is NOT a valid word");
final Keyboard keyboard = mService.getKeyboardForLocale(mLocale); final Keyboard keyboard = mService.getKeyboardForLocale(mLocale);
if (null == keyboard) { if (null == keyboard) {
Log.d(TAG, "No keyboard for locale: " + mLocale); Log.w(TAG, "onGetSuggestionsInternal() : No keyboard for locale: " + mLocale);
// If there is no keyboard for this locale, don't do any spell-checking. // If there is no keyboard for this locale, don't do any spell-checking.
return AndroidSpellCheckerService.getNotInDictEmptySuggestions( return AndroidSpellCheckerService.getNotInDictEmptySuggestions(
false /* reportAsTypo */); false /* reportAsTypo */);
} }
final WordComposer composer = new WordComposer(); final WordComposer composer = new WordComposer();
final int[] codePoints = StringUtils.toCodePointArray(text); final int[] codePoints = StringUtils.toCodePointArray(text);
final int[] coordinates; final int[] coordinates;
@ -281,17 +294,15 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
mLocale, composer.getComposedDataSnapshot(), ngramContext, keyboard); mLocale, composer.getComposedDataSnapshot(), ngramContext, keyboard);
final Result result = getResult(capitalizeType, mLocale, suggestionsLimit, final Result result = getResult(capitalizeType, mLocale, suggestionsLimit,
mService.getRecommendedThreshold(), text, suggestionResults); mService.getRecommendedThreshold(), text, suggestionResults);
final boolean isInDict = isInDictForAnyCapitalization(text, capitalizeType); if (DebugFlags.DEBUG_ENABLED) {
if (DBG) { if (result.mSuggestions != null && result.mSuggestions.length > 0) {
Log.i(TAG, "Spell checking results for " + text + " with suggestion limit " final StringBuilder builder = new StringBuilder();
+ suggestionsLimit);
Log.i(TAG, "IsInDict = " + isInDict);
Log.i(TAG, "LooksLikeTypo = " + (!isInDict));
Log.i(TAG, "HasRecommendedSuggestions = " + result.mHasRecommendedSuggestions);
if (null != result.mSuggestions) {
for (String suggestion : result.mSuggestions) { for (String suggestion : result.mSuggestions) {
Log.i(TAG, suggestion); builder.append(" [");
builder.append(suggestion);
builder.append("]");
} }
Log.i(TAG, "onGetSuggestionsInternal() : Suggestions =" + builder);
} }
} }
// Handle word not in dictionary. // Handle word not in dictionary.
@ -300,13 +311,10 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
// to this method. // to this method.
// Also, upon changing the orientation of the device, this is called // Also, upon changing the orientation of the device, this is called
// again for every unique invalid word in the text box. // again for every unique invalid word in the text box.
if (!isInDict) { StatsUtils.onInvalidWordIdentification(text);
StatsUtils.onInvalidWordIdentification(text);
}
final int flags = final int flags =
(isInDict ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO
: SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO)
| (result.mHasRecommendedSuggestions | (result.mHasRecommendedSuggestions
? SuggestionsInfoCompatUtils ? SuggestionsInfoCompatUtils
.getValueOf_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS() .getValueOf_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS()
@ -317,9 +325,6 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
return retval; return retval;
} catch (RuntimeException e) { } catch (RuntimeException e) {
// Don't kill the keyboard if there is a bug in the spell checker // Don't kill the keyboard if there is a bug in the spell checker
if (DBG) {
throw e;
}
Log.e(TAG, "Exception while spellchecking", e); Log.e(TAG, "Exception while spellchecking", e);
return AndroidSpellCheckerService.getNotInDictEmptySuggestions( return AndroidSpellCheckerService.getNotInDictEmptySuggestions(
false /* reportAsTypo */); false /* reportAsTypo */);
@ -342,11 +347,6 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
return new Result(null /* gatheredSuggestions */, return new Result(null /* gatheredSuggestions */,
false /* hasRecommendedSuggestions */); false /* hasRecommendedSuggestions */);
} }
if (DBG) {
for (final SuggestedWordInfo suggestedWordInfo : suggestionResults) {
Log.i(TAG, "" + suggestedWordInfo.mScore + " " + suggestedWordInfo.mWord);
}
}
final ArrayList<String> suggestions = new ArrayList<>(); final ArrayList<String> suggestions = new ArrayList<>();
for (final SuggestedWordInfo suggestedWordInfo : suggestionResults) { for (final SuggestedWordInfo suggestedWordInfo : suggestionResults) {
final String suggestion; final String suggestion;
@ -373,12 +373,6 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore( final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore(
originalText, bestSuggestion, bestScore); originalText, bestSuggestion, bestScore);
final boolean hasRecommendedSuggestions = (normalizedScore > recommendedThreshold); 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); return new Result(gatheredSuggestions, hasRecommendedSuggestions);
} }