Merge "Show important notice dialog"
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 6e0cdf2..00eb57c 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -22,6 +22,7 @@
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.keyboard.ProximityInfo;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.makedict.Word;
 import com.android.inputmethod.latin.settings.NativeSuggestOptions;
 import com.android.inputmethod.latin.utils.CollectionUtils;
 import com.android.inputmethod.latin.utils.JniUtils;
@@ -148,6 +149,7 @@
             int[] outCodePoints, boolean[] outFlags, int[] outProbabilityInfo,
             ArrayList<int[]> outBigramTargets, ArrayList<int[]> outBigramProbabilityInfo,
             ArrayList<int[]> outShortcutTargets, ArrayList<Integer> outShortcutProbabilities);
+    private static native int getNextWordNative(long dict, int token, int[] outCodePoints);
     private static native int getSuggestionsNative(long dict, long proximityInfo,
             long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times,
             int[] pointerIds, int[] inputCodePoints, int inputSize, int commitPoint,
@@ -332,6 +334,33 @@
                 outShortcutProbabilities);
     }
 
+    public static class GetNextWordPropertyResult {
+        public WordProperty mWordProperty;
+        public int mNextToken;
+
+        public GetNextWordPropertyResult(final WordProperty wordPreperty, final int nextToken) {
+            mWordProperty = wordPreperty;
+            mNextToken = nextToken;
+        }
+    }
+
+    /**
+     * Method to iterate all words in the dictionary for makedict.
+     * If token is 0, this method newly starts iterating the dictionary.
+     */
+    @UsedForTesting
+    public GetNextWordPropertyResult getNextWordProperty(final int token) {
+        final int[] codePoints = new int[MAX_WORD_LENGTH];
+        final int nextToken = getNextWordNative(mNativeDict, token, codePoints);
+        int len = 0;
+        // codePoints is null-terminated if its length is shorter than the array length.
+        while (len < MAX_WORD_LENGTH && codePoints[len] != 0) {
+            ++len;
+        }
+        final String word = new String(mOutputCodePoints, 0, len);
+        return new GetNextWordPropertyResult(getWordProperty(word), nextToken);
+    }
+
     // 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,
@@ -380,7 +409,6 @@
                 return;
             }
         }
-
     }
 
     private void reopen() {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 1a6d387..0806227 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1422,10 +1422,12 @@
             // because it may differ from mWordComposer.mTypedWord.
             autoCorrection = sourceSuggestedWords.mTypedWord;
         }
-        if (SuggestedWords.EMPTY != suggestedWords) {
+        if (SuggestedWords.EMPTY == suggestedWords) {
+            setNeutralSuggestionStrip();
+        } else {
             mInputLogic.mWordComposer.setAutoCorrection(autoCorrection);
+            setSuggestedWords(suggestedWords, isSuggestionsStripVisible());
         }
-        setSuggestedWords(suggestedWords, isSuggestionsStripVisible());
         // Cache the auto-correction in accessibility code so we can speak it if the user
         // touches a key that will insert it.
         AccessibilityUtils.getInstance().setAutoCorrection(suggestedWords,
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 1bc67b2..f53183f 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -1142,6 +1142,8 @@
         // Recorrection is not supported in languages without spaces because we don't know
         // how to segment them yet.
         if (!settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces) return;
+        // If no suggestions are requested, don't try restarting suggestions.
+        if (!settingsValues.isSuggestionsRequested()) return;
         // If the cursor is not touching a word, or if there is a selection, return right away.
         if (mConnection.hasSelection()) return;
         // If we don't know the cursor location, return.
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 8f3f8e2..c919ebd 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -260,6 +260,26 @@
             word1Length);
 }
 
+// Method to iterate all words in the dictionary for makedict.
+// If token is 0, this method newly starts iterating the dictionary. This method returns 0 when
+// the dictionary does not have a next word.
+static jint latinime_BinaryDictionary_getNextWord(JNIEnv *env, jclass clazz,
+        jlong dict, jint token, jintArray outCodePoints) {
+    Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
+    if (!dictionary) return 0;
+    const jsize outCodePointsLength = env->GetArrayLength(outCodePoints);
+    if (outCodePointsLength != MAX_WORD_LENGTH) {
+        AKLOGE("Invalid outCodePointsLength: %d", outCodePointsLength);
+        ASSERT(false);
+        return 0;
+    }
+    int wordCodePoints[outCodePointsLength];
+    memset(wordCodePoints, 0, sizeof(wordCodePoints));
+    const int nextToken = dictionary->getNextWordAndNextToken(token, wordCodePoints);
+    env->SetIntArrayRegion(outCodePoints, 0, outCodePointsLength, wordCodePoints);
+    return nextToken;
+}
+
 static void latinime_BinaryDictionary_getWordProperty(JNIEnv *env, jclass clazz,
         jlong dict, jintArray word, jintArray outCodePoints, jbooleanArray outFlags,
         jintArray outProbabilityInfo, jobject outBigramTargets, jobject outBigramProbabilityInfo,
@@ -527,6 +547,11 @@
         reinterpret_cast<void *>(latinime_BinaryDictionary_getWordProperty)
     },
     {
+        const_cast<char *>("getNextWordNative"),
+        const_cast<char *>("(JI[I)I"),
+        reinterpret_cast<void *>(latinime_BinaryDictionary_getNextWord)
+    },
+    {
         const_cast<char *>("calcNormalizedScoreNative"),
         const_cast<char *>("([I[II)F"),
         reinterpret_cast<void *>(latinime_BinaryDictionary_calcNormalizedScore)
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index 16b1a56..9b71eff 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -150,6 +150,12 @@
             codePoints, codePointCount);
 }
 
+int Dictionary::getNextWordAndNextToken(const int token, int *const outCodePoints) {
+    TimeKeeper::setCurrentTime();
+    return mDictionaryStructureWithBufferPolicy.get()->getNextWordAndNextToken(
+            token, outCodePoints);
+}
+
 void Dictionary::logDictionaryInfo(JNIEnv *const env) const {
     int dictionaryIdCodePointBuffer[HEADER_ATTRIBUTE_BUFFER_SIZE];
     int versionStringCodePointBuffer[HEADER_ATTRIBUTE_BUFFER_SIZE];
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h
index 4a468f3..0a413cb 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary.h
@@ -96,6 +96,11 @@
 
     const WordProperty getWordProperty(const int *const codePoints, const int codePointCount);
 
+    // Method to iterate all words in the dictionary.
+    // The returned token has to be used to get the next word. If token is 0, this method newly
+    // starts iterating the dictionary.
+    int getNextWordAndNextToken(const int token, int *const outCodePoints);
+
     const DictionaryStructureWithBufferPolicy *getDictionaryStructurePolicy() const {
         return mDictionaryStructureWithBufferPolicy.get();
     }
diff --git a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
index b878984..7844195 100644
--- a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
+++ b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
@@ -95,6 +95,11 @@
     virtual const WordProperty getWordProperty(const int *const codePonts,
             const int codePointCount) const = 0;
 
+    // Method to iterate all words in the dictionary.
+    // The returned token has to be used to get the next word. If token is 0, this method newly
+    // starts iterating the dictionary.
+    virtual int getNextWordAndNextToken(const int token, int *const outCodePoints) = 0;
+
  protected:
     DictionaryStructureWithBufferPolicy() {}
 
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
index 67d615e..319c815 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
@@ -129,6 +129,11 @@
         return WordProperty();
     }
 
+    int getNextWordAndNextToken(const int token, int *const outCodePoints) {
+        // getNextWordAndNextToken is not supported.
+        return 0;
+    }
+
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(PatriciaTriePolicy);
 
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
index 5022baf..1c420e0 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
@@ -392,4 +392,10 @@
             historicalInfo->getCount(), &bigrams, &shortcuts);
 }
 
+int Ver4PatriciaTriePolicy::getNextWordAndNextToken(const int token,
+        int *const outCodePoints) {
+    // TODO: Implement.
+    return 0;
+}
+
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
index a43bd0e..1bcd4ce 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
@@ -109,6 +109,8 @@
     const WordProperty getWordProperty(const int *const codePoints,
             const int codePointCount) const;
 
+    int getNextWordAndNextToken(const int token, int *const outCodePoints);
+
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4PatriciaTriePolicy);