diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 1abbf3084d1bb39ccee0e336b8e6dcdf5fae4f6f..51ae636314abb1196da6f766b65466b591c72b10 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -57,6 +57,8 @@ 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;
+
     private long mNativeDict;
     private final Locale mLocale;
     private final long mDictSize;
@@ -133,9 +135,11 @@ public final class BinaryDictionary extends Dictionary {
             int[] outputAutoCommitFirstWordConfidence);
     private static native float calcNormalizedScoreNative(int[] before, int[] after, int score);
     private static native int editDistanceNative(int[] before, int[] after);
-    private static native void addUnigramWordNative(long dict, int[] word, int probability);
+    private static native void addUnigramWordNative(long dict, int[] word, int probability,
+            int[] shortcutTarget, int shortcutProbability, boolean isNotAWord,
+            boolean isBlacklisted, int timeStamp);
     private static native void addBigramWordsNative(long dict, int[] word0, int[] word1,
-            int probability);
+            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);
@@ -282,7 +286,10 @@ public final class BinaryDictionary extends Dictionary {
             return;
         }
         final int[] codePoints = StringUtils.toCodePointArray(word);
-        addUnigramWordNative(mNativeDict, codePoints, probability);
+        final int[] shortcutTarget = new int[0];
+        addUnigramWordNative(mNativeDict, codePoints, probability, shortcutTarget,
+                NOT_A_PROBABILITY, false /* isNotAWord */, false /* isBlacklisted */,
+                NOT_A_VALID_TIME_STAMP);
     }
 
     // Add a bigram entry to binary dictionary in native code.
@@ -292,7 +299,8 @@ public final class BinaryDictionary extends Dictionary {
         }
         final int[] codePoints0 = StringUtils.toCodePointArray(word0);
         final int[] codePoints1 = StringUtils.toCodePointArray(word1);
-        addBigramWordsNative(mNativeDict, codePoints0, codePoints1, probability);
+        addBigramWordsNative(mNativeDict, codePoints0, codePoints1, probability,
+                NOT_A_VALID_TIME_STAMP);
     }
 
     // Remove a bigram entry form binary dictionary in native code.
@@ -308,15 +316,25 @@ public final class BinaryDictionary extends Dictionary {
     public static class LanguageModelParam {
         public final int[] mWord0;
         public final int[] mWord1;
+        public final int[] mShortcutTarget;
         public final int mUnigramProbability;
         public final int mBigramProbability;
+        public final int mShortcutProbability;
+        public final boolean mIsNotAWord;
+        public final boolean mIsBlacklisted;
+        public final int mTimeStamp;
 
         // Constructor for unigram.
         public LanguageModelParam(final String word, final int unigramProbability) {
             mWord0 = null;
             mWord1 = StringUtils.toCodePointArray(word);
+            mShortcutTarget = null;
             mUnigramProbability = unigramProbability;
             mBigramProbability = NOT_A_PROBABILITY;
+            mShortcutProbability = NOT_A_PROBABILITY;
+            mIsNotAWord = false;
+            mIsBlacklisted = false;
+            mTimeStamp = NOT_A_VALID_TIME_STAMP;
         }
 
         // Constructor for unigram and bigram.
@@ -324,8 +342,13 @@ public final class BinaryDictionary extends Dictionary {
                 final int unigramProbability, final int bigramProbability) {
             mWord0 = StringUtils.toCodePointArray(word0);
             mWord1 = StringUtils.toCodePointArray(word1);
+            mShortcutTarget = null;
             mUnigramProbability = unigramProbability;
             mBigramProbability = bigramProbability;
+            mShortcutProbability = NOT_A_PROBABILITY;
+            mIsNotAWord = false;
+            mIsBlacklisted = false;
+            mTimeStamp = NOT_A_VALID_TIME_STAMP;
         }
     }
 
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index b1aa034eac14a0832568c82ee2eed1a227e80b17..5fc20eaa0488f2d072a6a0b8f6b8fb973c53e639 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -277,7 +277,8 @@ 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 word, jint probability, jintArray shortcutTarget, jint shortuctProbability,
+        jboolean isNotAWord, jboolean isBlacklisted, jint timeStamp) {
     Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
     if (!dictionary) {
         return;
@@ -285,11 +286,16 @@ static void latinime_BinaryDictionary_addUnigramWord(JNIEnv *env, jclass clazz,
     jsize wordLength = env->GetArrayLength(word);
     int codePoints[wordLength];
     env->GetIntArrayRegion(word, 0, wordLength, codePoints);
+    jsize shortcutLength = shortcutTarget ? env->GetArrayLength(shortcutTarget) : 0;
+    int shortcutTargetCodePoints[wordLength];
+    if (shortcutTarget) {
+        env->GetIntArrayRegion(shortcutTarget, 0, shortcutLength, shortcutTargetCodePoints);
+    }
     dictionary->addUnigramWord(codePoints, wordLength, probability);
 }
 
 static void latinime_BinaryDictionary_addBigramWords(JNIEnv *env, jclass clazz, jlong dict,
-        jintArray word0, jintArray word1, jint probability) {
+        jintArray word0, jintArray word1, jint probability, jint timeStamp) {
     Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
     if (!dictionary) {
         return;
@@ -335,6 +341,8 @@ static int latinime_BinaryDictionary_addMultipleDictionaryEntries(JNIEnv *env, j
     jobject languageModelParam = env->GetObjectArrayElement(languageModelParams, 0);
     jclass languageModelParamClass = env->GetObjectClass(languageModelParam);
     env->DeleteLocalRef(languageModelParam);
+
+    // TODO: Support shortcut, timestamp and flags.
     jfieldID word0FieldId = env->GetFieldID(languageModelParamClass, "mWord0", "[I");
     jfieldID word1FieldId = env->GetFieldID(languageModelParamClass, "mWord1", "[I");
     jfieldID unigramProbabilityFieldId =
@@ -345,6 +353,9 @@ static int latinime_BinaryDictionary_addMultipleDictionaryEntries(JNIEnv *env, j
 
     for (int i = startIndex; i < languageModelParamCount; ++i) {
         jobject languageModelParam = env->GetObjectArrayElement(languageModelParams, i);
+        // languageModelParam is a set of params for word1; thus, word1 cannot be null. On the
+        // other hand, word0 can be null and then it means the set of params doesn't contain bigram
+        // information.
         jintArray word0 = static_cast<jintArray>(
                 env->GetObjectField(languageModelParam, word0FieldId));
         jsize word0Length = word0 ? env->GetArrayLength(word0) : 0;
@@ -459,12 +470,12 @@ static const JNINativeMethod sMethods[] = {
     },
     {
         const_cast<char *>("addUnigramWordNative"),
-        const_cast<char *>("(J[II)V"),
+        const_cast<char *>("(J[II[IIZZI)V"),
         reinterpret_cast<void *>(latinime_BinaryDictionary_addUnigramWord)
     },
     {
         const_cast<char *>("addBigramWordsNative"),
-        const_cast<char *>("(J[I[II)V"),
+        const_cast<char *>("(J[I[III)V"),
         reinterpret_cast<void *>(latinime_BinaryDictionary_addBigramWords)
     },
     {