Tentatively remove a dependency on WordCallback (A3)

Bug: 6252660
Bug: 6166228
Bug: 2704000
Bug: 6225530
Change-Id: Id5a59eaec2aeefa0ba4524420a8e035d383f6545
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index 4a5471c..f5886aa 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -21,6 +21,7 @@
 import com.android.inputmethod.keyboard.KeyDetector;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.ProximityInfo;
+import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.UserHistoryForgettingCurveUtils.ForgettingCurveParams;
 
 import java.util.ArrayList;
@@ -258,12 +259,14 @@
         if (codes.size() >= BinaryDictionary.MAX_WORD_LENGTH) {
             return;
         }
-        getWordsInner(codes, prevWordForBigrams, callback, proximityInfo);
+        final ArrayList<SuggestedWordInfo> suggestions =
+                getWordsInner(codes, prevWordForBigrams, proximityInfo);
+        Utils.addAllSuggestions(mDicTypeId, Dictionary.UNIGRAM, suggestions, callback);
     }
 
-    protected final void getWordsInner(final WordComposer codes,
-            final CharSequence prevWordForBigrams, final WordCallback callback,
-            final ProximityInfo proximityInfo) {
+    protected final ArrayList<SuggestedWordInfo> getWordsInner(final WordComposer codes,
+            final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) {
+        final ArrayList<SuggestedWordInfo> suggestions = new ArrayList<SuggestedWordInfo>();
         mInputLength = codes.size();
         if (mCodes.length < mInputLength) mCodes = new int[mInputLength][];
         final int[] xCoordinates = codes.getXCoordinates();
@@ -281,10 +284,11 @@
             proximityInfo.fillArrayWithNearestKeyCodes(x, y, codes.getCodeAt(i), mCodes[i]);
         }
         mMaxDepth = mInputLength * 3;
-        getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, -1, callback);
+        getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, -1, suggestions);
         for (int i = 0; i < mInputLength; i++) {
-            getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, i, callback);
+            getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, i, suggestions);
         }
+        return suggestions;
     }
 
     @Override
@@ -368,24 +372,27 @@
      * @param word the word to insert, as an array of code points
      * @param depth the depth of the node in the tree
      * @param finalFreq the frequency for this word
+     * @param suggestions the suggestion collection to add the suggestions to
      * @return whether there is still space for more words.
-     * @see Dictionary.WordCallback#addWord(char[], int, int, int, int, int)
      */
     private boolean addWordAndShortcutsFromNode(final Node node, final char[] word, final int depth,
-            final int finalFreq, final WordCallback callback) {
+            final int finalFreq, final ArrayList<SuggestedWordInfo> suggestions) {
         if (finalFreq > 0 && !node.mShortcutOnly) {
-            if (!callback.addWord(word, 0, depth + 1, finalFreq, mDicTypeId, Dictionary.UNIGRAM)) {
-                return false;
-            }
+            // Use KIND_CORRECTION always. This dictionary does not really have a notion of
+            // COMPLETION against CORRECTION; we could artificially add one by looking at
+            // the respective size of the typed word and the suggestion if it matters sometime
+            // in the future.
+            suggestions.add(new SuggestedWordInfo(new String(word, 0, depth + 1), finalFreq,
+                    SuggestedWordInfo.KIND_CORRECTION));
+            if (suggestions.size() >= Suggest.MAX_SUGGESTIONS) return false;
         }
         if (null != node.mShortcutTargets) {
             final int length = node.mShortcutTargets.size();
             for (int shortcutIndex = 0; shortcutIndex < length; ++shortcutIndex) {
                 final char[] shortcut = node.mShortcutTargets.get(shortcutIndex);
-                if (!callback.addWord(shortcut, 0, shortcut.length, finalFreq, mDicTypeId,
-                        Dictionary.UNIGRAM)) {
-                    return false;
-                }
+                suggestions.add(new SuggestedWordInfo(new String(shortcut, 0, shortcut.length),
+                        finalFreq, SuggestedWordInfo.KIND_SHORTCUT));
+                if (suggestions.size() > Suggest.MAX_SUGGESTIONS) return false;
             }
         }
         return true;
@@ -408,12 +415,12 @@
      * case we skip over some punctuations such as apostrophe in the traversal. That is, if you type
      * "wouldve", it could be matching "would've", so the depth will be one more than the
      * inputIndex
-     * @param callback the callback class for adding a word
+     * @param suggestions the list in which to add suggestions
      */
     // TODO: Share this routine with the native code for BinaryDictionary
     protected void getWordsRec(NodeArray roots, final WordComposer codes, final char[] word,
             final int depth, final boolean completion, int snr, int inputIndex, int skipPos,
-            WordCallback callback) {
+            final ArrayList<SuggestedWordInfo> suggestions) {
         final int count = roots.mLength;
         final int codeSize = mInputLength;
         // Optimization: Prune out words that are too long compared to how much was typed.
@@ -443,14 +450,14 @@
                     } else {
                         finalFreq = computeSkippedWordFinalFreq(freq, snr, mInputLength);
                     }
-                    if (!addWordAndShortcutsFromNode(node, word, depth, finalFreq, callback)) {
+                    if (!addWordAndShortcutsFromNode(node, word, depth, finalFreq, suggestions)) {
                         // No space left in the queue, bail out
                         return;
                     }
                 }
                 if (children != null) {
                     getWordsRec(children, codes, word, depth + 1, true, snr, inputIndex,
-                            skipPos, callback);
+                            skipPos, suggestions);
                 }
             } else if ((c == Keyboard.CODE_SINGLE_QUOTE
                     && currentChars[0] != Keyboard.CODE_SINGLE_QUOTE) || depth == skipPos) {
@@ -458,7 +465,7 @@
                 word[depth] = c;
                 if (children != null) {
                     getWordsRec(children, codes, word, depth + 1, completion, snr, inputIndex,
-                            skipPos, callback);
+                            skipPos, suggestions);
                 }
             } else {
                 // Don't use alternatives if we're looking for missing characters
@@ -483,7 +490,7 @@
                                             snr * addedAttenuation, mInputLength);
                                 }
                                 if (!addWordAndShortcutsFromNode(node, word, depth, finalFreq,
-                                        callback)) {
+                                        suggestions)) {
                                     // No space left in the queue, bail out
                                     return;
                                 }
@@ -491,12 +498,12 @@
                             if (children != null) {
                                 getWordsRec(children, codes, word, depth + 1,
                                         true, snr * addedAttenuation, inputIndex + 1,
-                                        skipPos, callback);
+                                        skipPos, suggestions);
                             }
                         } else if (children != null) {
                             getWordsRec(children, codes, word, depth + 1,
                                     false, snr * addedAttenuation, inputIndex + 1,
-                                    skipPos, callback);
+                                    skipPos, suggestions);
                         }
                     }
                 }
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 1ed91fe..45ac9ff 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -129,10 +129,11 @@
         public static final int KIND_BLACKLIST = 4; // Blacklisted word
         public static final int KIND_HARDCODED = 5; // Hardcoded suggestion, e.g. punctuation
         public static final int KIND_APP_DEFINED = 6; // Suggested by the application
+        public static final int KIND_SHORTCUT = 7; // A shortcut
         private final String mWordStr;
         public final CharSequence mWord;
         public final int mScore;
-        public final int mKind;
+        public final int mKind; // one of the KIND_* constants above
         public final int mCodePointCount;
         private String mDebugString = "";
 
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index f2d21ab..a44b1f9 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -44,6 +44,7 @@
 import java.io.PrintWriter;
 import java.nio.channels.FileChannel;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
 
@@ -530,4 +531,14 @@
         }
         return builder.toString();
     }
+
+    public static void addAllSuggestions(final int dicTypeId, final int dataType,
+            final ArrayList<SuggestedWords.SuggestedWordInfo> suggestions,
+            final Dictionary.WordCallback callback) {
+        for (SuggestedWordInfo suggestion : suggestions) {
+            final String suggestionStr = suggestion.mWord.toString();
+            callback.addWord(suggestionStr.toCharArray(), 0, suggestionStr.length(),
+                    suggestion.mScore, dicTypeId, dataType);
+        }
+    }
 }