Merge "Improve multi-word suggestion handling for user history."

This commit is contained in:
Keisuke Kuroyanagi 2014-05-12 11:11:15 +00:00 committed by Android (Google) Code Review
commit 84070cbc74
3 changed files with 29 additions and 14 deletions

View file

@ -169,6 +169,8 @@ public final class Constants {
// How many continuous deletes at which to start deleting at a higher speed. // How many continuous deletes at which to start deleting at a higher speed.
public static final int DELETE_ACCELERATE_AT = 20; public static final int DELETE_ACCELERATE_AT = 20;
public static final String WORD_SEPARATOR = " ";
public static boolean isValidCoordinate(final int coordinate) { public static boolean isValidCoordinate(final int coordinate) {
// Detect {@link NOT_A_COORDINATE}, {@link SUGGESTION_STRIP_COORDINATE}, // Detect {@link NOT_A_COORDINATE}, {@link SUGGESTION_STRIP_COORDINATE},
// and {@link SPELL_CHECKER_COORDINATE}. // and {@link SPELL_CHECKER_COORDINATE}.

View file

@ -56,7 +56,7 @@ public class DictionaryFacilitatorForSuggest {
private boolean mIsUserDictEnabled = false; private boolean mIsUserDictEnabled = false;
private volatile CountDownLatch mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0); private volatile CountDownLatch mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0);
// To synchronize assigning mDictionaries to ensure closing dictionaries. // To synchronize assigning mDictionaries to ensure closing dictionaries.
private Object mLock = new Object(); private final Object mLock = new Object();
private static final String[] DICT_TYPES_ORDERED_TO_GET_SUGGESTION = private static final String[] DICT_TYPES_ORDERED_TO_GET_SUGGESTION =
new String[] { new String[] {
@ -372,30 +372,42 @@ public class DictionaryFacilitatorForSuggest {
public void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized, public void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized,
final String previousWord, final int timeStampInSeconds) { final String previousWord, final int timeStampInSeconds) {
final Dictionaries dictionaries = mDictionaries; final Dictionaries dictionaries = mDictionaries;
final String[] words = suggestion.split(Constants.WORD_SEPARATOR);
for (int i = 0; i < words.length; i++) {
final String currentWord = words[i];
final String prevWord = (i == 0) ? previousWord : words[i - 1];
final boolean wasCurrentWordAutoCapitalized = (i == 0) ? wasAutoCapitalized : false;
addWordToUserHistory(dictionaries, prevWord, currentWord,
wasCurrentWordAutoCapitalized, timeStampInSeconds);
}
}
private void addWordToUserHistory(final Dictionaries dictionaries, final String prevWord,
final String word, final boolean wasAutoCapitalized, final int timeStampInSeconds) {
final ExpandableBinaryDictionary userHistoryDictionary = final ExpandableBinaryDictionary userHistoryDictionary =
dictionaries.getSubDict(Dictionary.TYPE_USER_HISTORY); dictionaries.getSubDict(Dictionary.TYPE_USER_HISTORY);
if (userHistoryDictionary == null) { if (userHistoryDictionary == null) {
return; return;
} }
final int maxFreq = getMaxFrequency(suggestion); final int maxFreq = getMaxFrequency(word);
if (maxFreq == 0) { if (maxFreq == 0) {
return; return;
} }
final String suggestionLowerCase = suggestion.toLowerCase(dictionaries.mLocale); final String lowerCasedWord = word.toLowerCase(dictionaries.mLocale);
final String secondWord; final String secondWord;
if (wasAutoCapitalized) { if (wasAutoCapitalized) {
if (isValidWord(suggestion, false /* ignoreCase */) if (isValidWord(word, false /* ignoreCase */)
&& !isValidWord(suggestionLowerCase, false /* ignoreCase */)) { && !isValidWord(lowerCasedWord, false /* ignoreCase */)) {
// If the word was auto-capitalized and exists only as a capitalized word in the // If the word was auto-capitalized and exists only as a capitalized word in the
// dictionary, then we must not downcase it before registering it. For example, // dictionary, then we must not downcase it before registering it. For example,
// the name of the contacts in start-of-sentence position would come here with the // the name of the contacts in start-of-sentence position would come here with the
// wasAutoCapitalized flag: if we downcase it, we'd register a lower-case version // wasAutoCapitalized flag: if we downcase it, we'd register a lower-case version
// of that contact's name which would end up popping in suggestions. // of that contact's name which would end up popping in suggestions.
secondWord = suggestion; secondWord = word;
} else { } else {
// If however the word is not in the dictionary, or exists as a lower-case word // If however the word is not in the dictionary, or exists as a lower-case word
// only, then we consider that was a lower-case word that had been auto-capitalized. // only, then we consider that was a lower-case word that had been auto-capitalized.
secondWord = suggestionLowerCase; secondWord = lowerCasedWord;
} }
} else { } else {
// HACK: We'd like to avoid adding the capitalized form of common words to the User // HACK: We'd like to avoid adding the capitalized form of common words to the User
@ -403,20 +415,20 @@ public class DictionaryFacilitatorForSuggest {
// consolidation is done. // consolidation is done.
// TODO: Remove this hack when ready. // TODO: Remove this hack when ready.
final int lowerCaseFreqInMainDict = dictionaries.hasDict(Dictionary.TYPE_MAIN) ? final int lowerCaseFreqInMainDict = dictionaries.hasDict(Dictionary.TYPE_MAIN) ?
dictionaries.getDict(Dictionary.TYPE_MAIN).getFrequency(suggestionLowerCase) : dictionaries.getDict(Dictionary.TYPE_MAIN).getFrequency(lowerCasedWord) :
Dictionary.NOT_A_PROBABILITY; Dictionary.NOT_A_PROBABILITY;
if (maxFreq < lowerCaseFreqInMainDict if (maxFreq < lowerCaseFreqInMainDict
&& lowerCaseFreqInMainDict >= CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT) { && lowerCaseFreqInMainDict >= CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT) {
// Use lower cased word as the word can be a distracter of the popular word. // Use lower cased word as the word can be a distracter of the popular word.
secondWord = suggestionLowerCase; secondWord = lowerCasedWord;
} else { } else {
secondWord = suggestion; secondWord = word;
} }
} }
// We demote unrecognized words (frequency < 0, below) by specifying them as "invalid". // We demote unrecognized words (frequency < 0, below) by specifying them as "invalid".
// We don't add words with 0-frequency (assuming they would be profanity etc.). // We don't add words with 0-frequency (assuming they would be profanity etc.).
final boolean isValid = maxFreq > 0; final boolean isValid = maxFreq > 0;
UserHistoryDictionary.addToDictionary(userHistoryDictionary, previousWord, secondWord, UserHistoryDictionary.addToDictionary(userHistoryDictionary, prevWord, secondWord,
isValid, timeStampInSeconds); isValid, timeStampInSeconds);
} }

View file

@ -604,7 +604,7 @@ public final class InputLogic {
if (null != candidate if (null != candidate
&& mSuggestedWords.mSequenceNumber >= mAutoCommitSequenceNumber) { && mSuggestedWords.mSequenceNumber >= mAutoCommitSequenceNumber) {
if (candidate.mSourceDict.shouldAutoCommit(candidate)) { if (candidate.mSourceDict.shouldAutoCommit(candidate)) {
final String[] commitParts = candidate.mWord.split(" ", 2); final String[] commitParts = candidate.mWord.split(Constants.WORD_SEPARATOR, 2);
batchPointers.shift(candidate.mIndexOfTouchPointOfSecondWord); batchPointers.shift(candidate.mIndexOfTouchPointOfSecondWord);
promotePhantomSpace(settingsValues); promotePhantomSpace(settingsValues);
mConnection.commitText(commitParts[0], 0); mConnection.commitText(commitParts[0], 0);
@ -1962,10 +1962,11 @@ public final class InputLogic {
final CharSequence chosenWordWithSuggestions = final CharSequence chosenWordWithSuggestions =
SuggestionSpanUtils.getTextWithSuggestionSpan(mLatinIME, chosenWord, SuggestionSpanUtils.getTextWithSuggestionSpan(mLatinIME, chosenWord,
suggestedWords); suggestedWords);
mConnection.commitText(chosenWordWithSuggestions, 1); // Use the 2nd previous word as the previous word because the 1st previous word is the word
// TODO: we pass 2 here, but would it be better to move this above and pass 1 instead? // to be committed.
final String prevWord = mConnection.getNthPreviousWord( final String prevWord = mConnection.getNthPreviousWord(
settingsValues.mSpacingAndPunctuations, 2); settingsValues.mSpacingAndPunctuations, 2);
mConnection.commitText(chosenWordWithSuggestions, 1);
// Add the word to the user history dictionary // Add the word to the user history dictionary
performAdditionToUserHistoryDictionary(settingsValues, chosenWord, prevWord); performAdditionToUserHistoryDictionary(settingsValues, chosenWord, prevWord);
// TODO: figure out here if this is an auto-correct or if the best word is actually // TODO: figure out here if this is an auto-correct or if the best word is actually