From a0befc6490ad295455782a7b6dbe8785788299e4 Mon Sep 17 00:00:00 2001 From: Keisuke Kuroyanagi Date: Wed, 4 Dec 2013 11:47:28 +0900 Subject: [PATCH] Start passing timestamp for dynamic dictionaries. Bug: 11073222 Change-Id: I89e1277f734d5959e33d61e7e9e7048084b9007a --- .../inputmethod/latin/BinaryDictionary.java | 47 +++++++++++++++---- .../latin/ExpandableBinaryDictionary.java | 12 +++-- .../android/inputmethod/latin/LatinIME.java | 4 +- ...ecayingExpandableBinaryDictionaryBase.java | 9 ++-- ...ersonalizationDictionaryUpdateSession.java | 4 +- ...oid_inputmethod_latin_BinaryDictionary.cpp | 18 +++---- .../latin/BinaryDictionaryTests.java | 5 +- .../UserHistoryDictionaryTests.java | 3 +- 8 files changed, 68 insertions(+), 34 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 174bbfb8e..0e03b5280 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -57,7 +57,7 @@ public final class BinaryDictionary extends Dictionary { @UsedForTesting public static final String MAX_BIGRAM_COUNT_QUERY = "MAX_BIGRAM_COUNT"; - private static final int NOT_A_VALID_TIME_STAMP = -1; + public static final int NOT_A_VALID_TIME_STAMP = -1; private long mNativeDict; private final Locale mLocale; @@ -138,9 +138,9 @@ public final class BinaryDictionary extends Dictionary { private static native int editDistanceNative(int[] before, int[] after); private static native void addUnigramWordNative(long dict, int[] word, int probability, int[] shortcutTarget, int shortcutProbability, boolean isNotAWord, - boolean isBlacklisted, int timeStamp); + boolean isBlacklisted, int timestamp); private static native void addBigramWordsNative(long dict, int[] word0, int[] word1, - int probability, int timeStamp); + int probability, int timestamp); private static native void removeBigramWordsNative(long dict, int[] word0, int[] word1); private static native int addMultipleDictionaryEntriesNative(long dict, LanguageModelParam[] languageModelParams, int startIndex); @@ -291,12 +291,26 @@ public final class BinaryDictionary extends Dictionary { return; } final int[] codePoints = StringUtils.toCodePointArray(word); - final int[] shortcutTarget = new int[0]; - addUnigramWordNative(mNativeDict, codePoints, probability, shortcutTarget, + final int[] shortcutTargetCodePoints = new int[0]; + addUnigramWordNative(mNativeDict, codePoints, probability, shortcutTargetCodePoints, NOT_A_PROBABILITY, false /* isNotAWord */, false /* isBlacklisted */, NOT_A_VALID_TIME_STAMP); } + // Add a unigram entry to binary dictionary with unigram attributes in native code. + public void addUnigramWord(final String word, final int probability, + final String shortcutTarget, final int shortcutProbability, final boolean isNotAWord, + final boolean isBlacklisted, final int timestamp) { + if (TextUtils.isEmpty(word)) { + return; + } + final int[] codePoints = StringUtils.toCodePointArray(word); + final int[] shortcutTargetCodePoints = (shortcutTarget != null) ? + StringUtils.toCodePointArray(shortcutTarget) : null; + addUnigramWordNative(mNativeDict, codePoints, probability, shortcutTargetCodePoints, + shortcutProbability, isNotAWord, isBlacklisted, timestamp); + } + // Add a bigram entry to binary dictionary in native code. public void addBigramWords(final String word0, final String word1, final int probability) { if (TextUtils.isEmpty(word0) || TextUtils.isEmpty(word1)) { @@ -308,6 +322,17 @@ public final class BinaryDictionary extends Dictionary { NOT_A_VALID_TIME_STAMP); } + // Add a bigram entry to binary dictionary with timestamp in native code. + public void addBigramWords(final String word0, final String word1, final int probability, + final int timestamp) { + if (TextUtils.isEmpty(word0) || TextUtils.isEmpty(word1)) { + return; + } + final int[] codePoints0 = StringUtils.toCodePointArray(word0); + final int[] codePoints1 = StringUtils.toCodePointArray(word1); + addBigramWordsNative(mNativeDict, codePoints0, codePoints1, probability, timestamp); + } + // Remove a bigram entry form binary dictionary in native code. public void removeBigramWords(final String word0, final String word1) { if (TextUtils.isEmpty(word0) || TextUtils.isEmpty(word1)) { @@ -327,10 +352,11 @@ public final class BinaryDictionary extends Dictionary { public final int mShortcutProbability; public final boolean mIsNotAWord; public final boolean mIsBlacklisted; - public final int mTimeStamp; + public final int mTimestamp; // Constructor for unigram. - public LanguageModelParam(final String word, final int unigramProbability) { + public LanguageModelParam(final String word, final int unigramProbability, + final int timestamp) { mWord0 = null; mWord1 = StringUtils.toCodePointArray(word); mShortcutTarget = null; @@ -339,12 +365,13 @@ public final class BinaryDictionary extends Dictionary { mShortcutProbability = NOT_A_PROBABILITY; mIsNotAWord = false; mIsBlacklisted = false; - mTimeStamp = NOT_A_VALID_TIME_STAMP; + mTimestamp = timestamp; } // Constructor for unigram and bigram. public LanguageModelParam(final String word0, final String word1, - final int unigramProbability, final int bigramProbability) { + final int unigramProbability, final int bigramProbability, + final int timestamp) { mWord0 = StringUtils.toCodePointArray(word0); mWord1 = StringUtils.toCodePointArray(word1); mShortcutTarget = null; @@ -353,7 +380,7 @@ public final class BinaryDictionary extends Dictionary { mShortcutProbability = NOT_A_PROBABILITY; mIsNotAWord = false; mIsBlacklisted = false; - mTimeStamp = NOT_A_VALID_TIME_STAMP; + mTimestamp = timestamp; } } diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 154e9b58b..f86517d12 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -334,8 +334,9 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { /** * Dynamically adds a word unigram to the dictionary. May overwrite an existing entry. */ - protected void addWordDynamically(final String word, final String shortcutTarget, - final int frequency, final int shortcutFreq, final boolean isNotAWord) { + protected void addWordDynamically(final String word, final int frequency, + final String shortcutTarget, final int shortcutFreq, final boolean isNotAWord, + final boolean isBlacklisted, final int timestamp) { if (!mIsUpdatable) { Log.w(TAG, "addWordDynamically is called for non-updatable dictionary: " + mFilename); return; @@ -344,7 +345,8 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { @Override public void run() { runGCIfRequiredInternalLocked(true /* mindsBlockByGC */); - mBinaryDictionary.addUnigramWord(word, frequency); + mBinaryDictionary.addUnigramWord(word, frequency, shortcutTarget, shortcutFreq, + isNotAWord, isBlacklisted, timestamp); } }); } @@ -353,7 +355,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { * Dynamically adds a word bigram in the dictionary. May overwrite an existing entry. */ protected void addBigramDynamically(final String word0, final String word1, - final int frequency) { + final int frequency, final int timestamp) { if (!mIsUpdatable) { Log.w(TAG, "addBigramDynamically is called for non-updatable dictionary: " + mFilename); @@ -363,7 +365,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { @Override public void run() { runGCIfRequiredInternalLocked(true /* mindsBlockByGC */); - mBinaryDictionary.addBigramWords(word0, word1, frequency); + mBinaryDictionary.addBigramWords(word0, word1, frequency, timestamp); } }); } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 8ce1e38f4..b3e711690 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -109,6 +109,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Locale; import java.util.TreeSet; +import java.util.concurrent.TimeUnit; /** * Input method implementation for Qwerty'ish keyboard. @@ -2871,7 +2872,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final int maxFreq = AutoCorrectionUtils.getMaxFrequency( suggest.getUnigramDictionaries(), suggestion); if (maxFreq == 0) return null; - userHistoryDictionary.addToDictionary(prevWord, secondWord, maxFreq > 0); + userHistoryDictionary.addToDictionary(prevWord, secondWord, maxFreq > 0, + (int)TimeUnit.MILLISECONDS.toSeconds((System.currentTimeMillis()))); return prevWord; } diff --git a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java index 8f26f8442..f4b7d6e5c 100644 --- a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java +++ b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java @@ -141,21 +141,22 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB * context, as in beginning of a sentence for example. * The second word may not be null (a NullPointerException would be thrown). */ - public void addToDictionary(final String word0, final String word1, final boolean isValid) { + public void addToDictionary(final String word0, final String word1, final boolean isValid, + final int timestamp) { if (word1.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH || (word0 != null && word0.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH)) { return; } final int frequency = isValid ? FREQUENCY_FOR_WORDS_IN_DICTS : FREQUENCY_FOR_WORDS_NOT_IN_DICTS; - addWordDynamically(word1, null /* shortcutTarget */, frequency, 0 /* shortcutFreq */, - false /* isNotAWord */); + addWordDynamically(word1, frequency, null /* shortcutTarget */, 0 /* shortcutFreq */, + false /* isNotAWord */, false /* isBlacklisted */, timestamp); // Do not insert a word as a bigram of itself if (word1.equals(word0)) { return; } if (null != word0) { - addBigramDynamically(word0, word1, frequency); + addBigramDynamically(word0, word1, frequency, timestamp); } } diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java index 2ab366b8a..c273023ef 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java @@ -90,12 +90,12 @@ public abstract class PersonalizationDictionaryUpdateSession { // TODO: Support multi locale to add bigram public void addBigramToPersonalizationDictionary(String word0, String word1, boolean isValid, - int frequency) { + int frequency, int timestamp) { final DecayingExpandableBinaryDictionaryBase dictionary = getPredictionDictionary(); if (dictionary == null) { return; } - dictionary.addToDictionary(word0, word1, isValid); + dictionary.addToDictionary(word0, word1, isValid, timestamp); } // TODO: Support multi locale. diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index c6a5900e7..57c170f59 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -284,7 +284,7 @@ static jint latinime_BinaryDictionary_editDistance(JNIEnv *env, jclass clazz, ji static void latinime_BinaryDictionary_addUnigramWord(JNIEnv *env, jclass clazz, jlong dict, jintArray word, jint probability, jintArray shortcutTarget, jint shortuctProbability, - jboolean isNotAWord, jboolean isBlacklisted, jint timeStamp) { + jboolean isNotAWord, jboolean isBlacklisted, jint timestamp) { Dictionary *dictionary = reinterpret_cast(dict); if (!dictionary) { return; @@ -297,11 +297,11 @@ static void latinime_BinaryDictionary_addUnigramWord(JNIEnv *env, jclass clazz, if (shortcutTarget) { env->GetIntArrayRegion(shortcutTarget, 0, shortcutLength, shortcutTargetCodePoints); } - dictionary->addUnigramWord(codePoints, wordLength, probability, timeStamp); + dictionary->addUnigramWord(codePoints, wordLength, probability, timestamp); } static void latinime_BinaryDictionary_addBigramWords(JNIEnv *env, jclass clazz, jlong dict, - jintArray word0, jintArray word1, jint probability, jint timeStamp) { + jintArray word0, jintArray word1, jint probability, jint timestamp) { Dictionary *dictionary = reinterpret_cast(dict); if (!dictionary) { return; @@ -313,7 +313,7 @@ static void latinime_BinaryDictionary_addBigramWords(JNIEnv *env, jclass clazz, int word1CodePoints[word1Length]; env->GetIntArrayRegion(word1, 0, word1Length, word1CodePoints); dictionary->addBigramWords(word0CodePoints, word0Length, word1CodePoints, - word1Length, probability, timeStamp); + word1Length, probability, timestamp); } static void latinime_BinaryDictionary_removeBigramWords(JNIEnv *env, jclass clazz, jlong dict, @@ -355,8 +355,8 @@ static int latinime_BinaryDictionary_addMultipleDictionaryEntries(JNIEnv *env, j env->GetFieldID(languageModelParamClass, "mUnigramProbability", "I"); jfieldID bigramProbabilityFieldId = env->GetFieldID(languageModelParamClass, "mBigramProbability", "I"); - jfieldID timeStampFieldId = - env->GetFieldID(languageModelParamClass, "mTimeStamp", "I"); + jfieldID timestampFieldId = + env->GetFieldID(languageModelParamClass, "mTimestamp", "I"); env->DeleteLocalRef(languageModelParamClass); for (int i = startIndex; i < languageModelParamCount; ++i) { @@ -377,12 +377,12 @@ static int latinime_BinaryDictionary_addMultipleDictionaryEntries(JNIEnv *env, j int word1CodePoints[word1Length]; env->GetIntArrayRegion(word1, 0, word1Length, word1CodePoints); jint unigramProbability = env->GetIntField(languageModelParam, unigramProbabilityFieldId); - jint timeStamp = env->GetIntField(languageModelParam, timeStampFieldId); - dictionary->addUnigramWord(word1CodePoints, word1Length, unigramProbability, timeStamp); + jint timestamp = env->GetIntField(languageModelParam, timestampFieldId); + dictionary->addUnigramWord(word1CodePoints, word1Length, unigramProbability, timestamp); if (word0) { jint bigramProbability = env->GetIntField(languageModelParam, bigramProbabilityFieldId); dictionary->addBigramWords(word0CodePoints, word0Length, word1CodePoints, word1Length, - bigramProbability, timeStamp); + bigramProbability, timestamp); } if (dictionary->needsToRunGC(true /* mindsBlockByGC */)) { return i + 1; diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java index 29f824168..8565db919 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java @@ -780,10 +780,11 @@ public class BinaryDictionaryTests extends AndroidTestCase { final int bigramProbability = random.nextInt(0xF); unigramProbabilities.put(word, probability); if (prevWord == null) { - languageModelParams[i] = new LanguageModelParam(word, probability); + languageModelParams[i] = new LanguageModelParam(word, probability, + BinaryDictionary.NOT_A_VALID_TIME_STAMP); } else { languageModelParams[i] = new LanguageModelParam(prevWord, word, probability, - bigramProbability); + bigramProbability, BinaryDictionary.NOT_A_VALID_TIME_STAMP); bigramProbabilities.put(new Pair(prevWord, word), bigramProbability); } diff --git a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java index beac57b2d..717b04f75 100644 --- a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java @@ -71,7 +71,8 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { private void addToDict(final UserHistoryDictionary dict, final List words) { String prevWord = null; for (String word : words) { - dict.addToDictionary(prevWord, word, true); + // TODO: Use timestamp properly. + dict.addToDictionary(prevWord, word, true, 0 /* timestamp */); prevWord = word; } }