diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 39cc56ae1..740b86d86 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -24,6 +24,7 @@ import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.personalization.DynamicPersonalizationDictionaryWriter; +import com.android.inputmethod.latin.personalization.DynamicPredictionDictionaryBase; import com.android.inputmethod.latin.utils.CollectionUtils; import java.io.File; @@ -72,7 +73,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { private BinaryDictionary mBinaryDictionary; /** The in-memory dictionary used to generate the binary dictionary. */ - private AbstractDictionaryWriter mDictionaryWriter; + protected AbstractDictionaryWriter mDictionaryWriter; /** * The name of this dictionary, used as the filename for storing the binary dictionary. Multiple @@ -624,4 +625,35 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { mLocalDictionaryController.writeLock().unlock(); } } + + // TODO: Implement native binary methods once the dynamic dictionary implementation is done. + @UsedForTesting + public boolean isInDictionaryForTests(final String word) { + mLocalDictionaryController.writeLock().lock(); + try { + if (mDictType == Dictionary.TYPE_USER_HISTORY) { + return ((DynamicPersonalizationDictionaryWriter) mDictionaryWriter) + .isInDictionaryForTests(word); + } + } finally { + mLocalDictionaryController.writeLock().unlock(); + } + return false; + } + + // TODO: Remove and use addToPersonalizationPredictionDictionary instead!!!!!!!!!!!!!!!! + @UsedForTesting + public void forceAddWordForTest( + final String word0, final String word1, final boolean isValid) { + mLocalDictionaryController.writeLock().lock(); + try { + mDictionaryWriter.addUnigramWord(word1, null /* the "shortcut" parameter is null */, + DynamicPredictionDictionaryBase.FREQUENCY_FOR_TYPED, false /* isNotAWord */); + mDictionaryWriter.addBigramWords(word0, word1, + DynamicPredictionDictionaryBase.FREQUENCY_FOR_TYPED, isValid, + 0 /* lastTouchedTime */); + } finally { + mLocalDictionaryController.writeLock().unlock(); + } + } } diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 342dcfc5e..ba7d1a2b0 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -265,10 +265,10 @@ public class ExpandableDictionary extends Dictionary { return (node == null) ? false : !node.mShortcutOnly; } - public boolean removeBigram(final String word1, final String word2) { + public boolean removeBigram(final String word0, final String word1) { // Refer to addOrSetBigram() about word1.toLowerCase() - final Node firstWord = searchWord(mRoots, word1.toLowerCase(), 0, null); - final Node secondWord = searchWord(mRoots, word2, 0, null); + final Node firstWord = searchWord(mRoots, word0.toLowerCase(), 0, null); + final Node secondWord = searchWord(mRoots, word1, 0, null); LinkedList bigrams = firstWord.mNGrams; NextWord bigramNode = null; if (bigrams == null || bigrams.size() == 0) { @@ -297,10 +297,10 @@ public class ExpandableDictionary extends Dictionary { return (node == null) ? -1 : node.mFrequency; } - public NextWord getBigramWord(final String word1, final String word2) { - // Refer to addOrSetBigram() about word1.toLowerCase() - final Node firstWord = searchWord(mRoots, word1.toLowerCase(), 0, null); - final Node secondWord = searchWord(mRoots, word2, 0, null); + public NextWord getBigramWord(final String word0, final String word1) { + // Refer to addOrSetBigram() about word0.toLowerCase() + final Node firstWord = searchWord(mRoots, word0.toLowerCase(), 0, null); + final Node secondWord = searchWord(mRoots, word1, 0, null); LinkedList bigrams = firstWord.mNGrams; if (bigrams == null || bigrams.size() == 0) { return null; @@ -473,37 +473,41 @@ public class ExpandableDictionary extends Dictionary { } } - public int setBigramAndGetFrequency(final String word1, final String word2, + public int setBigramAndGetFrequency(final String word0, final String word1, final int frequency) { - return setBigramAndGetFrequency(word1, word2, frequency, null /* unused */); + return setBigramAndGetFrequency(word0, word1, frequency, null /* unused */); } - public int setBigramAndGetFrequency(final String word1, final String word2, + public int setBigramAndGetFrequency(final String word0, final String word1, final ForgettingCurveParams fcp) { - return setBigramAndGetFrequency(word1, word2, 0 /* unused */, fcp); + return setBigramAndGetFrequency(word0, word1, 0 /* unused */, fcp); } /** * Adds bigrams to the in-memory trie structure that is being used to retrieve any word - * @param word1 the first word of this bigram - * @param word2 the second word of this bigram + * @param word0 the first word of this bigram + * @param word1 the second word of this bigram * @param frequency frequency for this bigram * @param fcp an instance of ForgettingCurveParams to use for decay policy * @return returns the final bigram frequency */ - private int setBigramAndGetFrequency(final String word1, final String word2, + private int setBigramAndGetFrequency(final String word0, final String word1, final int frequency, final ForgettingCurveParams fcp) { + if (TextUtils.isEmpty(word0)) { + Log.e(TAG, "Invalid bigram previous word: " + word0); + return frequency; + } // We don't want results to be different according to case of the looked up left hand side // word. We do want however to return the correct case for the right hand side. // So we want to squash the case of the left hand side, and preserve that of the right // hand side word. - final String word1Lower = word1.toLowerCase(); - if (TextUtils.isEmpty(word1Lower) || TextUtils.isEmpty(word2)) { - Log.e(TAG, "Invalid bigram pair: " + word1 + ", " + word1Lower + ", " + word2); + final String word0Lower = word0.toLowerCase(); + if (TextUtils.isEmpty(word0Lower) || TextUtils.isEmpty(word1)) { + Log.e(TAG, "Invalid bigram pair: " + word0 + ", " + word0Lower + ", " + word1); return frequency; } - final Node firstWord = searchWord(mRoots, word1Lower, 0, null); - final Node secondWord = searchWord(mRoots, word2, 0, null); + final Node firstWord = searchWord(mRoots, word0Lower, 0, null); + final Node secondWord = searchWord(mRoots, word1, 0, null); LinkedList bigrams = firstWord.mNGrams; if (bigrams == null || bigrams.size() == 0) { firstWord.mNGrams = CollectionUtils.newLinkedList(); diff --git a/java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java b/java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java index d44660623..e43e74d87 100644 --- a/java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java +++ b/java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java @@ -18,6 +18,7 @@ package com.android.inputmethod.latin.personalization; import android.content.Context; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.AbstractDictionaryWriter; import com.android.inputmethod.latin.ExpandableDictionary; @@ -156,4 +157,10 @@ public class DynamicPersonalizationDictionaryWriter extends AbstractDictionaryWr public boolean isValidWord(final String word) { return mExpandableDictionary.isValidWord(word); } + + @UsedForTesting + public boolean isInDictionaryForTests(final String word) { + // TODO: Use native method to determine whether the word is in dictionary or not + return mBigramList.containsKey(word); + } } diff --git a/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java index a08145b33..be4c7c42d 100644 --- a/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java +++ b/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java @@ -196,12 +196,6 @@ public abstract class DynamicPredictionDictionaryBase extends ExpandableBinaryDi return mLocale; } - @UsedForTesting - /* package for test */ void forceAddWordForTest( - final String word0, final String word1, final boolean isValid) { - addToPersonalizationPredictionDictionary(word0, word1, isValid); - } - public void registerUpdateSession(PersonalizationDictionaryUpdateSession session) { session.setPredictionDictionary(this); mSessions.add(session); diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java index 6c2c9e26e..4c1803bdf 100644 --- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java +++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java @@ -97,6 +97,10 @@ public final class UserHistoryDictionaryBigramList { return mBigramMap.isEmpty(); } + public boolean containsKey(String word) { + return mBigramMap.containsKey(word); + } + public Set keySet() { return mBigramMap.keySet(); } diff --git a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java index 1fd1b8a81..1a20ec52d 100644 --- a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java @@ -82,14 +82,29 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { } } + /** + * @param checksContents if true, checks whether written words are actually in the dictionary + * or not. + */ private void addAndWriteRandomWords(final String testFilenameSuffix, final int numberOfWords, - final Random random) { + final Random random, final boolean checksContents) { final List words = generateWords(numberOfWords, random); final UserHistoryPredictionDictionary dict = PersonalizationHelper.getUserHistoryPredictionDictionary(getContext(), testFilenameSuffix /* locale */, mPrefs); // Add random words to the user history dictionary. addToDict(dict, words); + if (checksContents) { + try { + Thread.sleep(TimeUnit.MILLISECONDS.convert(5L, TimeUnit.SECONDS)); + } catch (InterruptedException e) { + } + for (int i = 0; i < 10 && i < numberOfWords; ++i) { + final String word = words.get(i); + // This may fail as long as we use tryLock on inserting the bigram words + assertTrue(dict.isInDictionaryForTests(word)); + } + } // write to file. dict.close(); } @@ -103,7 +118,8 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { final Random random = new Random(123456); try { - addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random); + addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random, + true /* checksContents */); } finally { try { Log.d(TAG, "waiting for writing ..."); @@ -148,7 +164,8 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { final int index = i % numberOfLanguages; // Switch languages to testFilenameSuffixes[index]. addAndWriteRandomWords(testFilenameSuffixes[index], - numberOfWordsInsertedForEachLanguageSwitch, random); + numberOfWordsInsertedForEachLanguageSwitch, random, + false /* checksContents */); } final long end = System.currentTimeMillis();