Remove next letters frequency handling

Bug: 3428942
Change-Id: Id62f467ce4e50c60a56d59bf96770e799a4659e2
diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
index 3979fb5..1a4f901 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
@@ -22,6 +22,7 @@
 
 public abstract class KeyDetector {
     public static final int NOT_A_KEY = -1;
+    public static final int NOT_A_CODE = -1;
 
     protected Keyboard mKeyboard;
 
@@ -105,10 +106,10 @@
      *
      * @param x The x-coordinate of a touch point
      * @param y The y-coordinate of a touch point
-     * @param allKeys All nearby key indices are returned in this array
+     * @param allCodes All nearby key code except functional key are returned in this array
      * @return The nearest key index
      */
-    abstract public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys);
+    abstract public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes);
 
     /**
      * Compute the most common key width in order to use it as proximity key detection threshold.
@@ -116,14 +117,14 @@
      * @param keyboard The keyboard to compute the most common key width
      * @return The most common key width in the keyboard
      */
-    public static int getMostCommonKeyWidth(Keyboard keyboard) {
+    public static int getMostCommonKeyWidth(final Keyboard keyboard) {
         if (keyboard == null) return 0;
         final List<Key> keys = keyboard.getKeys();
         if (keys == null || keys.size() == 0) return 0;
         final HashMap<Integer, Integer> histogram = new HashMap<Integer, Integer>();
         int maxCount = 0;
         int mostCommonWidth = 0;
-        for (Key key : keys) {
+        for (final Key key : keys) {
             final Integer width = key.mWidth + key.mGap;
             Integer count = histogram.get(width);
             if (count == null)
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 2648ff3..9b98f28 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -288,12 +288,6 @@
         return null;
     }
 
-    public void setPreferredLetters(int[] frequencies) {
-        LatinKeyboard latinKeyboard = getLatinKeyboard();
-        if (latinKeyboard != null)
-            latinKeyboard.setPreferredLetters(frequencies);
-    }
-
     public void keyReleased() {
         LatinKeyboard latinKeyboard = getLatinKeyboard();
         if (latinKeyboard != null)
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
index ffb8d64..b6eab1f 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
@@ -21,6 +21,7 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -31,17 +32,12 @@
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.util.Log;
 
 import java.util.List;
 import java.util.Locale;
 
 // TODO: We should remove this class
 public class LatinKeyboard extends Keyboard {
-
-    private static final boolean DEBUG_PREFERRED_LETTER = false;
-    private static final String TAG = "LatinKeyboard";
-
     public static final int OPACITY_FULLY_OPAQUE = 255;
     private static final int SPACE_LED_LENGTH_PERCENT = 80;
 
@@ -69,15 +65,7 @@
     private final Drawable mEnabledShortcutIcon;
     private final Drawable mDisabledShortcutIcon;
 
-    private int[] mPrefLetterFrequencies;
-    private int mPrefLetter;
-    private int mPrefLetterX;
-    private int mPrefLetterY;
-    private int mPrefDistance;
-
     private static final float SPACEBAR_DRAG_THRESHOLD = 0.8f;
-    private static final float OVERLAP_PERCENTAGE_LOW_PROB = 0.70f;
-    private static final float OVERLAP_PERCENTAGE_HIGH_PROB = 0.85f;
     // Minimum width of space key preview (proportional to keyboard width)
     private static final float SPACEBAR_POPUP_MIN_RATIO = 0.4f;
     // Height in space key the language name will be drawn. (proportional to space key height)
@@ -265,7 +253,7 @@
             final boolean allowVariableTextSize = true;
             final String language = layoutSpacebar(paint, subtypeSwitcher.getInputLocale(),
                     mButtonArrowLeftIcon, mButtonArrowRightIcon, width, height,
-                    getTextSizeFromTheme(textStyle, defaultTextSize),
+                    getTextSizeFromTheme(mContext.getTheme(), textStyle, defaultTextSize),
                     allowVariableTextSize);
 
             // Draw language text with shadow
@@ -334,18 +322,9 @@
         return mSpaceDragLastDiff > 0 ? 1 : -1;
     }
 
-    public void setPreferredLetters(int[] frequencies) {
-        mPrefLetterFrequencies = frequencies;
-        mPrefLetter = 0;
-    }
-
     public void keyReleased() {
         mCurrentlyInSpace = false;
         mSpaceDragLastDiff = 0;
-        mPrefLetter = 0;
-        mPrefLetterX = 0;
-        mPrefLetterY = 0;
-        mPrefDistance = Integer.MAX_VALUE;
         if (mSpaceKey != null) {
             updateLocaleDrag(Integer.MAX_VALUE);
         }
@@ -381,80 +360,6 @@
                     return isOnSpace;
                 }
             }
-        } else if (mPrefLetterFrequencies != null) {
-            // New coordinate? Reset
-            if (mPrefLetterX != x || mPrefLetterY != y) {
-                mPrefLetter = 0;
-                mPrefDistance = Integer.MAX_VALUE;
-            }
-            // Handle preferred next letter
-            final int[] pref = mPrefLetterFrequencies;
-            if (mPrefLetter > 0) {
-                if (DEBUG_PREFERRED_LETTER) {
-                    if (mPrefLetter == code && !key.isOnKey(x, y)) {
-                        Log.d(TAG, "CORRECTED !!!!!!");
-                    }
-                }
-                return mPrefLetter == code;
-            } else {
-                final boolean isOnKey = key.isOnKey(x, y);
-                int[] nearby = getNearestKeys(x, y);
-                List<Key> nearbyKeys = getKeys();
-                if (isOnKey) {
-                    // If it's a preferred letter
-                    if (inPrefList(code, pref)) {
-                        // Check if its frequency is much lower than a nearby key
-                        mPrefLetter = code;
-                        mPrefLetterX = x;
-                        mPrefLetterY = y;
-                        for (int i = 0; i < nearby.length; i++) {
-                            Key k = nearbyKeys.get(nearby[i]);
-                            if (k != key && inPrefList(k.mCode, pref)) {
-                                final int dist = distanceFrom(k, x, y);
-                                if (dist < (int) (k.mWidth * OVERLAP_PERCENTAGE_LOW_PROB) &&
-                                        (pref[k.mCode] > pref[mPrefLetter] * 3))  {
-                                    mPrefLetter = k.mCode;
-                                    mPrefDistance = dist;
-                                    if (DEBUG_PREFERRED_LETTER) {
-                                        Log.d(TAG, "CORRECTED ALTHOUGH PREFERRED !!!!!!");
-                                    }
-                                    break;
-                                }
-                            }
-                        }
-
-                        return mPrefLetter == code;
-                    }
-                }
-
-                // Get the surrounding keys and intersect with the preferred list
-                // For all in the intersection
-                //   if distance from touch point is within a reasonable distance
-                //       make this the pref letter
-                // If no pref letter
-                //   return inside;
-                // else return thiskey == prefletter;
-
-                for (int i = 0; i < nearby.length; i++) {
-                    Key k = nearbyKeys.get(nearby[i]);
-                    if (inPrefList(k.mCode, pref)) {
-                        final int dist = distanceFrom(k, x, y);
-                        if (dist < (int) (k.mWidth * OVERLAP_PERCENTAGE_HIGH_PROB)
-                                && dist < mPrefDistance)  {
-                            mPrefLetter = k.mCode;
-                            mPrefLetterX = x;
-                            mPrefLetterY = y;
-                            mPrefDistance = dist;
-                        }
-                    }
-                }
-                // Didn't find any
-                if (mPrefLetter == 0) {
-                    return isOnKey;
-                } else {
-                    return mPrefLetter == code;
-                }
-            }
         }
 
         // Lock into the spacebar
@@ -463,19 +368,6 @@
         return key.isOnKey(x, y);
     }
 
-    private boolean inPrefList(int code, int[] pref) {
-        if (code < pref.length && code >= 0) return pref[code] > 0;
-        return false;
-    }
-
-    private int distanceFrom(Key k, int x, int y) {
-        if (y > k.mY && y < k.mY + k.mHeight) {
-            return Math.abs(k.mX + k.mWidth / 2 - x);
-        } else {
-            return Integer.MAX_VALUE;
-        }
-    }
-
     @Override
     public int[] getNearestKeys(int x, int y) {
         if (mCurrentlyInSpace) {
@@ -487,8 +379,8 @@
         }
     }
 
-    private int getTextSizeFromTheme(int style, int defValue) {
-        TypedArray array = mContext.getTheme().obtainStyledAttributes(
+    private static int getTextSizeFromTheme(Theme theme, int style, int defValue) {
+        TypedArray array = theme.obtainStyledAttributes(
                 style, new int[] { android.R.attr.textSize });
         int textSize = array.getDimensionPixelSize(array.getResourceId(0, 0), defValue);
         return textSize;
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java
index f04991e..a8750d3 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java
@@ -35,24 +35,24 @@
     }
 
     @Override
-    public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) {
+    public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) {
         final Key[] keys = getKeys();
         final int touchX = getTouchX(x);
         final int touchY = getTouchY(y);
 
-        int closestKeyIndex = NOT_A_KEY;
-        int closestKeyDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
+        int nearestIndex = NOT_A_KEY;
+        int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
         final int keyCount = keys.length;
         for (int index = 0; index < keyCount; index++) {
             final int dist = keys[index].squaredDistanceToEdge(touchX, touchY);
-            if (dist < closestKeyDist) {
-                closestKeyIndex = index;
-                closestKeyDist = dist;
+            if (dist < nearestDist) {
+                nearestIndex = index;
+                nearestDist = dist;
             }
         }
 
-        if (allKeys != null && closestKeyIndex != NOT_A_KEY)
-            allKeys[0] = keys[closestKeyIndex].mCode;
-        return closestKeyIndex;
+        if (allCodes != null && nearestIndex != NOT_A_KEY)
+            allCodes[0] = keys[nearestIndex].mCode;
+        return nearestIndex;
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java b/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java
index 0920da2..c3fd198 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java
@@ -16,49 +16,106 @@
 
 package com.android.inputmethod.keyboard;
 
+import android.util.Log;
+
 import java.util.Arrays;
 
 public class ProximityKeyDetector extends KeyDetector {
+    private static final String TAG = ProximityKeyDetector.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
     private static final int MAX_NEARBY_KEYS = 12;
 
     // working area
-    private int[] mDistances = new int[MAX_NEARBY_KEYS];
+    private final int[] mDistances = new int[MAX_NEARBY_KEYS];
+    private final int[] mIndices = new int[MAX_NEARBY_KEYS];
 
     @Override
     protected int getMaxNearbyKeys() {
         return MAX_NEARBY_KEYS;
     }
 
+    private void initializeNearbyKeys() {
+        Arrays.fill(mDistances, Integer.MAX_VALUE);
+        Arrays.fill(mIndices, NOT_A_KEY);
+    }
+
+    /**
+     * Insert the key into nearby keys buffer and sort nearby keys by ascending order of distance.
+     *
+     * @param keyIndex index of the key.
+     * @param distance distance between the key's edge and user touched point.
+     * @return order of the key in the nearby buffer, 0 if it is the nearest key.
+     */
+    private int sortNearbyKeys(int keyIndex, int distance) {
+        final int[] distances = mDistances;
+        final int[] indices = mIndices;
+        for (int insertPos = 0; insertPos < distances.length; insertPos++) {
+            if (distance < distances[insertPos]) {
+                final int nextPos = insertPos + 1;
+                if (nextPos < distances.length) {
+                    System.arraycopy(distances, insertPos, distances, nextPos,
+                            distances.length - nextPos);
+                    System.arraycopy(indices, insertPos, indices, nextPos,
+                            indices.length - nextPos);
+                }
+                distances[insertPos] = distance;
+                indices[insertPos] = keyIndex;
+                return insertPos;
+            }
+        }
+        return distances.length;
+    }
+
+    private void getNearbyKeyCodes(final int[] allCodes) {
+        final Key[] keys = getKeys();
+        final int[] indices = mIndices;
+
+        // allCodes[0] should always have the key code even if it is a non-letter key.
+        if (indices[0] == NOT_A_KEY) {
+            allCodes[0] = NOT_A_CODE;
+            return;
+        }
+
+        int numCodes = 0;
+        for (int j = 0; j < indices.length && numCodes < allCodes.length; j++) {
+            final int index = indices[j];
+            if (index == NOT_A_KEY)
+                break;
+            final int code = keys[index].mCode;
+            // filter out a non-letter key from nearby keys
+            if (code < Keyboard.CODE_SPACE)
+                continue;
+            allCodes[numCodes++] = code;
+        }
+    }
+
     @Override
-    public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) {
+    public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) {
         final Key[] keys = getKeys();
         final int touchX = getTouchX(x);
         final int touchY = getTouchY(y);
 
+        initializeNearbyKeys();
         int primaryIndex = NOT_A_KEY;
-        final int[] distances = mDistances;
-        Arrays.fill(distances, Integer.MAX_VALUE);
         for (final int index : mKeyboard.getNearestKeys(touchX, touchY)) {
             final Key key = keys[index];
             final boolean isInside = key.isInside(touchX, touchY);
-            if (isInside)
-                primaryIndex = index;
-            final int dist = key.squaredDistanceToEdge(touchX, touchY);
-            if (isInside || (mProximityCorrectOn && dist < mProximityThresholdSquare)) {
-                if (allKeys == null) continue;
-                // Find insertion point
-                for (int j = 0; j < distances.length; j++) {
-                    if (distances[j] > dist) {
-                        final int nextPos = j + 1;
-                        System.arraycopy(distances, j, distances, nextPos,
-                                distances.length - nextPos);
-                        System.arraycopy(allKeys, j, allKeys, nextPos,
-                                allKeys.length - nextPos);
-                        distances[j] = dist;
-                        allKeys[j] = key.mCode;
-                        break;
-                    }
-                }
+            final int distance = key.squaredDistanceToEdge(touchX, touchY);
+            if (isInside || (mProximityCorrectOn && distance < mProximityThresholdSquare)) {
+                final int insertedPosition = sortNearbyKeys(index, distance);
+                if (insertedPosition == 0 && isInside)
+                    primaryIndex = index;
+            }
+        }
+
+        if (allCodes != null && allCodes.length > 0) {
+            getNearbyKeyCodes(allCodes);
+            if (DEBUG) {
+                Log.d(TAG, "x=" + x + " y=" + y
+                        + " primary="
+                        + (primaryIndex == NOT_A_KEY ? "none" : keys[primaryIndex].mCode)
+                        + " codes=" + Arrays.toString(allCodes));
             }
         }
 
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index a7e95a0..ff7e2b8 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -118,8 +118,7 @@
     private native void closeNative(int dict);
     private native boolean isValidWordNative(int nativeData, char[] word, int wordLength);
     private native int getSuggestionsNative(int dict, int[] inputCodes, int codesSize,
-            char[] outputChars, int[] frequencies,
-            int[] nextLettersFrequencies, int nextLettersSize);
+            char[] outputChars, int[] frequencies);
     private native int getBigramsNative(int dict, char[] prevWord, int prevWordLength,
             int[] inputCodes, int inputCodesLength, char[] outputChars, int[] frequencies,
             int maxWordLength, int maxBigrams, int maxAlternatives);
@@ -133,7 +132,7 @@
 
     @Override
     public void getBigrams(final WordComposer codes, final CharSequence previousWord,
-            final WordCallback callback, int[] nextLettersFrequencies) {
+            final WordCallback callback) {
         if (mNativeDict == 0) return;
 
         char[] chars = previousWord.toString().toCharArray();
@@ -165,15 +164,14 @@
     }
 
     @Override
-    public void getWords(final WordComposer codes, final WordCallback callback,
-            int[] nextLettersFrequencies) {
+    public void getWords(final WordComposer codes, final WordCallback callback) {
         if (mNativeDict == 0) return;
 
         final int codesSize = codes.size();
         // Won't deal with really long words.
         if (codesSize > MAX_WORD_LENGTH - 1) return;
 
-        Arrays.fill(mInputCodes, -1);
+        Arrays.fill(mInputCodes, WordComposer.NOT_A_CODE);
         for (int i = 0; i < codesSize; i++) {
             int[] alternatives = codes.getCodesAt(i);
             System.arraycopy(alternatives, 0, mInputCodes, i * MAX_ALTERNATIVES,
@@ -183,8 +181,7 @@
         Arrays.fill(mFrequencies, 0);
 
         int count = getSuggestionsNative(mNativeDict, mInputCodes, codesSize, mOutputChars,
-                mFrequencies, nextLettersFrequencies,
-                nextLettersFrequencies != null ? nextLettersFrequencies.length : 0);
+                mFrequencies);
 
         for (int j = 0; j < count; ++j) {
             if (mFrequencies[j] < 1) break;
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 7493359..56f0cc5 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -61,14 +61,9 @@
      * words are added through the callback object.
      * @param composer the key sequence to match
      * @param callback the callback object to send matched words to as possible candidates
-     * @param nextLettersFrequencies array of frequencies of next letters that could follow the
-     *        word so far. For instance, "bracke" can be followed by "t", so array['t'] will have
-     *        a non-zero value on returning from this method. 
-     *        Pass in null if you don't want the dictionary to look up next letters.
      * @see WordCallback#addWord(char[], int, int)
      */
-    abstract public void getWords(final WordComposer composer, final WordCallback callback,
-            int[] nextLettersFrequencies);
+    abstract public void getWords(final WordComposer composer, final WordCallback callback);
 
     /**
      * Searches for pairs in the bigram dictionary that matches the previous word and all the
@@ -76,13 +71,9 @@
      * @param composer the key sequence to match
      * @param previousWord the word before
      * @param callback the callback object to send possible word following previous word
-     * @param nextLettersFrequencies array of frequencies of next letters that could follow the
-     *        word so far. For instance, "bracke" can be followed by "t", so array['t'] will have
-     *        a non-zero value on returning from this method.
-     *        Pass in null if you don't want the dictionary to look up next letters.
      */
     public void getBigrams(final WordComposer composer, final CharSequence previousWord,
-            final WordCallback callback, int[] nextLettersFrequencies) {
+            final WordCallback callback) {
         // empty base implementation
     }
 
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index 0fc86c3..b10e7a6 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -37,7 +37,6 @@
     private int mDicTypeId;
     private int mMaxDepth;
     private int mInputLength;
-    private int[] mNextLettersFrequencies;
     private StringBuilder sb = new StringBuilder(MAX_WORD_LENGTH);
 
     private static final char QUOTE = '\'';
@@ -191,8 +190,7 @@
     }
 
     @Override
-    public void getWords(final WordComposer codes, final WordCallback callback,
-            int[] nextLettersFrequencies) {
+    public void getWords(final WordComposer codes, final WordCallback callback) {
         synchronized (mUpdatingLock) {
             // If we need to update, start off a background task
             if (mRequiresReload) startDictionaryLoadingTaskLocked();
@@ -201,7 +199,6 @@
         }
 
         mInputLength = codes.size();
-        mNextLettersFrequencies = nextLettersFrequencies;
         if (mCodes.length < mInputLength) mCodes = new int[mInputLength][];
         // Cache the codes so that we don't have to lookup an array list
         for (int i = 0; i < mInputLength; i++) {
@@ -282,11 +279,6 @@
                                 DataType.UNIGRAM)) {
                         return;
                     }
-                    // Add to frequency of next letters for predictive correction
-                    if (mNextLettersFrequencies != null && depth >= inputIndex && skipPos < 0
-                            && mNextLettersFrequencies.length > word[inputIndex]) {
-                        mNextLettersFrequencies[word[inputIndex]]++;
-                    }
                 }
                 if (children != null) {
                     getWordsRec(children, codes, word, depth + 1, completion, snr, inputIndex,
@@ -427,7 +419,7 @@
 
     @Override
     public void getBigrams(final WordComposer codes, final CharSequence previousWord,
-            final WordCallback callback, int[] nextLettersFrequencies) {
+            final WordCallback callback) {
         if (!reloadDictionaryIfRequired()) {
             runReverseLookUp(previousWord, callback);
         }
@@ -516,7 +508,7 @@
         }
     }
 
-    static char toLowerCase(char c) {
+    private static char toLowerCase(char c) {
         char baseChar = c;
         if (c < BASE_CHARS.length) {
             baseChar = BASE_CHARS[c];
@@ -535,7 +527,7 @@
      * if c is not a combined character, or the base character if it
      * is combined.
      */
-    static final char BASE_CHARS[] = {
+    private static final char BASE_CHARS[] = {
         0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 
         0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 
         0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index cb1ff41..648c1ba 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1500,8 +1500,6 @@
     }
 
     public void updateSuggestions() {
-        mKeyboardSwitcher.setPreferredLetters(null);
-
         // Check if we have a suggestion engine attached.
         if ((mSuggest == null || !isSuggestionsRequested())
                 && !mVoiceConnector.isVoiceInputHighlighted()) {
@@ -1520,7 +1518,6 @@
     }
 
     private void showCorrections(WordAlternatives alternatives) {
-        mKeyboardSwitcher.setPreferredLetters(null);
         SuggestedWords.Builder builder = alternatives.getAlternatives();
         builder.setTypedWordValid(false).setHasMinimalSuggestion(false);
         showSuggestions(builder.build(), alternatives.getOriginalWord());
@@ -1533,9 +1530,6 @@
         SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
                 mKeyboardSwitcher.getInputView(), word, prevWord);
 
-        int[] nextLettersFrequencies = mSuggest.getNextLettersFrequencies();
-        mKeyboardSwitcher.setPreferredLetters(nextLettersFrequencies);
-
         boolean correctionAvailable = !mInputTypeNoAutoCorrect && !mJustReverted
                 && mSuggest.hasAutoCorrection();
         final CharSequence typedWord = word.getTypedWord();
@@ -1704,7 +1698,6 @@
         saveWordInHistory(suggestion);
         mHasValidSuggestions = false;
         mCommittedLength = suggestion.length();
-        switcher.setPreferredLetters(null);
     }
 
     /**
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index c9e57d0..6466f79 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -87,12 +87,6 @@
     private int[] mPriorities = new int[mPrefMaxSuggestions];
     private int[] mBigramPriorities = new int[PREF_MAX_BIGRAMS];
 
-    // Handle predictive correction for only the first 1280 characters for performance reasons
-    // If we support scripts that need latin characters beyond that, we should probably use some
-    // kind of a sparse array or language specific list with a mapping lookup table.
-    // 1280 is the size of the BASE_CHARS array in ExpandableDictionary, which is a basic set of
-    // latin characters.
-    private int[] mNextLettersFrequencies = new int[1280];
     private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>();
     ArrayList<CharSequence> mBigramSuggestions  = new ArrayList<CharSequence>();
     private ArrayList<CharSequence> mStringPool = new ArrayList<CharSequence>();
@@ -216,7 +210,6 @@
         mIsAllUpperCase = wordComposer.isAllUpperCase();
         collectGarbage(mSuggestions, mPrefMaxSuggestions);
         Arrays.fill(mPriorities, 0);
-        Arrays.fill(mNextLettersFrequencies, 0);
 
         // Save a lowercase version of the original word
         CharSequence typedWord = wordComposer.getTypedWord();
@@ -244,16 +237,13 @@
                     prevWordForBigram = lowerPrevWord;
                 }
                 if (mUserBigramDictionary != null) {
-                    mUserBigramDictionary.getBigrams(wordComposer, prevWordForBigram, this,
-                            mNextLettersFrequencies);
+                    mUserBigramDictionary.getBigrams(wordComposer, prevWordForBigram, this);
                 }
                 if (mContactsDictionary != null) {
-                    mContactsDictionary.getBigrams(wordComposer, prevWordForBigram, this,
-                            mNextLettersFrequencies);
+                    mContactsDictionary.getBigrams(wordComposer, prevWordForBigram, this);
                 }
                 if (mMainDict != null) {
-                    mMainDict.getBigrams(wordComposer, prevWordForBigram, this,
-                            mNextLettersFrequencies);
+                    mMainDict.getBigrams(wordComposer, prevWordForBigram, this);
                 }
                 char currentChar = wordComposer.getTypedWord().charAt(0);
                 char currentCharUpper = Character.toUpperCase(currentChar);
@@ -278,10 +268,10 @@
             // At second character typed, search the unigrams (scores being affected by bigrams)
             if (mUserDictionary != null || mContactsDictionary != null) {
                 if (mUserDictionary != null) {
-                    mUserDictionary.getWords(wordComposer, this, mNextLettersFrequencies);
+                    mUserDictionary.getWords(wordComposer, this);
                 }
                 if (mContactsDictionary != null) {
-                    mContactsDictionary.getWords(wordComposer, this, mNextLettersFrequencies);
+                    mContactsDictionary.getWords(wordComposer, this);
                 }
 
                 if (mSuggestions.size() > 0 && isValidWord(typedWord)
@@ -293,7 +283,7 @@
                     mHasAutoCorrection = true;
                 }
             }
-            if (mMainDict != null) mMainDict.getWords(wordComposer, this, mNextLettersFrequencies);
+            if (mMainDict != null) mMainDict.getWords(wordComposer, this);
             if ((mCorrectionMode == CORRECTION_FULL || mCorrectionMode == CORRECTION_FULL_BIGRAM)
                     && mSuggestions.size() > 0 && mPriorities.length > 0) {
                 // TODO: when the normalized score of the first suggestion is nearly equals to
@@ -388,10 +378,6 @@
         }
     }
 
-    public int[] getNextLettersFrequencies() {
-        return mNextLettersFrequencies;
-    }
-
     private void removeDupes() {
         final ArrayList<CharSequence> suggestions = mSuggestions;
         if (suggestions.size() < 2) return;
diff --git a/java/src/com/android/inputmethod/latin/UserDictionary.java b/java/src/com/android/inputmethod/latin/UserDictionary.java
index db5d924..c06bd73 100644
--- a/java/src/com/android/inputmethod/latin/UserDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserDictionary.java
@@ -126,9 +126,8 @@
     }
 
     @Override
-    public synchronized void getWords(final WordComposer codes, final WordCallback callback,
-            int[] nextLettersFrequencies) {
-        super.getWords(codes, callback, nextLettersFrequencies);
+    public synchronized void getWords(final WordComposer codes, final WordCallback callback) {
+        super.getWords(codes, callback);
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 2e415b7..e003dcd 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -16,12 +16,16 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.keyboard.KeyDetector;
+
 import java.util.ArrayList;
 
 /**
  * A place to store the currently composing word with information such as adjacent key codes as well
  */
 public class WordComposer {
+    public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE;
+
     /**
      * The list of unicode values for each keystroke (including surrounding keys)
      */
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 25580f4..4660103 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -123,26 +123,20 @@
 }
 
 static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jint dict,
-        jintArray inputArray, jint arraySize, jcharArray outputArray, jintArray frequencyArray,
-        jintArray nextLettersArray, jint nextLettersSize) {
+        jintArray inputArray, jint arraySize, jcharArray outputArray, jintArray frequencyArray) {
     Dictionary *dictionary = (Dictionary*)dict;
     if (!dictionary) return 0;
 
     int *frequencies = env->GetIntArrayElements(frequencyArray, NULL);
     int *inputCodes = env->GetIntArrayElements(inputArray, NULL);
     jchar *outputChars = env->GetCharArrayElements(outputArray, NULL);
-    int *nextLetters = nextLettersArray != NULL ? env->GetIntArrayElements(nextLettersArray, NULL)
-            : NULL;
 
     int count = dictionary->getSuggestions(inputCodes, arraySize, (unsigned short*) outputChars,
-            frequencies, nextLetters, nextLettersSize);
+            frequencies);
 
     env->ReleaseIntArrayElements(frequencyArray, frequencies, 0);
     env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT);
     env->ReleaseCharArrayElements(outputArray, outputChars, 0);
-    if (nextLetters) {
-        env->ReleaseIntArrayElements(nextLettersArray, nextLetters, 0);
-    }
 
     return count;
 }
@@ -209,7 +203,7 @@
 static JNINativeMethod gMethods[] = {
     {"openNative", "(Ljava/lang/String;JJIIIII)I", (void*)latinime_BinaryDictionary_open},
     {"closeNative", "(I)V", (void*)latinime_BinaryDictionary_close},
-    {"getSuggestionsNative", "(I[II[C[I[II)I", (void*)latinime_BinaryDictionary_getSuggestions},
+    {"getSuggestionsNative", "(I[II[C[I)I", (void*)latinime_BinaryDictionary_getSuggestions},
     {"isValidWordNative", "(I[CI)Z", (void*)latinime_BinaryDictionary_isValidWord},
     {"getBigramsNative", "(I[CI[II[C[IIII)I", (void*)latinime_BinaryDictionary_getBigrams}
 };
diff --git a/native/src/defines.h b/native/src/defines.h
index c1eaf0d..7fa7e35 100644
--- a/native/src/defines.h
+++ b/native/src/defines.h
@@ -151,6 +151,9 @@
 #define MIN_USER_TYPED_LENGTH_FOR_MISSING_SPACE_SUGGESTION 3
 #define MIN_USER_TYPED_LENGTH_FOR_EXCESSIVE_CHARACTER_SUGGESTION 3
 
+// The size of next letters frequency array.  Zero will disable the feature.
+#define NEXT_LETTERS_SIZE 0
+
 #define min(a,b) ((a)<(b)?(a):(b))
 
 #endif // LATINIME_DEFINES_H
diff --git a/native/src/dictionary.h b/native/src/dictionary.h
index cef1cf9..941bd19 100644
--- a/native/src/dictionary.h
+++ b/native/src/dictionary.h
@@ -27,10 +27,8 @@
 public:
     Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, int typedLetterMultipler,
             int fullWordMultiplier, int maxWordLength, int maxWords, int maxAlternatives);
-    int getSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies,
-            int *nextLetters, int nextLettersSize) {
-        return mUnigramDictionary->getSuggestions(codes, codesSize, outWords, frequencies,
-                nextLetters, nextLettersSize);
+    int getSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies) {
+        return mUnigramDictionary->getSuggestions(codes, codesSize, outWords, frequencies);
     }
 
     // TODO: Call mBigramDictionary instead of mUnigramDictionary
diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp
index dfbe822..3d5683e 100644
--- a/native/src/unigram_dictionary.cpp
+++ b/native/src/unigram_dictionary.cpp
@@ -32,7 +32,7 @@
 UnigramDictionary::UnigramDictionary(const unsigned char *dict, int typedLetterMultiplier,
         int fullWordMultiplier, int maxWordLength, int maxWords, int maxProximityChars,
         const bool isLatestDictVersion)
-    : DICT(dict), MAX_WORD_LENGTH(maxWordLength),MAX_WORDS(maxWords),
+    : DICT(dict), MAX_WORD_LENGTH(maxWordLength), MAX_WORDS(maxWords),
     MAX_PROXIMITY_CHARS(maxProximityChars), IS_LATEST_DICT_VERSION(isLatestDictVersion),
     TYPED_LETTER_MULTIPLIER(typedLetterMultiplier), FULL_WORD_MULTIPLIER(fullWordMultiplier),
     ROOT_POS(isLatestDictVersion ? DICTIONARY_HEADER_SIZE : 0) {
@@ -42,7 +42,7 @@
 UnigramDictionary::~UnigramDictionary() {}
 
 int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short *outWords,
-        int *frequencies, int *nextLetters, int nextLettersSize) {
+        int *frequencies) {
     PROF_OPEN;
     PROF_START(0);
     initSuggestions(codes, codesSize, outWords, frequencies);
@@ -52,7 +52,7 @@
     PROF_END(0);
 
     PROF_START(1);
-    getSuggestionCandidates(-1, -1, -1, nextLetters, nextLettersSize, MAX_DEPTH);
+    getSuggestionCandidates(-1, -1, -1, mNextLettersFrequency, NEXT_LETTERS_SIZE, MAX_DEPTH);
     PROF_END(1);
 
     PROF_START(2);
@@ -108,9 +108,9 @@
     if (DEBUG_DICT) {
         LOGI("Returning %d words", suggestedWordsCount);
         LOGI("Next letters: ");
-        for (int k = 0; k < nextLettersSize; k++) {
-            if (nextLetters[k] > 0) {
-                LOGI("%c = %d,", k, nextLetters[k]);
+        for (int k = 0; k < NEXT_LETTERS_SIZE; k++) {
+            if (mNextLettersFrequency[k] > 0) {
+                LOGI("%c = %d,", k, mNextLettersFrequency[k]);
             }
         }
     }
diff --git a/native/src/unigram_dictionary.h b/native/src/unigram_dictionary.h
index 90c9814..43aafc6 100644
--- a/native/src/unigram_dictionary.h
+++ b/native/src/unigram_dictionary.h
@@ -32,8 +32,7 @@
 public:
     UnigramDictionary(const unsigned char *dict, int typedLetterMultipler, int fullWordMultiplier,
             int maxWordLength, int maxWords, int maxProximityChars, const bool isLatestDictVersion);
-    int getSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies,
-            int *nextLetters, int nextLettersSize);
+    int getSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies);
     ~UnigramDictionary();
 
 private:
@@ -109,6 +108,7 @@
     int mStackInputIndex[MAX_WORD_LENGTH_INTERNAL];
     int mStackDiffs[MAX_WORD_LENGTH_INTERNAL];
     int mStackSiblingPos[MAX_WORD_LENGTH_INTERNAL];
+    int mNextLettersFrequency[NEXT_LETTERS_SIZE];
 };
 
 // ----------------------------------------------------------------------------
diff --git a/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java b/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java
index a6fb6e1..46e5a24 100644
--- a/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java
+++ b/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java
@@ -61,7 +61,7 @@
             mSuggest.getSuggestions(null, firstChar, previous);
             boolean reloading = mUserBigram.reloadDictionaryIfRequired();
             if (reloading) mUserBigram.waitForDictionaryLoading();
-            mUserBigram.getBigrams(firstChar, previous, mSuggest, null);
+            mUserBigram.getBigrams(firstChar, previous, mSuggest);
         }
 
         for (int i = 0; i < mSuggest.mBigramSuggestions.size(); i++) {