Merge "Adaptive suggestions strip"
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 874d77f..a83aca0 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1181,7 +1181,7 @@
 
         mVoiceProxy.handleBackspace();
 
-        boolean deleteChar = false;
+        final boolean deleteChar = !mHasUncommittedTypedChars;
         if (mHasUncommittedTypedChars) {
             final int length = mComposing.length();
             if (length > 0) {
@@ -1202,8 +1202,6 @@
             } else {
                 ic.deleteSurroundingText(1, 0);
             }
-        } else {
-            deleteChar = true;
         }
         mHandler.postUpdateShiftKeyState();
 
@@ -1231,7 +1229,7 @@
                 // different behavior only in the case of picking the first
                 // suggestion (typed word).  It's intentional to have made this
                 // inconsistent with backspacing after selecting other suggestions.
-                revertLastWord(deleteChar);
+                revertLastWord(true /* deleteChar */);
             } else {
                 sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
                 if (mDeleteCount > DELETE_ACCELERATE_AT) {
@@ -1799,7 +1797,7 @@
         return TextUtils.equals(text, beforeText);
     }
 
-    public void revertLastWord(boolean deleteChar) {
+    private void revertLastWord(boolean deleteChar) {
         final int length = mComposing.length();
         if (!mHasUncommittedTypedChars && length > 0) {
             final InputConnection ic = getCurrentInputConnection();
@@ -1837,7 +1835,7 @@
         }
     }
 
-    public boolean revertDoubleSpace() {
+    private boolean revertDoubleSpace() {
         mHandler.cancelDoubleSpacesTimer();
         final InputConnection ic = getCurrentInputConnection();
         // Here we test whether we indeed have a period and a space before us. This should not
diff --git a/java/src/com/android/inputmethod/latin/TextEntryState.java b/java/src/com/android/inputmethod/latin/TextEntryState.java
index de13f3a..b6e2611 100644
--- a/java/src/com/android/inputmethod/latin/TextEntryState.java
+++ b/java/src/com/android/inputmethod/latin/TextEntryState.java
@@ -144,7 +144,7 @@
             break;
         case UNDO_COMMIT:
             if (isSpace || isSeparator) {
-                setState(ACCEPTED_DEFAULT);
+                setState(START);
             } else {
                 setState(IN_WORD);
             }
diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp
index e3296f1..290e9f9 100644
--- a/native/src/unigram_dictionary.cpp
+++ b/native/src/unigram_dictionary.cpp
@@ -153,6 +153,13 @@
 
     if (DEBUG_DICT) {
         LOGI("Returning %d words", suggestedWordsCount);
+        /// Print the returned words
+        for (int j = 0; j < suggestedWordsCount; ++j) {
+            short unsigned int* w = mOutputChars + j * MAX_WORD_LENGTH;
+            char s[MAX_WORD_LENGTH];
+            for (int i = 0; i <= MAX_WORD_LENGTH; i++) s[i] = w[i];
+            LOGI("%s %i", s, mFrequencies[j]);
+        }
         LOGI("Next letters: ");
         for (int k = 0; k < NEXT_LETTERS_SIZE; k++) {
             if (mNextLettersFrequency[k] > 0) {
@@ -322,16 +329,6 @@
     return false;
 }
 
-inline void UnigramDictionary::addWordAlternatesSpellings(const uint8_t* const root, int pos,
-        int depth, int finalFreq) {
-    // TODO: actually add alternates when the format supports it.
-}
-
-static inline bool hasAlternateSpellings(uint8_t flags) {
-    // TODO: when the format supports it, return the actual value.
-    return false;
-}
-
 static inline unsigned short toBaseLowerCase(unsigned short c) {
     if (c < sizeof(BASE_CHARS) / sizeof(BASE_CHARS[0])) {
         c = BASE_CHARS[c];
@@ -372,7 +369,7 @@
         assert(missingPos < mInputLength);
     }
     int rootPosition = ROOT_POS;
-    // Get the number of child of root, then increment the position
+    // Get the number of children of root, then increment the position
     int childCount = Dictionary::getCount(DICT_ROOT, &rootPosition);
     int depth = 0;
 
@@ -657,22 +654,19 @@
 }
 
 inline void UnigramDictionary::onTerminal(unsigned short int* word, const int depth,
-        const uint8_t* const root, const uint8_t flags, int pos,
+        const uint8_t* const root, const uint8_t flags, const int pos,
         const int inputIndex, const int matchWeight, const int skipPos,
         const int excessivePos, const int transposedPos, const int freq, const bool sameLength,
         int* nextLetters, const int nextLettersSize) {
 
     const bool isSameAsTyped = sameLength ? sameAsTyped(word, depth + 1) : false;
-    const bool hasAlternates = hasAlternateSpellings(flags);
-    if (isSameAsTyped && !hasAlternates) return;
+    if (isSameAsTyped) return;
 
     if (depth >= MIN_SUGGEST_DEPTH) {
         const int finalFreq = calculateFinalFreq(inputIndex, depth, matchWeight, skipPos,
                 excessivePos, transposedPos, freq, sameLength);
         if (!isSameAsTyped)
             addWord(word, depth + 1, finalFreq);
-        if (hasAlternates)
-            addWordAlternatesSpellings(DICT_ROOT, pos, flags, finalFreq);
     }
 
     if (sameLength && depth >= mInputLength && skipPos < 0) {
@@ -680,6 +674,47 @@
     }
 }
 
+bool UnigramDictionary::getSplitTwoWordsSuggestion(const int inputLength,
+        const int firstWordStartPos, const int firstWordLength, const int secondWordStartPos,
+        const int secondWordLength, const bool isSpaceProximity) {
+    if (inputLength >= MAX_WORD_LENGTH) return false;
+    if (0 >= firstWordLength || 0 >= secondWordLength || firstWordStartPos >= secondWordStartPos
+            || firstWordStartPos < 0 || secondWordStartPos + secondWordLength > inputLength)
+        return false;
+    const int newWordLength = firstWordLength + secondWordLength + 1;
+    // Allocating variable length array on stack
+    unsigned short word[newWordLength];
+    const int firstFreq = getMostFrequentWordLike(firstWordStartPos, firstWordLength, mWord);
+    if (DEBUG_DICT) {
+        LOGI("First freq: %d", firstFreq);
+    }
+    if (firstFreq <= 0) return false;
+
+    for (int i = 0; i < firstWordLength; ++i) {
+        word[i] = mWord[i];
+    }
+
+    const int secondFreq = getMostFrequentWordLike(secondWordStartPos, secondWordLength, mWord);
+    if (DEBUG_DICT) {
+        LOGI("Second  freq:  %d", secondFreq);
+    }
+    if (secondFreq <= 0) return false;
+
+    word[firstWordLength] = SPACE;
+    for (int i = (firstWordLength + 1); i < newWordLength; ++i) {
+        word[i] = mWord[i - firstWordLength - 1];
+    }
+
+    int pairFreq = calcFreqForSplitTwoWords(TYPED_LETTER_MULTIPLIER, firstWordLength,
+            secondWordLength, firstFreq, secondFreq, isSpaceProximity);
+    if (DEBUG_DICT) {
+        LOGI("Split two words:  %d, %d, %d, %d, %d", firstFreq, secondFreq, pairFreq, inputLength,
+                TYPED_LETTER_MULTIPLIER);
+    }
+    addWord(word, newWordLength, pairFreq);
+    return true;
+}
+
 #ifndef NEW_DICTIONARY_FORMAT
 // TODO: Don't forget to bring inline functions back to over where they are used.
 
@@ -725,8 +760,8 @@
     }
 }
 
-inline int UnigramDictionary::getBestWordFreq(const int startInputIndex, const int inputLength,
-        unsigned short *word) {
+inline int UnigramDictionary::getMostFrequentWordLike(const int startInputIndex,
+        const int inputLength, unsigned short *word) {
     int pos = ROOT_POS;
     int count = Dictionary::getCount(DICT_ROOT, &pos);
     int maxFreq = 0;
@@ -860,52 +895,10 @@
     return NOT_VALID_WORD;
 }
 
-
 // The following functions will be modified.
-bool UnigramDictionary::getSplitTwoWordsSuggestion(const int inputLength,
-        const int firstWordStartPos, const int firstWordLength, const int secondWordStartPos,
-        const int secondWordLength, const bool isSpaceProximity) {
-    if (inputLength >= MAX_WORD_LENGTH) return false;
-    if (0 >= firstWordLength || 0 >= secondWordLength || firstWordStartPos >= secondWordStartPos
-            || firstWordStartPos < 0 || secondWordStartPos + secondWordLength > inputLength)
-        return false;
-    const int newWordLength = firstWordLength + secondWordLength + 1;
-    // Allocating variable length array on stack
-    unsigned short word[newWordLength];
-    const int firstFreq = getBestWordFreq(firstWordStartPos, firstWordLength, mWord);
-    if (DEBUG_DICT) {
-        LOGI("First freq: %d", firstFreq);
-    }
-    if (firstFreq <= 0) return false;
-
-    for (int i = 0; i < firstWordLength; ++i) {
-        word[i] = mWord[i];
-    }
-
-    const int secondFreq = getBestWordFreq(secondWordStartPos, secondWordLength, mWord);
-    if (DEBUG_DICT) {
-        LOGI("Second  freq:  %d", secondFreq);
-    }
-    if (secondFreq <= 0) return false;
-
-    word[firstWordLength] = SPACE;
-    for (int i = (firstWordLength + 1); i < newWordLength; ++i) {
-        word[i] = mWord[i - firstWordLength - 1];
-    }
-
-    int pairFreq = calcFreqForSplitTwoWords(TYPED_LETTER_MULTIPLIER, firstWordLength,
-            secondWordLength, firstFreq, secondFreq, isSpaceProximity);
-    if (DEBUG_DICT) {
-        LOGI("Split two words:  %d, %d, %d, %d, %d", firstFreq, secondFreq, pairFreq, inputLength,
-                TYPED_LETTER_MULTIPLIER);
-    }
-    addWord(word, newWordLength, pairFreq);
-    return true;
-}
-
-inline bool UnigramDictionary::processCurrentNode(const int pos, const int depth,
-        const int maxDepth, const bool traverseAllNodes, int matchWeight, int inputIndex,
-        const int diffs, const int skipPos, const int excessivePos, const int transposedPos,
+inline bool UnigramDictionary::processCurrentNode(const int initialPos, const int initialDepth,
+        const int maxDepth, const bool initialTraverseAllNodes, int matchWeight, int inputIndex,
+        const int initialDiffs, const int skipPos, const int excessivePos, const int transposedPos,
         int *nextLetters, const int nextLettersSize, int *newCount, int *newChildPosition,
         bool *newTraverseAllNodes, int *newMatchRate, int *newInputIndex, int *newDiffs,
         int *nextSiblingPosition, int *nextOutputIndex) {
@@ -922,6 +915,11 @@
     int freq;
     bool isSameAsUserTypedLength = false;
 
+    const int pos = initialPos;
+    const int depth = initialDepth;
+    const int traverseAllNodes = initialTraverseAllNodes;
+    const int diffs = initialDiffs;
+
     const uint8_t flags = 0; // No flags for now
 
     if (excessivePos == depth && inputIndex < mInputLength - 1) ++inputIndex;
@@ -993,53 +991,12 @@
 
 #else // NEW_DICTIONARY_FORMAT
 
-bool UnigramDictionary::getSplitTwoWordsSuggestion(const int inputLength,
-        const int firstWordStartPos, const int firstWordLength, const int secondWordStartPos,
-        const int secondWordLength, const bool isSpaceProximity) {
-    if (inputLength >= MAX_WORD_LENGTH) return false;
-    if (0 >= firstWordLength || 0 >= secondWordLength || firstWordStartPos >= secondWordStartPos
-            || firstWordStartPos < 0 || secondWordStartPos + secondWordLength > inputLength)
-        return false;
-    const int newWordLength = firstWordLength + secondWordLength + 1;
-    // Allocating variable length array on stack
-    unsigned short word[newWordLength];
-    const int firstFreq = getBestWordFreq(firstWordStartPos, firstWordLength, mWord);
-    if (DEBUG_DICT) {
-        LOGI("First freq: %d", firstFreq);
-    }
-    if (firstFreq <= 0) return false;
-
-    for (int i = 0; i < firstWordLength; ++i) {
-        word[i] = mWord[i];
-    }
-
-    const int secondFreq = getBestWordFreq(secondWordStartPos, secondWordLength, mWord);
-    if (DEBUG_DICT) {
-        LOGI("Second  freq:  %d", secondFreq);
-    }
-    if (secondFreq <= 0) return false;
-
-    word[firstWordLength] = SPACE;
-    for (int i = (firstWordLength + 1); i < newWordLength; ++i) {
-        word[i] = mWord[i - firstWordLength - 1];
-    }
-
-    int pairFreq = calcFreqForSplitTwoWords(TYPED_LETTER_MULTIPLIER, firstWordLength,
-            secondWordLength, firstFreq, secondFreq, isSpaceProximity);
-    if (DEBUG_DICT) {
-        LOGI("Split two words:  %d, %d, %d, %d, %d", firstFreq, secondFreq, pairFreq, inputLength,
-                TYPED_LETTER_MULTIPLIER);
-    }
-    addWord(word, newWordLength, pairFreq);
-    return true;
-}
-
-inline bool UnigramDictionary::processCurrentNode(const int pos, const int depth,
-        const int maxDepth, const bool traverseAllNodes, int matchWeight, int inputIndex,
-        const int diffs, const int skipPos, const int excessivePos, const int transposedPos,
+inline bool UnigramDictionary::processCurrentNode(const int initialPos, const int initialDepth,
+        const int maxDepth, const bool initialTraverseAllNodes, int matchWeight, int inputIndex,
+        const int initialDiffs, const int skipPos, const int excessivePos, const int transposedPos,
         int *nextLetters, const int nextLettersSize, int *newCount, int *newChildPosition,
         bool *newTraverseAllNodes, int *newMatchRate, int *newInputIndex, int *newDiffs,
-        int *nextSiblingPosition, int *nextOutputIndex) {
+        int *nextSiblingPosition, int *newOutputIndex) {
     if (DEBUG_DICT) {
         int inputCount = 0;
         if (skipPos >= 0) ++inputCount;
@@ -1053,13 +1010,18 @@
     int freq;
     bool isSameAsUserTypedLength = false;
 
+    int pos = initialPos;
+    int depth = initialDepth;
+    int traverseAllNodes = initialTraverseAllNodes;
+    int diffs = initialDiffs;
+
     const uint8_t flags = 0; // No flags for now
 
     if (excessivePos == depth && inputIndex < mInputLength - 1) ++inputIndex;
 
     *nextSiblingPosition = Dictionary::setDictionaryValues(DICT_ROOT, IS_LATEST_DICT_VERSION, pos,
             &c, &childPosition, &terminal, &freq);
-    *nextOutputIndex = depth + 1;
+    *newOutputIndex = depth + 1;
 
     const bool needsToTraverseChildrenNodes = childPosition != 0;
 
diff --git a/native/src/unigram_dictionary.h b/native/src/unigram_dictionary.h
index 154ac9b..789c495 100644
--- a/native/src/unigram_dictionary.h
+++ b/native/src/unigram_dictionary.h
@@ -60,31 +60,18 @@
     void getSuggestionCandidates(const int skipPos, const int excessivePos,
             const int transposedPos, int *nextLetters, const int nextLettersSize,
             const int maxDepth);
-    void getVersionNumber();
-    bool checkIfDictVersionIsLatest();
-    int getAddress(int *pos);
-    int getFreq(int *pos);
     bool sameAsTyped(const unsigned short *word, int length) const;
     bool addWord(unsigned short *word, int length, int frequency);
-    void addWordAlternatesSpellings(const uint8_t* const root, int pos, int depth, int finalFreq);
-    void getWordsRec(const int childrenCount, const int pos, const int depth, const int maxDepth,
-            const bool traverseAllNodes, const int snr, const int inputIndex, const int diffs,
-            const int skipPos, const int excessivePos, const int transposedPos, int *nextLetters,
-            const int nextLettersSize);
     bool getSplitTwoWordsSuggestion(const int inputLength,
             const int firstWordStartPos, const int firstWordLength,
             const int secondWordStartPos, const int secondWordLength, const bool isSpaceProximity);
     bool getMissingSpaceWords(const int inputLength, const int missingSpacePos);
     bool getMistypedSpaceWords(const int inputLength, const int spaceProximityPos);
-    // Keep getWordsOld for comparing performance between getWords and getWordsOld
-    void getWordsOld(const int initialPos, const int inputLength, const int skipPos,
-            const int excessivePos, const int transposedPos, int *nextLetters,
-            const int nextLettersSize);
     int calculateFinalFreq(const int inputIndex, const int depth, const int snr, const int skipPos,
             const int excessivePos, const int transposedPos, const int freq,
             const bool sameLength) const;
     void onTerminal(unsigned short int* word, const int depth,
-            const uint8_t* const root, const uint8_t flags, int pos,
+            const uint8_t* const root, const uint8_t flags, const int pos,
             const int inputIndex, const int matchWeight, const int skipPos,
             const int excessivePos, const int transposedPos, const int freq, const bool sameLength,
             int *nextLetters, const int nextLettersSize);
@@ -93,21 +80,30 @@
     ProximityType getMatchedProximityId(const int *currentChars, const unsigned short c,
             const int skipPos, const int excessivePos, const int transposedPos);
     // Process a node by considering proximity, missing and excessive character
-    bool processCurrentNode(const int pos, const int depth,
-            const int maxDepth, const bool traverseAllNodes, const int snr, int inputIndex,
-            const int diffs, const int skipPos, const int excessivePos, const int transposedPos,
-            int *nextLetters, const int nextLettersSize, int *newCount, int *newChildPosition,
-            bool *newTraverseAllNodes, int *newSnr, int*newInputIndex, int *newDiffs,
-            int *nextSiblingPosition, int *nextOutputIndex);
-    int getBestWordFreq(const int startInputIndex, const int inputLength, unsigned short *word);
-    // Process a node by considering missing space
-    bool processCurrentNodeForExactMatch(const int firstChildPos,
-            const int startInputIndex, const int depth, unsigned short *word,
-            int *newChildPosition, int *newCount, bool *newTerminal, int *newFreq, int *siblingPos);
+    bool processCurrentNode(const int initialPos, const int initialDepth,
+            const int maxDepth, const bool initialTraverseAllNodes, const int snr, int inputIndex,
+            const int initialDiffs, const int skipPos, const int excessivePos,
+            const int transposedPos, int *nextLetters, const int nextLettersSize, int *newCount,
+            int *newChildPosition, bool *newTraverseAllNodes, int *newSnr, int*newInputIndex,
+            int *newDiffs, int *nextSiblingPosition, int *nextOutputIndex);
     bool existsAdjacentProximityChars(const int inputIndex, const int inputLength) const;
     inline const int* getInputCharsAt(const int index) const {
         return mInputCodes + (index * MAX_PROXIMITY_CHARS);
     }
+    int getMostFrequentWordLike(const int startInputIndex, const int inputLength,
+            unsigned short *word);
+    void getWordsRec(const int childrenCount, const int pos, const int depth, const int maxDepth,
+            const bool traverseAllNodes, const int snr, const int inputIndex, const int diffs,
+            const int skipPos, const int excessivePos, const int transposedPos, int *nextLetters,
+            const int nextLettersSize);
+    // Keep getWordsOld for comparing performance between getWords and getWordsOld
+    void getWordsOld(const int initialPos, const int inputLength, const int skipPos,
+            const int excessivePos, const int transposedPos, int *nextLetters,
+            const int nextLettersSize);
+    // Process a node by considering missing space
+    bool processCurrentNodeForExactMatch(const int firstChildPos,
+            const int startInputIndex, const int depth, unsigned short *word,
+            int *newChildPosition, int *newCount, bool *newTerminal, int *newFreq, int *siblingPos);
 
     const uint8_t* const DICT_ROOT;
     const int MAX_WORD_LENGTH;