diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index 3979fb53e..1a4f90195 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -22,6 +22,7 @@ import java.util.List; 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 @@ public abstract class KeyDetector { * * @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 @@ public abstract class KeyDetector { * @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 keys = keyboard.getKeys(); if (keys == null || keys.size() == 0) return 0; final HashMap histogram = new HashMap(); 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 2648ff3d4..9b98f2878 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -288,12 +288,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha 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 ffb8d6410..b6eab1f3b 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java @@ -21,6 +21,7 @@ import com.android.inputmethod.latin.SubtypeSwitcher; 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.PorterDuff; 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 @@ public class LatinKeyboard extends Keyboard { 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 @@ public class LatinKeyboard extends Keyboard { 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 @@ public class LatinKeyboard extends Keyboard { 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 @@ public class LatinKeyboard extends Keyboard { 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 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 @@ public class LatinKeyboard extends Keyboard { 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 @@ public class LatinKeyboard extends Keyboard { } } - 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 f04991eb7..a8750d378 100644 --- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java @@ -35,24 +35,24 @@ public class MiniKeyboardKeyDetector extends KeyDetector { } @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 0920da2cb..c3fd1984b 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 a7e95a080..ff7e2b88a 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -118,8 +118,7 @@ public class BinaryDictionary extends Dictionary { 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 @@ public class BinaryDictionary extends Dictionary { @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 @@ public class BinaryDictionary extends Dictionary { } @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 @@ public class BinaryDictionary extends Dictionary { 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 74933595c..56f0cc503 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -61,14 +61,9 @@ public abstract class Dictionary { * 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 @@ public abstract class Dictionary { * @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 0fc86c335..b10e7a61e 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -37,7 +37,6 @@ public class ExpandableDictionary extends Dictionary { 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 @@ public class ExpandableDictionary extends Dictionary { } @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 @@ public class ExpandableDictionary extends Dictionary { } 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 @@ public class ExpandableDictionary extends Dictionary { 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 @@ public class ExpandableDictionary extends Dictionary { @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 @@ public class ExpandableDictionary extends Dictionary { } } - 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 @@ public class ExpandableDictionary extends Dictionary { * 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 cb1ff41dd..648c1bab8 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1500,8 +1500,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } public void updateSuggestions() { - mKeyboardSwitcher.setPreferredLetters(null); - // Check if we have a suggestion engine attached. if ((mSuggest == null || !isSuggestionsRequested()) && !mVoiceConnector.isVoiceInputHighlighted()) { @@ -1520,7 +1518,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } 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 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen 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 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen 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 c9e57d0a5..6466f7980 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -87,12 +87,6 @@ public class Suggest implements Dictionary.WordCallback { 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 mSuggestions = new ArrayList(); ArrayList mBigramSuggestions = new ArrayList(); private ArrayList mStringPool = new ArrayList(); @@ -216,7 +210,6 @@ public class Suggest implements Dictionary.WordCallback { 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 @@ public class Suggest implements Dictionary.WordCallback { 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 @@ public class Suggest implements Dictionary.WordCallback { // 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 @@ public class Suggest implements Dictionary.WordCallback { 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 class Suggest implements Dictionary.WordCallback { } } - public int[] getNextLettersFrequencies() { - return mNextLettersFrequencies; - } - private void removeDupes() { final ArrayList 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 db5d9244f..c06bd736e 100644 --- a/java/src/com/android/inputmethod/latin/UserDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserDictionary.java @@ -126,9 +126,8 @@ public class UserDictionary extends ExpandableDictionary { } @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 2e415b771..e003dcd5b 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 25580f4b1..4660103b1 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -123,26 +123,20 @@ static jint latinime_BinaryDictionary_open(JNIEnv *env, jobject object, } 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 void latinime_BinaryDictionary_close(JNIEnv *env, jobject object, jint di 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 c1eaf0df2..7fa7e35e0 100644 --- a/native/src/defines.h +++ b/native/src/defines.h @@ -151,6 +151,9 @@ static void prof_out(void) { #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 cef1cf9eb..941bd191a 100644 --- a/native/src/dictionary.h +++ b/native/src/dictionary.h @@ -27,10 +27,8 @@ class Dictionary { 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 dfbe8228e..3d5683ed9 100644 --- a/native/src/unigram_dictionary.cpp +++ b/native/src/unigram_dictionary.cpp @@ -32,7 +32,7 @@ namespace latinime { 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(const unsigned char *dict, int typedLetterM 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 @@ int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short 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 @@ int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short 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 90c98149b..43aafc69d 100644 --- a/native/src/unigram_dictionary.h +++ b/native/src/unigram_dictionary.h @@ -32,8 +32,7 @@ class UnigramDictionary { 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 @@ private: 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 a6fb6e1e1..46e5a2454 100644 --- a/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java +++ b/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java @@ -61,7 +61,7 @@ public class UserBigramSuggestHelper extends SuggestHelper { 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++) {