Merge "Update the prototype of onAddSuggestedWord - calling side."
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index 2a02603..620c553 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -161,7 +161,7 @@
      * bigrams depending on locale.
      */
     private void addName(String name) {
-        int len = name.codePointCount(0, name.length());
+        int len = StringUtils.codePointCount(name);
         String prevWord = null;
         // TODO: Better tokenization for non-Latin writing systems
         for (int i = 0; i < len; i++) {
@@ -171,7 +171,7 @@
                 i = end - 1;
                 // Don't add single letter words, possibly confuses
                 // capitalization of i.
-                final int wordLen = word.codePointCount(0, word.length());
+                final int wordLen = StringUtils.codePointCount(word);
                 if (wordLen < MAX_WORD_LENGTH && wordLen > 1) {
                     super.addWord(word, null /* shortcut */, FREQUENCY_FOR_CONTACTS);
                     if (!TextUtils.isEmpty(prevWord)) {
@@ -260,14 +260,14 @@
      * Checks if the words in a name are in the current binary dictionary.
      */
     private boolean isNameInDictionary(String name) {
-        int len = name.codePointCount(0, name.length());
+        int len = StringUtils.codePointCount(name);
         String prevWord = null;
         for (int i = 0; i < len; i++) {
             if (Character.isLetter(name.codePointAt(i))) {
                 int end = getWordEndPosition(name, len, i);
                 String word = name.substring(i, end);
                 i = end - 1;
-                final int wordLen = word.codePointCount(0, word.length());
+                final int wordLen = StringUtils.codePointCount(word);
                 if (wordLen < MAX_WORD_LENGTH && wordLen > 1) {
                     if (!TextUtils.isEmpty(prevWord) && mUseFirstLastBigrams) {
                         if (!super.isValidBigramLocked(prevWord, word)) {
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 45ac9ff..9883cd6 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -142,7 +142,7 @@
             mWord = word;
             mScore = score;
             mKind = kind;
-            mCodePointCount = mWordStr.codePointCount(0, mWordStr.length());
+            mCodePointCount = StringUtils.codePointCount(mWordStr);
         }
 
 
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index ca9caa1..bcd295d 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -92,7 +92,7 @@
         refreshSize();
     }
 
-    public final void refreshSize() {
+    private final void refreshSize() {
         mCodePointSize = mTypedWord.codePointCount(0, mTypedWord.length());
     }
 
diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index 5d705b1..a6bb487 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -26,6 +26,8 @@
 LATIN_IME_SRC_DIR := src
 
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR)
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR)/gesture
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR)/gesture/impl
 
 LOCAL_CFLAGS += -Werror -Wall
 
diff --git a/native/jni/src/dictionary.cpp b/native/jni/src/dictionary.cpp
index e0b7f87..10ea9fe 100644
--- a/native/jni/src/dictionary.cpp
+++ b/native/jni/src/dictionary.cpp
@@ -44,7 +44,8 @@
             fullWordMultiplier, maxWordLength, maxWords, options);
     mBigramDictionary = new BigramDictionary(mDict + headerSize, maxWordLength);
     mGestureDecoder = new GestureDecoder(maxWordLength, maxWords);
-    mGestureDecoder->setDict(mUnigramDictionary, mBigramDictionary);
+    mGestureDecoder->setDict(mUnigramDictionary, mBigramDictionary,
+            mDict + headerSize /* dict root */, 0 /* root pos */);
 }
 
 Dictionary::~Dictionary() {
diff --git a/native/jni/src/gesture/gesture_decoder_impl.h b/native/jni/src/gesture/impl/gesture_decoder_impl.h
similarity index 100%
rename from native/jni/src/gesture/gesture_decoder_impl.h
rename to native/jni/src/gesture/impl/gesture_decoder_impl.h
diff --git a/native/jni/src/gesture/incremental_decoder_impl.h b/native/jni/src/gesture/impl/incremental_decoder_impl.h
similarity index 94%
rename from native/jni/src/gesture/incremental_decoder_impl.h
rename to native/jni/src/gesture/impl/incremental_decoder_impl.h
index 5731ad8..84121e8 100644
--- a/native/jni/src/gesture/incremental_decoder_impl.h
+++ b/native/jni/src/gesture/impl/incremental_decoder_impl.h
@@ -28,7 +28,8 @@
 
  public:
      IncrementalDecoderImpl(int maxWordLength, int maxWords) { };
-     void setDict(const UnigramDictionary *dict, const BigramDictionary *bigram) { };
+     void setDict(const UnigramDictionary *dict, const BigramDictionary *bigram,
+             const uint8_t *dictRoot, int rootPos) { };
      void setPrevWord(const int32_t *prevWord, int prevWordLength) { };
      void reset() { };
 
diff --git a/native/jni/src/gesture/incremental_decoder_interface.h b/native/jni/src/gesture/incremental_decoder_interface.h
index d34b0da..c5404a4 100644
--- a/native/jni/src/gesture/incremental_decoder_interface.h
+++ b/native/jni/src/gesture/incremental_decoder_interface.h
@@ -31,7 +31,8 @@
             int *pointerIds, int *codes, int inputSize, int commitPoint, bool isMainDict,
             unsigned short *outWords, int *frequencies, int *outputIndices) = 0;
     virtual void reset() = 0;
-    virtual void setDict(const UnigramDictionary *dict, const BigramDictionary *bigram) = 0;
+    virtual void setDict(const UnigramDictionary *dict, const BigramDictionary *bigram,
+            const uint8_t *dictRoot, int rootPos) = 0;
     virtual void setPrevWord(const int32_t *prevWord, int prevWordLength) = 0;
     virtual ~IncrementalDecoderInterface() { };
 };
diff --git a/native/jni/src/proximity_info.cpp b/native/jni/src/proximity_info.cpp
index 2ba244a..a4a6411 100644
--- a/native/jni/src/proximity_info.cpp
+++ b/native/jni/src/proximity_info.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <assert.h>
+#include <math.h>
 #include <stdio.h>
 #include <string>
 
@@ -210,4 +211,25 @@
     }
     return mCodeToKeyIndex[baseLowerC];
 }
+
+// TODO: [Staging] Optimize
+void ProximityInfo::getCenters(int *centerXs, int *centerYs, int *codeToKeyIndex,
+        int *keyToCodeIndex, int *keyCount, int *keyWidth) const {
+    *keyCount = KEY_COUNT;
+    *keyWidth = sqrt((float)MOST_COMMON_KEY_WIDTH_SQUARE);
+
+    for (int i = 0; i < KEY_COUNT; ++i) {
+        const int code = mKeyCharCodes[i];
+        const int lowerCode = toBaseLowerCase(code);
+        centerXs[i] = mKeyXCoordinates[i] + mKeyWidths[i] / 2;
+        centerYs[i] = mKeyYCoordinates[i] + mKeyHeights[i] / 2;
+        codeToKeyIndex[code] = i;
+        if (code != lowerCode && lowerCode >= 0 && lowerCode <= MAX_CHAR_CODE) {
+            codeToKeyIndex[lowerCode] = i;
+            keyToCodeIndex[i] = lowerCode;
+        } else {
+            keyToCodeIndex[i] = code;
+        }
+    }
+}
 } // namespace latinime
diff --git a/native/jni/src/proximity_info.h b/native/jni/src/proximity_info.h
index fec6555..d58935c 100644
--- a/native/jni/src/proximity_info.h
+++ b/native/jni/src/proximity_info.h
@@ -98,6 +98,10 @@
         return GRID_HEIGHT;
     }
 
+    // Returns the keyboard key-center information.
+    void getCenters(int *centersX, int *centersY, int *codeToKeyIndex, int *keyToCodeIndex,
+            int *keyCount, int *keyWidth) const;
+
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfo);
     // The max number of the keys in one keyboard layout