Contacts dictionary rebuilds only when contact names have changed.

Bug: 6396600
Change-Id: Iad693ec4bab6351793d624e5c5b0a9f5c12a60e3
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index de9dbf9..b8f4ec7 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -182,6 +182,20 @@
     return result;
 }
 
+static jboolean latinime_BinaryDictionary_isValidBigram(JNIEnv *env, jobject object, jlong dict,
+        jintArray wordArray1, jintArray wordArray2) {
+    Dictionary *dictionary = (Dictionary*)dict;
+    if (!dictionary) return (jboolean) false;
+    jint *word1 = env->GetIntArrayElements(wordArray1, 0);
+    jint *word2 = env->GetIntArrayElements(wordArray2, 0);
+    jsize length1 = word1 ? env->GetArrayLength(wordArray1) : 0;
+    jsize length2 = word2 ? env->GetArrayLength(wordArray2) : 0;
+    jboolean result = dictionary->isValidBigram(word1, length1, word2, length2);
+    env->ReleaseIntArrayElements(wordArray2, word2, JNI_ABORT);
+    env->ReleaseIntArrayElements(wordArray1, word1, JNI_ABORT);
+    return result;
+}
+
 static jdouble latinime_BinaryDictionary_calcNormalizedScore(JNIEnv *env, jobject object,
         jcharArray before, jint beforeLength, jcharArray after, jint afterLength, jint score) {
     jchar *beforeChars = env->GetCharArrayElements(before, 0);
@@ -239,6 +253,7 @@
     {"getSuggestionsNative", "(JJ[I[I[II[IZ[C[I)I",
             (void*)latinime_BinaryDictionary_getSuggestions},
     {"isValidWordNative", "(J[II)Z", (void*)latinime_BinaryDictionary_isValidWord},
+    {"isValidBigramNative", "(J[I[I)Z", (void*)latinime_BinaryDictionary_isValidBigram},
     {"getBigramsNative", "(J[II[II[C[III)I", (void*)latinime_BinaryDictionary_getBigrams},
     {"calcNormalizedScoreNative", "([CI[CII)D",
             (void*)latinime_BinaryDictionary_calcNormalizedScore},
diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp
index 0703108..7ed4dc4 100644
--- a/native/jni/src/bigram_dictionary.cpp
+++ b/native/jni/src/bigram_dictionary.cpp
@@ -128,7 +128,7 @@
                 ++bigramCount;
             }
         }
-    } while (0 != (UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags));
+    } while (UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags);
     return bigramCount;
 }
 
@@ -189,5 +189,25 @@
     return false;
 }
 
+bool BigramDictionary::isValidBigram(const int32_t *word1, int length1, const int32_t *word2,
+        int length2) {
+    const uint8_t* const root = DICT;
+    int pos = getBigramListPositionForWord(word1, length1);
+    // getBigramListPositionForWord returns 0 if this word isn't in the dictionary or has no bigrams
+    if (0 == pos) return false;
+    int nextWordPos = BinaryFormat::getTerminalPosition(root, word2, length2);
+    if (NOT_VALID_WORD == nextWordPos) return false;
+    int bigramFlags;
+    do {
+        bigramFlags = BinaryFormat::getFlagsAndForwardPointer(root, &pos);
+        const int bigramPos = BinaryFormat::getAttributeAddressAndForwardPointer(root, bigramFlags,
+                &pos);
+        if (bigramPos == nextWordPos) {
+            return true;
+        }
+    } while (UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags);
+    return false;
+}
+
 // TODO: Move functions related to bigram to here
 } // namespace latinime
diff --git a/native/jni/src/bigram_dictionary.h b/native/jni/src/bigram_dictionary.h
index 7328d58..b8763a5 100644
--- a/native/jni/src/bigram_dictionary.h
+++ b/native/jni/src/bigram_dictionary.h
@@ -33,6 +33,7 @@
     int getBigramListPositionForWord(const int32_t *prevWord, const int prevWordLength);
     void fillBigramAddressToFrequencyMapAndFilter(const int32_t *prevWord, const int prevWordLength,
             std::map<int, int> *map, uint8_t *filter);
+    bool isValidBigram(const int32_t *word1, int length1, const int32_t *word2, int length2);
     ~BigramDictionary();
  private:
     bool addWordBigram(unsigned short *word, int length, int frequency);
diff --git a/native/jni/src/dictionary.cpp b/native/jni/src/dictionary.cpp
index 9dc2072..8ea7c49 100644
--- a/native/jni/src/dictionary.cpp
+++ b/native/jni/src/dictionary.cpp
@@ -58,4 +58,9 @@
     return mUnigramDictionary->isValidWord(word, length);
 }
 
+bool Dictionary::isValidBigram(const int32_t *word1, int length1, const int32_t *word2,
+        int length2) {
+    return mBigramDictionary->isValidBigram(word1, length1, word2, length2);
+}
+
 } // namespace latinime
diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h
index bce86d1..87891ee 100644
--- a/native/jni/src/dictionary.h
+++ b/native/jni/src/dictionary.h
@@ -53,6 +53,7 @@
     }
 
     bool isValidWord(const int32_t *word, int length);
+    bool isValidBigram(const int32_t *word1, int length1, const int32_t *word2, int length2);
     void *getDict() { return (void *)mDict; }
     int getDictSize() { return mDictSize; }
     int getMmapFd() { return mMmapFd; }