Make PrevWordsInfo have multiple words' information.

Bug: 14425059
Change-Id: I2bd6a872904a44b80f638a13d91a97559217cc1a
Keisuke Kuroyanagi 2014-06-25 14:14:37 +09:00
parent 9bbc3aa02a
commit e708b1bc2e
18 changed files with 181 additions and 83 deletions

View File

@ -259,9 +259,8 @@ public final class BinaryDictionary extends Dictionary {
} }
final DicTraverseSession session = getTraverseSession(sessionId); final DicTraverseSession session = getTraverseSession(sessionId);
Arrays.fill(session.mInputCodePoints, Constants.NOT_A_CODE); Arrays.fill(session.mInputCodePoints, Constants.NOT_A_CODE);
// TODO: toLowerCase in the native code prevWordsInfo.outputToArray(session.mPrevWordCodePointArrays,
final int[] prevWordCodePointArray = (null == prevWordsInfo.mPrevWord) session.mIsBeginningOfSentenceArray);
? null : StringUtils.toCodePointArray(prevWordsInfo.mPrevWord);
final InputPointers inputPointers = composer.getInputPointers(); final InputPointers inputPointers = composer.getInputPointers();
final boolean isGesture = composer.isBatchMode(); final boolean isGesture = composer.isBatchMode();
final int inputSize; final int inputSize;
@ -283,13 +282,13 @@ public final class BinaryDictionary extends Dictionary {
} else { } else {
session.mInputOutputLanguageWeight[0] = Dictionary.NOT_A_LANGUAGE_WEIGHT; session.mInputOutputLanguageWeight[0] = Dictionary.NOT_A_LANGUAGE_WEIGHT;
} }
// proximityInfo and/or prevWordForBigrams may not be null. // TOOD: Pass multiple previous words information for n-gram.
getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(),
getTraverseSession(sessionId).getSession(), inputPointers.getXCoordinates(), getTraverseSession(sessionId).getSession(), inputPointers.getXCoordinates(),
inputPointers.getYCoordinates(), inputPointers.getTimes(), inputPointers.getYCoordinates(), inputPointers.getTimes(),
inputPointers.getPointerIds(), session.mInputCodePoints, inputSize, inputPointers.getPointerIds(), session.mInputCodePoints, inputSize,
session.mNativeSuggestOptions.getOptions(), prevWordCodePointArray, session.mNativeSuggestOptions.getOptions(), session.mPrevWordCodePointArrays[0],
prevWordsInfo.mIsBeginningOfSentence, session.mOutputSuggestionCount, session.mIsBeginningOfSentenceArray[0], session.mOutputSuggestionCount,
session.mOutputCodePoints, session.mOutputScores, session.mSpaceIndices, session.mOutputCodePoints, session.mOutputScores, session.mSpaceIndices,
session.mOutputTypes, session.mOutputAutoCommitFirstWordConfidence, session.mOutputTypes, session.mOutputAutoCommitFirstWordConfidence,
session.mInputOutputLanguageWeight); session.mInputOutputLanguageWeight);
@ -352,10 +351,13 @@ public final class BinaryDictionary extends Dictionary {
if (!prevWordsInfo.isValid() || TextUtils.isEmpty(word)) { if (!prevWordsInfo.isValid() || TextUtils.isEmpty(word)) {
return NOT_A_PROBABILITY; return NOT_A_PROBABILITY;
} }
final int[] codePoints0 = StringUtils.toCodePointArray(prevWordsInfo.mPrevWord); final int[][] prevWordCodePointArrays = new int[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM][];
final int[] codePoints1 = StringUtils.toCodePointArray(word); final boolean[] isBeginningOfSentenceArray =
return getBigramProbabilityNative(mNativeDict, codePoints0, new boolean[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
prevWordsInfo.mIsBeginningOfSentence, codePoints1); prevWordsInfo.outputToArray(prevWordCodePointArrays, isBeginningOfSentenceArray);
final int[] wordCodePoints = StringUtils.toCodePointArray(word);
return getBigramProbabilityNative(mNativeDict, prevWordCodePointArrays[0],
isBeginningOfSentenceArray[0], wordCodePoints);
} }
public WordProperty getWordProperty(final String word) { public WordProperty getWordProperty(final String word) {
@ -442,10 +444,13 @@ public final class BinaryDictionary extends Dictionary {
if (!prevWordsInfo.isValid() || TextUtils.isEmpty(word)) { if (!prevWordsInfo.isValid() || TextUtils.isEmpty(word)) {
return false; return false;
} }
final int[] codePoints0 = StringUtils.toCodePointArray(prevWordsInfo.mPrevWord); final int[][] prevWordCodePointArrays = new int[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM][];
final int[] codePoints1 = StringUtils.toCodePointArray(word); final boolean[] isBeginningOfSentenceArray =
if (!addBigramWordsNative(mNativeDict, codePoints0, prevWordsInfo.mIsBeginningOfSentence, new boolean[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
codePoints1, probability, timestamp)) { prevWordsInfo.outputToArray(prevWordCodePointArrays, isBeginningOfSentenceArray);
final int[] wordCodePoints = StringUtils.toCodePointArray(word);
if (!addBigramWordsNative(mNativeDict, prevWordCodePointArrays[0],
isBeginningOfSentenceArray[0], wordCodePoints, probability, timestamp)) {
return false; return false;
} }
mHasUpdated = true; mHasUpdated = true;
@ -457,10 +462,13 @@ public final class BinaryDictionary extends Dictionary {
if (!prevWordsInfo.isValid() || TextUtils.isEmpty(word)) { if (!prevWordsInfo.isValid() || TextUtils.isEmpty(word)) {
return false; return false;
} }
final int[] codePoints0 = StringUtils.toCodePointArray(prevWordsInfo.mPrevWord); final int[][] prevWordCodePointArrays = new int[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM][];
final int[] codePoints1 = StringUtils.toCodePointArray(word); final boolean[] isBeginningOfSentenceArray =
if (!removeBigramWordsNative(mNativeDict, codePoints0, prevWordsInfo.mIsBeginningOfSentence, new boolean[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
codePoints1)) { prevWordsInfo.outputToArray(prevWordCodePointArrays, isBeginningOfSentenceArray);
final int[] wordCodePoints = StringUtils.toCodePointArray(word);
if (!removeBigramWordsNative(mNativeDict, prevWordCodePointArrays[0],
isBeginningOfSentenceArray[0], wordCodePoints)) {
return false; return false;
} }
mHasUpdated = true; mHasUpdated = true;

View File

@ -166,6 +166,10 @@ public final class Constants {
// Must be equal to MAX_WORD_LENGTH in native/jni/src/defines.h // Must be equal to MAX_WORD_LENGTH in native/jni/src/defines.h
public static final int DICTIONARY_MAX_WORD_LENGTH = 48; public static final int DICTIONARY_MAX_WORD_LENGTH = 48;
// (MAX_PREV_WORD_COUNT_FOR_N_GRAM + 1)-gram is supported in Java side. Needs to modify
// MAX_PREV_WORD_COUNT_FOR_N_GRAM in native/jni/src/defines.h for suggestions.
public static final int MAX_PREV_WORD_COUNT_FOR_N_GRAM = 2;
// Key events coming any faster than this are long-presses. // Key events coming any faster than this are long-presses.
public static final int LONG_PRESS_MILLISECONDS = 200; public static final int LONG_PRESS_MILLISECONDS = 200;
// TODO: Set this value appropriately. // TODO: Set this value appropriately.

View File

@ -233,19 +233,19 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
final int wordLen = StringUtils.codePointCount(word); final int wordLen = StringUtils.codePointCount(word);
if (wordLen < MAX_WORD_LENGTH && wordLen > 1) { if (wordLen < MAX_WORD_LENGTH && wordLen > 1) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "addName " + name + ", " + word + ", " Log.d(TAG, "addName " + name + ", " + word + ", " + prevWordsInfo);
+ prevWordsInfo.mPrevWord);
} }
runGCIfRequiredLocked(true /* mindsBlockByGC */); runGCIfRequiredLocked(true /* mindsBlockByGC */);
addUnigramLocked(word, FREQUENCY_FOR_CONTACTS, addUnigramLocked(word, FREQUENCY_FOR_CONTACTS,
null /* shortcut */, 0 /* shortcutFreq */, false /* isNotAWord */, null /* shortcut */, 0 /* shortcutFreq */, false /* isNotAWord */,
false /* isBlacklisted */, BinaryDictionary.NOT_A_VALID_TIMESTAMP); false /* isBlacklisted */, BinaryDictionary.NOT_A_VALID_TIMESTAMP);
if (!TextUtils.isEmpty(prevWordsInfo.mPrevWord) && mUseFirstLastBigrams) { if (!prevWordsInfo.isValid() && mUseFirstLastBigrams) {
runGCIfRequiredLocked(true /* mindsBlockByGC */); runGCIfRequiredLocked(true /* mindsBlockByGC */);
addNgramEntryLocked(prevWordsInfo, word, FREQUENCY_FOR_CONTACTS_BIGRAM, addNgramEntryLocked(prevWordsInfo, word, FREQUENCY_FOR_CONTACTS_BIGRAM,
BinaryDictionary.NOT_A_VALID_TIMESTAMP); BinaryDictionary.NOT_A_VALID_TIMESTAMP);
} }
prevWordsInfo = new PrevWordsInfo(word); prevWordsInfo = prevWordsInfo.getNextPrevWordsInfo(
new PrevWordsInfo.WordInfo(word));
} }
} }
} }

View File

@ -28,6 +28,10 @@ public final class DicTraverseSession {
// Must be equal to MAX_RESULTS in native/jni/src/defines.h // Must be equal to MAX_RESULTS in native/jni/src/defines.h
private static final int MAX_RESULTS = 18; private static final int MAX_RESULTS = 18;
public final int[] mInputCodePoints = new int[Constants.DICTIONARY_MAX_WORD_LENGTH]; public final int[] mInputCodePoints = new int[Constants.DICTIONARY_MAX_WORD_LENGTH];
public final int[][] mPrevWordCodePointArrays =
new int[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM][];
public final boolean[] mIsBeginningOfSentenceArray =
new boolean[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
public final int[] mOutputSuggestionCount = new int[1]; public final int[] mOutputSuggestionCount = new int[1];
public final int[] mOutputCodePoints = public final int[] mOutputCodePoints =
new int[Constants.DICTIONARY_MAX_WORD_LENGTH * MAX_RESULTS]; new int[Constants.DICTIONARY_MAX_WORD_LENGTH * MAX_RESULTS];

View File

@ -23,6 +23,7 @@ import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.PrevWordsInfo.WordInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.personalization.ContextualDictionary; import com.android.inputmethod.latin.personalization.ContextualDictionary;
import com.android.inputmethod.latin.personalization.PersonalizationDataChunk; import com.android.inputmethod.latin.personalization.PersonalizationDataChunk;
@ -407,13 +408,14 @@ public class DictionaryFacilitator {
final boolean blockPotentiallyOffensive) { final boolean blockPotentiallyOffensive) {
final Dictionaries dictionaries = mDictionaries; final Dictionaries dictionaries = mDictionaries;
final String[] words = suggestion.split(Constants.WORD_SEPARATOR); final String[] words = suggestion.split(Constants.WORD_SEPARATOR);
PrevWordsInfo prevWordsInfoForCurrentWord = prevWordsInfo;
for (int i = 0; i < words.length; i++) { for (int i = 0; i < words.length; i++) {
final String currentWord = words[i]; final String currentWord = words[i];
final PrevWordsInfo prevWordsInfoForCurrentWord =
(i == 0) ? prevWordsInfo : new PrevWordsInfo(words[i - 1]);
final boolean wasCurrentWordAutoCapitalized = (i == 0) ? wasAutoCapitalized : false; final boolean wasCurrentWordAutoCapitalized = (i == 0) ? wasAutoCapitalized : false;
addWordToUserHistory(dictionaries, prevWordsInfoForCurrentWord, currentWord, addWordToUserHistory(dictionaries, prevWordsInfoForCurrentWord, currentWord,
wasCurrentWordAutoCapitalized, timeStampInSeconds, blockPotentiallyOffensive); wasCurrentWordAutoCapitalized, timeStampInSeconds, blockPotentiallyOffensive);
prevWordsInfoForCurrentWord =
prevWordsInfoForCurrentWord.getNextPrevWordsInfo(new WordInfo(currentWord));
} }
} }
@ -647,7 +649,8 @@ public class DictionaryFacilitator {
contextualDict.addNgramEntry(prevWordsInfo, phrase[i], contextualDict.addNgramEntry(prevWordsInfo, phrase[i],
bigramProbabilityForWords, BinaryDictionary.NOT_A_VALID_TIMESTAMP); bigramProbabilityForWords, BinaryDictionary.NOT_A_VALID_TIMESTAMP);
} }
prevWordsInfo = new PrevWordsInfo(phrase[i]); prevWordsInfo =
prevWordsInfo.getNextPrevWordsInfo(new PrevWordsInfo.WordInfo(phrase[i]));
} }
} }

View File

@ -426,10 +426,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
if (mBinaryDictionary == null) { if (mBinaryDictionary == null) {
return null; return null;
} }
if (composer.size() == 0 && prevWordsInfo.mIsBeginningOfSentence
&& !enableBeginningOfSentencePrediction()) {
return null;
}
final ArrayList<SuggestedWordInfo> suggestions = final ArrayList<SuggestedWordInfo> suggestions =
mBinaryDictionary.getSuggestions(composer, prevWordsInfo, proximityInfo, mBinaryDictionary.getSuggestions(composer, prevWordsInfo, proximityInfo,
blockOffensiveWords, additionalFeaturesOptions, sessionId, blockOffensiveWords, additionalFeaturesOptions, sessionId,

View File

@ -16,47 +16,122 @@
package com.android.inputmethod.latin; package com.android.inputmethod.latin;
import java.util.Arrays;
import com.android.inputmethod.latin.utils.StringUtils;
/** /**
* Class to represent information of previous words. This class is used to add n-gram entries * Class to represent information of previous words. This class is used to add n-gram entries
* into binary dictionaries, to get predictions, and to get suggestions. * into binary dictionaries, to get predictions, and to get suggestions.
*/ */
// TODO: Support multiple previous words for n-gram.
public class PrevWordsInfo { public class PrevWordsInfo {
public static final PrevWordsInfo EMPTY_PREV_WORDS_INFO = new PrevWordsInfo(null); public static final PrevWordsInfo EMPTY_PREV_WORDS_INFO =
new PrevWordsInfo(WordInfo.EMPTY_WORD_INFO);
public static final PrevWordsInfo BEGINNING_OF_SENTENCE = new PrevWordsInfo(); public static final PrevWordsInfo BEGINNING_OF_SENTENCE = new PrevWordsInfo();
// The word immediately before the considered word. null means we don't have any context /**
// including the "beginning of sentence context" - we just don't know what to predict. * Word information used to represent previous words information.
// An example of that is after a comma. */
// For simplicity of implementation, this may also be null transiently after the WordComposer public static class WordInfo {
// was reset and before starting a new composing word, but we should never be calling public static final WordInfo EMPTY_WORD_INFO = new WordInfo(null);
// getSuggetions* in this situation. public static final WordInfo BEGINNING_OF_SENTENCE = new WordInfo();
// This is an empty string when mIsBeginningOfSentence is true.
public final String mPrevWord;
// TODO: Have sentence separator. // This is an empty string when mIsBeginningOfSentence is true.
// Whether the current context is beginning of sentence or not. This is true when composing at public final String mWord;
// the beginning of an input field or composing a word after a sentence separator. // TODO: Have sentence separator.
public final boolean mIsBeginningOfSentence; // Whether the current context is beginning of sentence or not. This is true when composing
// at the beginning of an input field or composing a word after a sentence separator.
public final boolean mIsBeginningOfSentence;
// Beginning of sentence.
public WordInfo() {
mWord = "";
mIsBeginningOfSentence = true;
}
public WordInfo(final String word) {
mWord = word;
mIsBeginningOfSentence = false;
}
public boolean isValid() {
return mWord != null;
}
}
// The words immediately before the considered word. EMPTY_WORD_INFO element means we don't
// have any context for that previous word including the "beginning of sentence context" - we
// just don't know what to predict using the information. An example of that is after a comma.
// For simplicity of implementation, elements may also be EMPTY_WORD_INFO transiently after the
// WordComposer was reset and before starting a new composing word, but we should never be
// calling getSuggetions* in this situation.
public WordInfo[] mPrevWordsInfo = new WordInfo[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
// Beginning of sentence. // Beginning of sentence.
public PrevWordsInfo() { public PrevWordsInfo() {
mPrevWord = ""; mPrevWordsInfo[0] = WordInfo.BEGINNING_OF_SENTENCE;
mIsBeginningOfSentence = true; Arrays.fill(mPrevWordsInfo, 1 /* start */, mPrevWordsInfo.length, WordInfo.EMPTY_WORD_INFO);
} }
public PrevWordsInfo(final String prevWord) { // Construct from the previous word information.
mPrevWord = prevWord; public PrevWordsInfo(final WordInfo prevWordInfo) {
mIsBeginningOfSentence = false; mPrevWordsInfo[0] = prevWordInfo;
Arrays.fill(mPrevWordsInfo, 1 /* start */, mPrevWordsInfo.length, WordInfo.EMPTY_WORD_INFO);
}
// Construct from WordInfo array. n-th element represents (n+1)-th previous word's information.
public PrevWordsInfo(final WordInfo[] prevWordsInfo) {
for (int i = 0; i < Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM; i++) {
mPrevWordsInfo[i] =
(prevWordsInfo.length > i) ? prevWordsInfo[i] : WordInfo.EMPTY_WORD_INFO;
}
}
// Create next prevWordsInfo using current prevWordsInfo.
public PrevWordsInfo getNextPrevWordsInfo(final WordInfo wordInfo) {
final WordInfo[] prevWordsInfo = new WordInfo[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
prevWordsInfo[0] = wordInfo;
for (int i = 1; i < prevWordsInfo.length; i++) {
prevWordsInfo[i] = mPrevWordsInfo[i - 1];
}
return new PrevWordsInfo(prevWordsInfo);
} }
public boolean isValid() { public boolean isValid() {
return mPrevWord != null; return mPrevWordsInfo[0].isValid();
}
public void outputToArray(final int[][] codePointArrays,
final boolean[] isBeginningOfSentenceArray) {
for (int i = 0; i < mPrevWordsInfo.length; i++) {
final WordInfo wordInfo = mPrevWordsInfo[i];
if (wordInfo == null || !wordInfo.isValid()) {
codePointArrays[i] = new int[0];
isBeginningOfSentenceArray[i] = false;
continue;
}
codePointArrays[i] = StringUtils.toCodePointArray(wordInfo.mWord);
isBeginningOfSentenceArray[i] = wordInfo.mIsBeginningOfSentence;
}
} }
@Override @Override
public String toString() { public String toString() {
return "PrevWord: " + mPrevWord + ", isBeginningOfSentence: " final StringBuffer builder = new StringBuffer();
+ mIsBeginningOfSentence + "."; for (int i = 0; i < mPrevWordsInfo.length; i++) {
final WordInfo wordInfo = mPrevWordsInfo[i];
builder.append("PrevWord[");
builder.append(i);
builder.append("]: ");
if (!wordInfo.isValid()) {
builder.append("Empty. ");
continue;
}
builder.append(wordInfo.mWord);
builder.append(", isBeginningOfSentence: ");
builder.append(wordInfo.mIsBeginningOfSentence);
builder.append(". ");
}
return builder.toString();
} }
} }

View File

@ -603,7 +603,7 @@ public final class RichInputConnection {
|| spacingAndPunctuations.isWordConnector(lastChar)) { || spacingAndPunctuations.isWordConnector(lastChar)) {
return PrevWordsInfo.EMPTY_PREV_WORDS_INFO; return PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
} }
return new PrevWordsInfo(nthPrevWord); return new PrevWordsInfo(new PrevWordsInfo.WordInfo(nthPrevWord));
} }
/** /**

View File

@ -1528,7 +1528,8 @@ public final class InputLogic {
} else { } else {
return LastComposedWord.NOT_A_COMPOSED_WORD == mLastComposedWord ? return LastComposedWord.NOT_A_COMPOSED_WORD == mLastComposedWord ?
PrevWordsInfo.BEGINNING_OF_SENTENCE : PrevWordsInfo.BEGINNING_OF_SENTENCE :
new PrevWordsInfo(mLastComposedWord.mCommittedWord.toString()); new PrevWordsInfo(new PrevWordsInfo.WordInfo(
mLastComposedWord.mCommittedWord.toString()));
} }
} }

View File

@ -60,7 +60,7 @@ public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBas
public static void addToDictionary(final ExpandableBinaryDictionary userHistoryDictionary, public static void addToDictionary(final ExpandableBinaryDictionary userHistoryDictionary,
final PrevWordsInfo prevWordsInfo, final String word, final boolean isValid, final PrevWordsInfo prevWordsInfo, final String word, final boolean isValid,
final int timestamp, final DistracterFilter distracterFilter) { final int timestamp, final DistracterFilter distracterFilter) {
final String prevWord = prevWordsInfo.mPrevWord; final String prevWord = prevWordsInfo.mPrevWordsInfo[0].mWord;
if (word.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH || if (word.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH ||
(prevWord != null && prevWord.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH)) { (prevWord != null && prevWord.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH)) {
return; return;

View File

@ -61,7 +61,8 @@ public final class AndroidSpellCheckerSession extends AndroidWordLevelSpellCheck
final int offset = ssi.getOffsetAt(i); final int offset = ssi.getOffsetAt(i);
final int length = ssi.getLengthAt(i); final int length = ssi.getLengthAt(i);
final String subText = typedText.substring(offset, offset + length); final String subText = typedText.substring(offset, offset + length);
final PrevWordsInfo prevWordsInfo = new PrevWordsInfo(currentWord); final PrevWordsInfo prevWordsInfo =
new PrevWordsInfo(new PrevWordsInfo.WordInfo(currentWord));
currentWord = subText; currentWord = subText;
if (!subText.contains(AndroidSpellCheckerService.SINGLE_QUOTE)) { if (!subText.contains(AndroidSpellCheckerService.SINGLE_QUOTE)) {
continue; continue;
@ -203,7 +204,8 @@ public final class AndroidSpellCheckerSession extends AndroidWordLevelSpellCheck
} else { } else {
prevWord = null; prevWord = null;
} }
final PrevWordsInfo prevWordsInfo = new PrevWordsInfo(prevWord); final PrevWordsInfo prevWordsInfo =
new PrevWordsInfo(new PrevWordsInfo.WordInfo(prevWord));
retval[i] = onGetSuggestionsInternal(textInfos[i], prevWordsInfo, suggestionsLimit); retval[i] = onGetSuggestionsInternal(textInfos[i], prevWordsInfo, suggestionsLimit);
retval[i].setCookieAndSequence(textInfos[i].getCookie(), retval[i].setCookieAndSequence(textInfos[i].getCookie(),
textInfos[i].getSequence()); textInfos[i].getSequence());

View File

@ -72,10 +72,10 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
// TODO: Support n-gram input // TODO: Support n-gram input
private static String generateKey(final String query, final PrevWordsInfo prevWordsInfo) { private static String generateKey(final String query, final PrevWordsInfo prevWordsInfo) {
if (TextUtils.isEmpty(query) || TextUtils.isEmpty(prevWordsInfo.mPrevWord)) { if (TextUtils.isEmpty(query) || !prevWordsInfo.isValid()) {
return query; return query;
} }
return query + CHAR_DELIMITER + prevWordsInfo.mPrevWord; return query + CHAR_DELIMITER + prevWordsInfo;
} }
public SuggestionsParams getSuggestionsFromCache(String query, public SuggestionsParams getSuggestionsFromCache(String query,

View File

@ -117,7 +117,8 @@ public final class LanguageModelParam {
continue; continue;
} }
languageModelParams.add(languageModelParam); languageModelParams.add(languageModelParam);
prevWordsInfo = new PrevWordsInfo(languageModelParam.mTargetWord); prevWordsInfo = prevWordsInfo.getNextPrevWordsInfo(
new PrevWordsInfo.WordInfo(tempWord));
} }
return languageModelParams; return languageModelParams;
} }
@ -153,7 +154,7 @@ public final class LanguageModelParam {
final DistracterFilter distracterFilter) { final DistracterFilter distracterFilter) {
final String word; final String word;
if (StringUtils.getCapitalizationType(targetWord) == StringUtils.CAPITALIZE_FIRST if (StringUtils.getCapitalizationType(targetWord) == StringUtils.CAPITALIZE_FIRST
&& prevWordsInfo.mPrevWord == null && !isValidWord) { && !prevWordsInfo.isValid() && !isValidWord) {
word = targetWord.toLowerCase(locale); word = targetWord.toLowerCase(locale);
} else { } else {
word = targetWord; word = targetWord;
@ -167,7 +168,7 @@ public final class LanguageModelParam {
} }
final int unigramProbability = isValidWord ? final int unigramProbability = isValidWord ?
UNIGRAM_PROBABILITY_FOR_VALID_WORD : UNIGRAM_PROBABILITY_FOR_OOV_WORD; UNIGRAM_PROBABILITY_FOR_VALID_WORD : UNIGRAM_PROBABILITY_FOR_OOV_WORD;
if (prevWordsInfo.mPrevWord == null) { if (!prevWordsInfo.isValid()) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "--- add unigram: current(" Log.d(TAG, "--- add unigram: current("
+ (isValidWord ? "Valid" : "OOV") + ") = " + word); + (isValidWord ? "Valid" : "OOV") + ") = " + word);
@ -175,12 +176,12 @@ public final class LanguageModelParam {
return new LanguageModelParam(word, unigramProbability, timestamp); return new LanguageModelParam(word, unigramProbability, timestamp);
} }
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "--- add bigram: prev = " + prevWordsInfo.mPrevWord + ", current(" Log.d(TAG, "--- add bigram: prev = " + prevWordsInfo + ", current("
+ (isValidWord ? "Valid" : "OOV") + ") = " + word); + (isValidWord ? "Valid" : "OOV") + ") = " + word);
} }
final int bigramProbability = isValidWord ? final int bigramProbability = isValidWord ?
BIGRAM_PROBABILITY_FOR_VALID_WORD : BIGRAM_PROBABILITY_FOR_OOV_WORD; BIGRAM_PROBABILITY_FOR_VALID_WORD : BIGRAM_PROBABILITY_FOR_OOV_WORD;
return new LanguageModelParam(prevWordsInfo.mPrevWord, word, unigramProbability, return new LanguageModelParam(prevWordsInfo.mPrevWordsInfo[0].mWord, word,
bigramProbability, timestamp); unigramProbability, bigramProbability, timestamp);
} }
} }

View File

@ -20,6 +20,7 @@ import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.LargeTest;
import android.util.Pair; import android.util.Pair;
import com.android.inputmethod.latin.PrevWordsInfo.WordInfo;
import com.android.inputmethod.latin.makedict.BinaryDictIOUtils; import com.android.inputmethod.latin.makedict.BinaryDictIOUtils;
import com.android.inputmethod.latin.makedict.CodePointUtils; import com.android.inputmethod.latin.makedict.CodePointUtils;
import com.android.inputmethod.latin.makedict.DictDecoder; import com.android.inputmethod.latin.makedict.DictDecoder;
@ -77,13 +78,13 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
private void addBigramWords(final BinaryDictionary binaryDictionary, final String word0, private void addBigramWords(final BinaryDictionary binaryDictionary, final String word0,
final String word1, final int probability) { final String word1, final int probability) {
binaryDictionary.addNgramEntry(new PrevWordsInfo(word0), word1, probability, binaryDictionary.addNgramEntry(new PrevWordsInfo(new WordInfo(word0)), word1, probability,
mCurrentTime /* timestamp */); mCurrentTime /* timestamp */);
} }
private static boolean isValidBigram(final BinaryDictionary binaryDictionary, private static boolean isValidBigram(final BinaryDictionary binaryDictionary,
final String word0, final String word1) { final String word0, final String word1) {
return binaryDictionary.isValidNgram(new PrevWordsInfo(word0), word1); return binaryDictionary.isValidNgram(new PrevWordsInfo(new WordInfo(word0)), word1);
} }
private void forcePassingShortTime(final BinaryDictionary binaryDictionary) { private void forcePassingShortTime(final BinaryDictionary binaryDictionary) {

View File

@ -21,6 +21,7 @@ import android.test.suitebuilder.annotation.LargeTest;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Pair; import android.util.Pair;
import com.android.inputmethod.latin.PrevWordsInfo.WordInfo;
import com.android.inputmethod.latin.makedict.CodePointUtils; import com.android.inputmethod.latin.makedict.CodePointUtils;
import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FormatSpec;
import com.android.inputmethod.latin.makedict.WeightedString; import com.android.inputmethod.latin.makedict.WeightedString;
@ -203,23 +204,23 @@ public class BinaryDictionaryTests extends AndroidTestCase {
private static void addBigramWords(final BinaryDictionary binaryDictionary, final String word0, private static void addBigramWords(final BinaryDictionary binaryDictionary, final String word0,
final String word1, final int probability) { final String word1, final int probability) {
binaryDictionary.addNgramEntry(new PrevWordsInfo(word0), word1, probability, binaryDictionary.addNgramEntry(new PrevWordsInfo(new WordInfo(word0)), word1, probability,
BinaryDictionary.NOT_A_VALID_TIMESTAMP /* timestamp */); BinaryDictionary.NOT_A_VALID_TIMESTAMP /* timestamp */);
} }
private static boolean isValidBigram(final BinaryDictionary binaryDictionary, private static boolean isValidBigram(final BinaryDictionary binaryDictionary,
final String word0, final String word1) { final String word0, final String word1) {
return binaryDictionary.isValidNgram(new PrevWordsInfo(word0), word1); return binaryDictionary.isValidNgram(new PrevWordsInfo(new WordInfo(word0)), word1);
} }
private static void removeBigramEntry(final BinaryDictionary binaryDictionary, private static void removeBigramEntry(final BinaryDictionary binaryDictionary,
final String word0, final String word1) { final String word0, final String word1) {
binaryDictionary.removeNgramEntry(new PrevWordsInfo(word0), word1); binaryDictionary.removeNgramEntry(new PrevWordsInfo(new WordInfo(word0)), word1);
} }
private static int getBigramProbability(final BinaryDictionary binaryDictionary, private static int getBigramProbability(final BinaryDictionary binaryDictionary,
final String word0, final String word1) { final String word0, final String word1) {
return binaryDictionary.getNgramProbability(new PrevWordsInfo(word0), word1); return binaryDictionary.getNgramProbability(new PrevWordsInfo(new WordInfo(word0)), word1);
} }
public void testAddUnigramWord() { public void testAddUnigramWord() {

View File

@ -156,16 +156,16 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
public void testGetPreviousWord() { public void testGetPreviousWord() {
// If one of the following cases breaks, the bigram suggestions won't work. // If one of the following cases breaks, the bigram suggestions won't work.
assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord( assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord(
"abc def", mSpacingAndPunctuations, 2).mPrevWord, "abc"); "abc def", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "abc");
assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord( assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord(
"abc", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE); "abc", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE);
assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord( assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord(
"abc. def", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE); "abc. def", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE);
assertFalse(RichInputConnection.getPrevWordsInfoFromNthPreviousWord( assertFalse(RichInputConnection.getPrevWordsInfoFromNthPreviousWord(
"abc def", mSpacingAndPunctuations, 2).mIsBeginningOfSentence); "abc def", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mIsBeginningOfSentence);
assertTrue(RichInputConnection.getPrevWordsInfoFromNthPreviousWord( assertTrue(RichInputConnection.getPrevWordsInfoFromNthPreviousWord(
"abc", mSpacingAndPunctuations, 2).mIsBeginningOfSentence); "abc", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mIsBeginningOfSentence);
// The following tests reflect the current behavior of the function // The following tests reflect the current behavior of the function
// RichInputConnection#getNthPreviousWord. // RichInputConnection#getNthPreviousWord.
// TODO: However at this time, the code does never go // TODO: However at this time, the code does never go
@ -174,20 +174,20 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
// logical. These tests are just there to catch any unintentional // logical. These tests are just there to catch any unintentional
// changes in the behavior of the RichInputConnection#getPreviousWord method. // changes in the behavior of the RichInputConnection#getPreviousWord method.
assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord( assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord(
"abc def ", mSpacingAndPunctuations, 2).mPrevWord, "abc"); "abc def ", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "abc");
assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord( assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord(
"abc def.", mSpacingAndPunctuations, 2).mPrevWord, "abc"); "abc def.", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "abc");
assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord( assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord(
"abc def .", mSpacingAndPunctuations, 2).mPrevWord, "def"); "abc def .", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "def");
assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord( assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord(
"abc ", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE); "abc ", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE);
assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord( assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord(
"abc def", mSpacingAndPunctuations, 1).mPrevWord, "def"); "abc def", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "def");
assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord( assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord(
"abc def ", mSpacingAndPunctuations, 1).mPrevWord, "def"); "abc def ", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "def");
assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord( assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord(
"abc 'def", mSpacingAndPunctuations, 1).mPrevWord, "'def"); "abc 'def", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "'def");
assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord( assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord(
"abc def.", mSpacingAndPunctuations, 1), PrevWordsInfo.BEGINNING_OF_SENTENCE); "abc def.", mSpacingAndPunctuations, 1), PrevWordsInfo.BEGINNING_OF_SENTENCE);
assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord( assertEquals(RichInputConnection.getPrevWordsInfoFromNthPreviousWord(

View File

@ -104,7 +104,8 @@ public class Ver4DictEncoder implements DictEncoder {
for (final WordProperty word0Property : dict) { for (final WordProperty word0Property : dict) {
if (null == word0Property.mBigrams) continue; if (null == word0Property.mBigrams) continue;
for (final WeightedString word1 : word0Property.mBigrams) { for (final WeightedString word1 : word0Property.mBigrams) {
final PrevWordsInfo prevWordsInfo = new PrevWordsInfo(word0Property.mWord); final PrevWordsInfo prevWordsInfo =
new PrevWordsInfo(new PrevWordsInfo.WordInfo(word0Property.mWord));
if (!binaryDict.addNgramEntry(prevWordsInfo, word1.mWord, if (!binaryDict.addNgramEntry(prevWordsInfo, word1.mWord,
word1.getProbability(), 0 /* timestamp */)) { word1.getProbability(), 0 /* timestamp */)) {
MakedictLog.e("Cannot add n-gram entry for " MakedictLog.e("Cannot add n-gram entry for "

View File

@ -22,6 +22,7 @@ import android.util.Log;
import com.android.inputmethod.latin.ExpandableBinaryDictionary; import com.android.inputmethod.latin.ExpandableBinaryDictionary;
import com.android.inputmethod.latin.PrevWordsInfo; import com.android.inputmethod.latin.PrevWordsInfo;
import com.android.inputmethod.latin.PrevWordsInfo.WordInfo;
import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.BinaryDictionaryUtils;
import com.android.inputmethod.latin.utils.DistracterFilter; import com.android.inputmethod.latin.utils.DistracterFilter;
import com.android.inputmethod.latin.utils.FileUtils; import com.android.inputmethod.latin.utils.FileUtils;
@ -115,7 +116,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
UserHistoryDictionary.addToDictionary(dict, prevWordsInfo, word, true, UserHistoryDictionary.addToDictionary(dict, prevWordsInfo, word, true,
(int)TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()), (int)TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()),
DistracterFilter.EMPTY_DISTRACTER_FILTER); DistracterFilter.EMPTY_DISTRACTER_FILTER);
prevWordsInfo = new PrevWordsInfo(word); prevWordsInfo = prevWordsInfo.getNextPrevWordsInfo(new WordInfo(word));
} }
} }
@ -262,11 +263,11 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
final UserHistoryDictionary dict = final UserHistoryDictionary dict =
PersonalizationHelper.getUserHistoryDictionary(getContext(), dummyLocale); PersonalizationHelper.getUserHistoryDictionary(getContext(), dummyLocale);
dict.waitAllTasksForTests(); dict.waitAllTasksForTests();
PrevWordsInfo prevWordsInfo = new PrevWordsInfo(null); PrevWordsInfo prevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
for (final String word : words) { for (final String word : words) {
UserHistoryDictionary.addToDictionary(dict, prevWordsInfo, word, true, mCurrentTime, UserHistoryDictionary.addToDictionary(dict, prevWordsInfo, word, true, mCurrentTime,
DistracterFilter.EMPTY_DISTRACTER_FILTER); DistracterFilter.EMPTY_DISTRACTER_FILTER);
prevWordsInfo = new PrevWordsInfo(word); prevWordsInfo = prevWordsInfo.getNextPrevWordsInfo(new WordInfo(word));
dict.waitAllTasksForTests(); dict.waitAllTasksForTests();
assertTrue(dict.isInDictionary(word)); assertTrue(dict.isInDictionary(word));
} }