Fix a bug where the top prediction would disappear.

This is because prediction can't be easily distinguished in
style. This fixes the bug by simulating the right members,
but some refactoring should be done to remove useless
booleans.

Bug: 17271923
Change-Id: Ib88f3fb95678021624e59535492926dd315d26fb
diff --git a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
index c07997b..c33c015 100644
--- a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
+++ b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
@@ -68,7 +68,7 @@
     public static CharSequence getTextWithSuggestionSpan(final Context context,
             final String pickedWord, final SuggestedWords suggestedWords) {
         if (TextUtils.isEmpty(pickedWord) || suggestedWords.isEmpty()
-                || suggestedWords.mIsPrediction || suggestedWords.isPunctuationSuggestions()) {
+                || suggestedWords.isPrediction() || suggestedWords.isPunctuationSuggestions()) {
             return pickedWord;
         }
 
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 6045b34..aebc710 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1051,7 +1051,7 @@
                         applicationSpecifiedCompletions);
         final SuggestedWords suggestedWords = new SuggestedWords(applicationSuggestedWords,
                 null /* rawSuggestions */, false /* typedWordValid */, false /* willAutoCorrect */,
-                false /* isObsoleteSuggestions */, false /* isPrediction */,
+                false /* isObsoleteSuggestions */,
                 SuggestedWords.INPUT_STYLE_APPLICATION_SPECIFIED /* inputStyle */);
         // When in fullscreen mode, show completions generated by the application forcibly
         setSuggestedWords(suggestedWords);
diff --git a/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java b/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java
index 6b0205c..56014cb 100644
--- a/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java
@@ -35,7 +35,6 @@
                 false /* typedWordValid */,
                 false /* hasAutoCorrectionCandidate */,
                 false /* isObsoleteSuggestions */,
-                false /* isPrediction */,
                 INPUT_STYLE_NONE /* inputStyle */);
     }
 
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index ab852f8..6779351 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -120,9 +120,9 @@
     // and calls the callback function with the suggestions.
     private void getSuggestedWordsForNonBatchInput(final WordComposer wordComposer,
             final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo,
-            final SettingsValuesForSuggestion settingsValuesForSuggestion, final int inputStyle,
-            final boolean isCorrectionEnabled, final int sequenceNumber,
-            final OnGetSuggestedWordsCallback callback) {
+            final SettingsValuesForSuggestion settingsValuesForSuggestion,
+            final int inputStyleIfNotPrediction, final boolean isCorrectionEnabled,
+            final int sequenceNumber, final OnGetSuggestedWordsCallback callback) {
         final String typedWord = wordComposer.getTypedWord();
         final int trailingSingleQuotesCount = StringUtils.getTrailingSingleQuotesCount(typedWord);
         final String consideredWord = trailingSingleQuotesCount > 0
@@ -186,6 +186,8 @@
             suggestionsList = suggestionsContainer;
         }
 
+        final int inputStyle = resultsArePredictions ? SuggestedWords.INPUT_STYLE_PREDICTION :
+                inputStyleIfNotPrediction;
         callback.onGetSuggestedWords(new SuggestedWords(suggestionsList,
                 suggestionResults.mRawSuggestions,
                 // TODO: this first argument is lying. If this is a whitelisted word which is an
@@ -193,8 +195,7 @@
                 // rename the attribute or change the value.
                 !resultsArePredictions && !allowsToBeAutoCorrected /* typedWordValid */,
                 hasAutoCorrection /* willAutoCorrect */,
-                false /* isObsoleteSuggestions */, resultsArePredictions,
-                inputStyle, sequenceNumber));
+                false /* isObsoleteSuggestions */, inputStyle, sequenceNumber));
     }
 
     // Retrieves suggestions for the batch input
@@ -244,7 +245,6 @@
                 true /* typedWordValid */,
                 false /* willAutoCorrect */,
                 false /* isObsoleteSuggestions */,
-                false /* isPrediction */,
                 inputStyle, sequenceNumber));
     }
 
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 38fcb68..1eebabe 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -38,14 +38,15 @@
     public static final int INPUT_STYLE_TAIL_BATCH = 3;
     public static final int INPUT_STYLE_APPLICATION_SPECIFIED = 4;
     public static final int INPUT_STYLE_RECORRECTION = 5;
+    public static final int INPUT_STYLE_PREDICTION = 6;
 
     // The maximum number of suggestions available.
     public static final int MAX_SUGGESTIONS = 18;
 
     private static final ArrayList<SuggestedWordInfo> EMPTY_WORD_INFO_LIST = new ArrayList<>(0);
     public static final SuggestedWords EMPTY = new SuggestedWords(
-            EMPTY_WORD_INFO_LIST, null /* rawSuggestions */, false, false, false, false,
-            INPUT_STYLE_NONE);
+            EMPTY_WORD_INFO_LIST, null /* rawSuggestions */, false /* typedWordValid */,
+            false /* willAutoCorrect */, false /* isObsoleteSuggestions */, INPUT_STYLE_NONE);
 
     public final String mTypedWord;
     public final boolean mTypedWordValid;
@@ -54,7 +55,6 @@
     // whether this exactly matches the user entry or not.
     public final boolean mWillAutoCorrect;
     public final boolean mIsObsoleteSuggestions;
-    public final boolean mIsPrediction;
     // How the input for these suggested words was done by the user. Must be one of the
     // INPUT_STYLE_* constants above.
     public final int mInputStyle;
@@ -67,10 +67,9 @@
             final boolean typedWordValid,
             final boolean willAutoCorrect,
             final boolean isObsoleteSuggestions,
-            final boolean isPrediction,
             final int inputStyle) {
         this(suggestedWordInfoList, rawSuggestions, typedWordValid, willAutoCorrect,
-                isObsoleteSuggestions, isPrediction, inputStyle, NOT_A_SEQUENCE_NUMBER);
+                isObsoleteSuggestions, inputStyle, NOT_A_SEQUENCE_NUMBER);
     }
 
     public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList,
@@ -78,13 +77,12 @@
             final boolean typedWordValid,
             final boolean willAutoCorrect,
             final boolean isObsoleteSuggestions,
-            final boolean isPrediction,
             final int inputStyle,
             final int sequenceNumber) {
         this(suggestedWordInfoList, rawSuggestions,
-                (suggestedWordInfoList.isEmpty() || isPrediction) ? null
+                (suggestedWordInfoList.isEmpty() || INPUT_STYLE_PREDICTION == inputStyle) ? null
                         : suggestedWordInfoList.get(INDEX_OF_TYPED_WORD).mWord,
-                typedWordValid, willAutoCorrect, isObsoleteSuggestions, isPrediction, inputStyle,
+                typedWordValid, willAutoCorrect, isObsoleteSuggestions, inputStyle,
                 sequenceNumber);
     }
 
@@ -94,7 +92,6 @@
             final boolean typedWordValid,
             final boolean willAutoCorrect,
             final boolean isObsoleteSuggestions,
-            final boolean isPrediction,
             final int inputStyle,
             final int sequenceNumber) {
         mSuggestedWordInfoList = suggestedWordInfoList;
@@ -102,7 +99,6 @@
         mTypedWordValid = typedWordValid;
         mWillAutoCorrect = willAutoCorrect;
         mIsObsoleteSuggestions = isObsoleteSuggestions;
-        mIsPrediction = isPrediction;
         mInputStyle = inputStyle;
         mSequenceNumber = sequenceNumber;
         mTypedWord = typedWord;
@@ -381,9 +377,14 @@
         }
     }
 
+    public boolean isPrediction() {
+        return INPUT_STYLE_PREDICTION == mInputStyle;
+    }
+
     // SuggestedWords is an immutable object, as much as possible. We must not just remove
     // words from the member ArrayList as some other parties may expect the object to never change.
-    public SuggestedWords getSuggestedWordsExcludingTypedWord(final int inputStyle) {
+    // This is only ever called by recorrection at the moment, hence the ForRecorrection moniker.
+    public SuggestedWords getSuggestedWordsExcludingTypedWordForRecorrection() {
         final ArrayList<SuggestedWordInfo> newSuggestions = new ArrayList<>();
         String typedWord = null;
         for (int i = 0; i < mSuggestedWordInfoList.size(); ++i) {
@@ -399,7 +400,7 @@
         // no auto-correction should take place hence willAutoCorrect = false.
         return new SuggestedWords(newSuggestions, null /* rawSuggestions */, typedWord,
                 true /* typedWordValid */, false /* willAutoCorrect */, mIsObsoleteSuggestions,
-                mIsPrediction, inputStyle, NOT_A_SEQUENCE_NUMBER);
+                SuggestedWords.INPUT_STYLE_RECORRECTION, NOT_A_SEQUENCE_NUMBER);
     }
 
     // Creates a new SuggestedWordInfo from the currently suggested words that removes all but the
@@ -418,8 +419,7 @@
                     SuggestedWordInfo.NOT_A_CONFIDENCE));
         }
         return new SuggestedWords(newSuggestions, null /* rawSuggestions */, mTypedWordValid,
-                mWillAutoCorrect, mIsObsoleteSuggestions, mIsPrediction,
-                INPUT_STYLE_TAIL_BATCH);
+                mWillAutoCorrect, mIsObsoleteSuggestions, INPUT_STYLE_TAIL_BATCH);
     }
 
     /**
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 616828e..a697880 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -638,7 +638,7 @@
             case Constants.CODE_SHIFT:
                 performRecapitalization(inputTransaction.mSettingsValues);
                 inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
-                if (mSuggestedWords.mIsPrediction) {
+                if (mSuggestedWords.isPrediction()) {
                     inputTransaction.setRequiresUpdateSuggestions();
                 }
                 break;
@@ -1466,11 +1466,10 @@
                                     && !shouldIncludeResumedWordInSuggestions) {
                                 // We were able to compute new suggestions for this word.
                                 // Remove the typed word, since we don't want to display it in this
-                                // case. The #getSuggestedWordsExcludingTypedWord() method sets
-                                // willAutoCorrect to false.
+                                // case. The #getSuggestedWordsExcludingTypedWordForRecorrection()
+                                // method sets willAutoCorrect to false.
                                 suggestedWords = suggestedWordsIncludingTypedWord
-                                        .getSuggestedWordsExcludingTypedWord(SuggestedWords
-                                                .INPUT_STYLE_RECORRECTION);
+                                        .getSuggestedWordsExcludingTypedWordForRecorrection();
                             } else {
                                 // No saved suggestions, and we were unable to compute any good one
                                 // either. Rather than displaying an empty suggestion strip, we'll
@@ -1487,11 +1486,9 @@
             // color of the word in the suggestion strip changes according to this parameter,
             // and false gives the correct color.
             final SuggestedWords suggestedWords = new SuggestedWords(suggestions,
-                    null /* rawSuggestions */, typedWord,
-                    false /* typedWordValid */, false /* willAutoCorrect */,
-                    false /* isObsoleteSuggestions */, false /* isPrediction */,
-                    SuggestedWords.INPUT_STYLE_RECORRECTION,
-                    SuggestedWords.NOT_A_SEQUENCE_NUMBER);
+                    null /* rawSuggestions */, typedWord, false /* typedWordValid */,
+                    false /* willAutoCorrect */, false /* isObsoleteSuggestions */,
+                    SuggestedWords.INPUT_STYLE_RECORRECTION, SuggestedWords.NOT_A_SEQUENCE_NUMBER);
             mIsAutoCorrectionIndicatorOn = false;
             mLatinIME.mHandler.showSuggestionStrip(suggestedWords);
         }
@@ -1787,8 +1784,7 @@
                 SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord, oldSuggestedWords);
         return new SuggestedWords(typedWordAndPreviousSuggestions, null /* rawSuggestions */,
                 false /* typedWordValid */, false /* hasAutoCorrectionCandidate */,
-                true /* isObsoleteSuggestions */, false /* isPrediction */,
-                oldSuggestedWords.mInputStyle);
+                true /* isObsoleteSuggestions */, oldSuggestedWords.mInputStyle);
     }
 
     /**
diff --git a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
index 2785dec..c28d08c 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
@@ -62,6 +62,7 @@
     public void testGetSuggestedWordsExcludingTypedWord() {
         final String TYPED_WORD = "typed";
         final int NUMBER_OF_ADDED_SUGGESTIONS = 5;
+        final int KIND_OF_SECOND_CORRECTION = SuggestedWordInfo.KIND_CORRECTION;
         final ArrayList<SuggestedWordInfo> list = new ArrayList<>();
         list.add(createTypedWordInfo(TYPED_WORD));
         for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) {
@@ -73,21 +74,23 @@
                 false /* typedWordValid */,
                 false /* willAutoCorrect */,
                 false /* isObsoleteSuggestions */,
-                false /* isPrediction*/,
                 SuggestedWords.INPUT_STYLE_NONE);
         assertEquals(NUMBER_OF_ADDED_SUGGESTIONS + 1, words.size());
         assertEquals("typed", words.getWord(0));
         assertTrue(words.getInfo(0).isKindOf(SuggestedWordInfo.KIND_TYPED));
         assertEquals("0", words.getWord(1));
-        assertTrue(words.getInfo(1).isKindOf(SuggestedWordInfo.KIND_CORRECTION));
+        assertTrue(words.getInfo(1).isKindOf(KIND_OF_SECOND_CORRECTION));
         assertEquals("4", words.getWord(5));
-        assertTrue(words.getInfo(5).isKindOf(SuggestedWordInfo.KIND_CORRECTION));
+        assertTrue(words.getInfo(5).isKindOf(KIND_OF_SECOND_CORRECTION));
 
-        final SuggestedWords wordsWithoutTyped = words.getSuggestedWordsExcludingTypedWord(
-                SuggestedWords.INPUT_STYLE_NONE);
+        final SuggestedWords wordsWithoutTyped =
+                words.getSuggestedWordsExcludingTypedWordForRecorrection();
+        // Make sure that the typed word has indeed been excluded, by testing the size of the
+        // suggested words, the string and the kind of the top suggestion, which should match
+        // the string and kind of what we inserted after the typed word.
         assertEquals(words.size() - 1, wordsWithoutTyped.size());
         assertEquals("0", wordsWithoutTyped.getWord(0));
-        assertTrue(wordsWithoutTyped.getInfo(0).isKindOf(SuggestedWordInfo.KIND_CORRECTION));
+        assertTrue(wordsWithoutTyped.getInfo(0).isKindOf(KIND_OF_SECOND_CORRECTION));
     }
 
     // Helper for testGetTransformedWordInfo
@@ -133,7 +136,6 @@
                 false /* typedWordValid */,
                 false /* willAutoCorrect */,
                 false /* isObsoleteSuggestions */,
-                false /* isPrediction*/,
                 SuggestedWords.INPUT_STYLE_NONE);
         final SuggestedWordInfo typedWord = wordsWithTypedWord.getTypedWordInfoOrNull();
         assertNotNull(typedWord);
@@ -141,8 +143,7 @@
 
         // Make sure getTypedWordInfoOrNull() returns null.
         final SuggestedWords wordsWithoutTypedWord =
-                wordsWithTypedWord.getSuggestedWordsExcludingTypedWord(
-                        SuggestedWords.INPUT_STYLE_NONE);
+                wordsWithTypedWord.getSuggestedWordsExcludingTypedWordForRecorrection();
         assertNull(wordsWithoutTypedWord.getTypedWordInfoOrNull());
 
         // Make sure getTypedWordInfoOrNull() returns null.
diff --git a/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java
index 2cc22fa..eb76032 100644
--- a/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java
+++ b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java
@@ -429,7 +429,7 @@
         assertFalse("willAutoCorrect", suggestedWords.mWillAutoCorrect);
         assertTrue("isPunctuationSuggestions", suggestedWords.isPunctuationSuggestions());
         assertFalse("isObsoleteSuggestions", suggestedWords.mIsObsoleteSuggestions);
-        assertFalse("isPrediction", suggestedWords.mIsPrediction);
+        assertFalse("isPrediction", suggestedWords.isPrediction());
         assertEquals("size", punctuationLabels.length, suggestedWords.size());
         for (int index = 0; index < suggestedWords.size(); index++) {
             assertEquals("punctuation label at " + index,