diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 26248db7592d46ec701844a84108469b77f9efac..90398deb2deedae977a05de19cdb597e8354b24e 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -155,6 +155,10 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
         onSharedPreferenceChanged(prefs, PREF_USE_CONTACTS_KEY);
     }
 
+    public float getRecommendedThreshold() {
+        return mRecommendedThreshold;
+    }
+
     private static String getKeyboardLayoutNameForScript(final int script) {
         switch (script) {
         case ScriptUtils.SCRIPT_LATIN:
@@ -214,95 +218,6 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
                 EMPTY_STRING_ARRAY);
     }
 
-    public SuggestionsGatherer newSuggestionsGatherer(final String text, int maxLength) {
-        return new SuggestionsGatherer(text, mRecommendedThreshold, maxLength);
-    }
-
-    // TODO: remove this class and replace it by storage local to the session.
-    public static final class SuggestionsGatherer {
-        public static final class Result {
-            public final String[] mSuggestions;
-            public final boolean mHasRecommendedSuggestions;
-            public Result(final String[] gatheredSuggestions,
-                    final boolean hasRecommendedSuggestions) {
-                mSuggestions = gatheredSuggestions;
-                mHasRecommendedSuggestions = hasRecommendedSuggestions;
-            }
-        }
-
-        private final ArrayList<String> mSuggestions;
-        private final ArrayList<Integer> mScores;
-        private final String mOriginalText;
-        private final float mRecommendedThreshold;
-        private final int mMaxLength;
-
-        SuggestionsGatherer(final String originalText, final float recommendedThreshold,
-                final int maxLength) {
-            mOriginalText = originalText;
-            mRecommendedThreshold = recommendedThreshold;
-            mMaxLength = maxLength;
-            mSuggestions = new ArrayList<>();
-            mScores = new ArrayList<>();
-        }
-
-        public void addResults(final SuggestionResults suggestionResults) {
-            if (suggestionResults == null) {
-                return;
-            }
-            // suggestionResults is sorted.
-            for (final SuggestedWordInfo suggestedWordInfo : suggestionResults) {
-                mSuggestions.add(suggestedWordInfo.mWord);
-                mScores.add(suggestedWordInfo.mScore);
-            }
-        }
-
-        public Result getResults(final int capitalizeType, final Locale locale) {
-            final String[] gatheredSuggestions;
-            final boolean hasRecommendedSuggestions;
-            if (mSuggestions.isEmpty()) {
-                gatheredSuggestions = null;
-                hasRecommendedSuggestions = false;
-            } else {
-                if (DBG) {
-                    for (int i = 0; i < mSuggestions.size(); i++) {
-                        Log.i(TAG, "" + mScores.get(i) + " " + mSuggestions.get(i));
-                    }
-                }
-                StringUtils.removeDupes(mSuggestions);
-                if (StringUtils.CAPITALIZE_ALL == capitalizeType) {
-                    for (int i = 0; i < mSuggestions.size(); ++i) {
-                        // get(i) returns a CharSequence which is actually a String so .toString()
-                        // should return the same object.
-                        mSuggestions.set(i, mSuggestions.get(i).toString().toUpperCase(locale));
-                    }
-                } else if (StringUtils.CAPITALIZE_FIRST == capitalizeType) {
-                    for (int i = 0; i < mSuggestions.size(); ++i) {
-                        // Likewise
-                        mSuggestions.set(i, StringUtils.capitalizeFirstCodePoint(
-                                mSuggestions.get(i).toString(), locale));
-                    }
-                }
-                // This returns a String[], while toArray() returns an Object[] which cannot be cast
-                // into a String[].
-                gatheredSuggestions = mSuggestions.toArray(EMPTY_STRING_ARRAY);
-
-                final int bestScore = mScores.get(0);
-                final String bestSuggestion = mSuggestions.get(0);
-                final float normalizedScore =
-                        BinaryDictionaryUtils.calcNormalizedScore(
-                                mOriginalText, bestSuggestion.toString(), bestScore);
-                hasRecommendedSuggestions = (normalizedScore > mRecommendedThreshold);
-                if (DBG) {
-                    Log.i(TAG, "Best suggestion : " + bestSuggestion + ", score " + bestScore);
-                    Log.i(TAG, "Normalized score = " + normalizedScore
-                            + " (threshold " + mRecommendedThreshold
-                            + ") => hasRecommendedSuggestions = " + hasRecommendedSuggestions);
-                }
-            }
-            return new Result(gatheredSuggestions, hasRecommendedSuggestions);
-        }
-    }
-
     public boolean isValidWord(final Locale locale, final String word) {
         mSemaphore.acquireUninterruptibly();
         try {
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java
index 6bfd354ea79a8f08ec12fe79c5ae838d489aa23b..38d72066428425c8f5da6db6ebe220614c8d8fc2 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java
@@ -32,7 +32,6 @@ import java.util.Locale;
 public final class AndroidSpellCheckerSession extends AndroidWordLevelSpellCheckerSession {
     private static final String TAG = AndroidSpellCheckerSession.class.getSimpleName();
     private static final boolean DBG = false;
-    private final static String[] EMPTY_STRING_ARRAY = new String[0];
     private final Resources mResources;
     private SentenceLevelAdapter mSentenceLevelAdapter;
 
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index ca0725e28ab618a9cff82cfc1dd034886d24574d..d668672aa20c57241e146bfa2ed3782c128fddca 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -34,20 +34,22 @@ import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.PrevWordsInfo;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.WordComposer;
-import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
-import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService.SuggestionsGatherer;
+import com.android.inputmethod.latin.utils.BinaryDictionaryUtils;
 import com.android.inputmethod.latin.utils.CoordinateUtils;
 import com.android.inputmethod.latin.utils.LocaleUtils;
 import com.android.inputmethod.latin.utils.ScriptUtils;
 import com.android.inputmethod.latin.utils.StringUtils;
 import com.android.inputmethod.latin.utils.SuggestionResults;
 
+import java.util.ArrayList;
 import java.util.Locale;
 
 public abstract class AndroidWordLevelSpellCheckerSession extends Session {
     private static final String TAG = AndroidWordLevelSpellCheckerSession.class.getSimpleName();
     private static final boolean DBG = false;
 
+    public final static String[] EMPTY_STRING_ARRAY = new String[0];
+
     // Immutable, but not available in the constructor.
     private Locale mLocale;
     // Cache this for performance
@@ -279,14 +281,11 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
                 proximityInfo = keyboard.getProximityInfo();
             }
             composer.setComposingWord(codePoints, coordinates);
+            // TODO: Don't gather suggestions if the limit is <= 0 unless necessary
             final SuggestionResults suggestionResults = mService.getSuggestionResults(
                     mLocale, composer, prevWordsInfo, proximityInfo);
-            // TODO: Don't gather suggestions if the limit is <= 0 unless necessary
-            final SuggestionsGatherer suggestionsGatherer = mService.newSuggestionsGatherer(
-                    text, suggestionsLimit);
-            suggestionsGatherer.addResults(suggestionResults);
-            final SuggestionsGatherer.Result result = suggestionsGatherer.getResults(
-                    capitalizeType, mLocale);
+            final Result result = getResult(capitalizeType, mLocale, suggestionsLimit,
+                    mService.getRecommendedThreshold(), text, suggestionResults);
             isInDict = isInDictForAnyCapitalization(text, capitalizeType);
             if (DBG) {
                 Log.i(TAG, "Spell checking results for " + text + " with suggestion limit "
@@ -324,6 +323,62 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
         }
     }
 
+    private static final class Result {
+        public final String[] mSuggestions;
+        public final boolean mHasRecommendedSuggestions;
+        public Result(final String[] gatheredSuggestions,
+                final boolean hasRecommendedSuggestions) {
+            mSuggestions = gatheredSuggestions;
+            mHasRecommendedSuggestions = hasRecommendedSuggestions;
+        }
+    }
+
+    private static Result getResult(final int capitalizeType, final Locale locale,
+            final int suggestionsLimit, final float recommendedThreshold, final String originalText,
+            final SuggestionResults suggestionResults) {
+        if (suggestionResults.isEmpty() || suggestionsLimit <= 0) {
+            return new Result(null /* gatheredSuggestions */,
+                    false /* hasRecommendedSuggestions */);
+        }
+        if (DBG) {
+            for (final SuggestedWordInfo suggestedWordInfo : suggestionResults) {
+                Log.i(TAG, "" + suggestedWordInfo.mScore + " " + suggestedWordInfo.mWord);
+            }
+        }
+        final ArrayList<String> suggestions = new ArrayList<>();
+        for (final SuggestedWordInfo suggestedWordInfo : suggestionResults) {
+            final String suggestion;
+            if (StringUtils.CAPITALIZE_ALL == capitalizeType) {
+                suggestion = suggestedWordInfo.mWord.toUpperCase(locale);
+            } else if (StringUtils.CAPITALIZE_FIRST == capitalizeType) {
+                suggestion = StringUtils.capitalizeFirstCodePoint(
+                        suggestedWordInfo.mWord, locale);
+            } else {
+                suggestion = suggestedWordInfo.mWord;
+            }
+            suggestions.add(suggestion);
+        }
+        StringUtils.removeDupes(suggestions);
+        // This returns a String[], while toArray() returns an Object[] which cannot be cast
+        // into a String[].
+        final String[] gatheredSuggestions =
+                suggestions.subList(0, Math.min(suggestions.size(), suggestionsLimit))
+                        .toArray(EMPTY_STRING_ARRAY);
+
+        final int bestScore = suggestionResults.first().mScore;
+        final String bestSuggestion = suggestions.get(0);
+        final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore(
+                originalText, bestSuggestion.toString(), bestScore);
+        final boolean hasRecommendedSuggestions = (normalizedScore > recommendedThreshold);
+        if (DBG) {
+            Log.i(TAG, "Best suggestion : " + bestSuggestion + ", score " + bestScore);
+            Log.i(TAG, "Normalized score = " + normalizedScore
+                    + " (threshold " + recommendedThreshold
+                    + ") => hasRecommendedSuggestions = " + hasRecommendedSuggestions);
+        }
+        return new Result(gatheredSuggestions, hasRecommendedSuggestions);
+    }
+
     /*
      * The spell checker acts on its own behalf. That is needed, in particular, to be able to
      * access the dictionary files, which the provider restricts to the identity of Latin IME.