diff options
Diffstat (limited to 'java/src')
5 files changed, 124 insertions, 43 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index f77155ee3..9e4c1ea79 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -138,7 +138,7 @@ public class Keyboard { mProximityInfo = new ProximityInfo( params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, - mMostCommonKeyWidth, mKeys, params.mTouchPositionCorrectionXs, + mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrectionXs, params.mTouchPositionCorrectionYs, params.mTouchPositionCorrectionRadii); } diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index 210ab48a1..d35b1a939 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -16,6 +16,9 @@ package com.android.inputmethod.keyboard; +import android.graphics.Rect; + +import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo; @@ -27,9 +30,9 @@ public class ProximityInfo { public static final int MAX_PROXIMITY_CHARS_SIZE = 16; /** Number of key widths from current touch point to search for nearest keys. */ private static float SEARCH_DISTANCE = 1.2f; - private static final int UNKNOWN_THEME = -1; private static final int[] EMPTY_INT_ARRAY = new int[0]; + private final int mKeyHeight; private final int mGridWidth; private final int mGridHeight; private final int mGridSize; @@ -45,8 +48,8 @@ public class ProximityInfo { private final float[] mTouchPositionCorrectionRadii; ProximityInfo(int gridWidth, int gridHeight, int minWidth, int height, int keyWidth, - List<Key> keys, float[] touchPositionCorrectionXs, float[] touchPositionCorrectionYs, - float[] touchPositionCorrectionRadii) { + int keyHeight, List<Key> keys, float[] touchPositionCorrectionXs, + float[] touchPositionCorrectionYs, float[] touchPositionCorrectionRadii) { mGridWidth = gridWidth; mGridHeight = gridHeight; mGridSize = mGridWidth * mGridHeight; @@ -54,6 +57,7 @@ public class ProximityInfo { mCellHeight = (height + mGridHeight - 1) / mGridHeight; mKeyboardMinWidth = minWidth; mKeyboardHeight = height; + mKeyHeight = keyHeight; mTouchPositionCorrectionXs = touchPositionCorrectionXs; mTouchPositionCorrectionYs = touchPositionCorrectionYs; mTouchPositionCorrectionRadii = touchPositionCorrectionRadii; @@ -66,7 +70,7 @@ public class ProximityInfo { } public static ProximityInfo createDummyProximityInfo() { - return new ProximityInfo(1, 1, 1, 1, 1, Collections.<Key>emptyList(), null, null, null); + return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.<Key>emptyList(), null, null, null); } public static ProximityInfo createSpellCheckerProximityInfo() { @@ -75,7 +79,7 @@ public class ProximityInfo { spellCheckerProximityInfo.setProximityInfoNative( SpellCheckerProximityInfo.ROW_SIZE, 480, 300, 10, 3, SpellCheckerProximityInfo.PROXIMITY, - 0, null, null, null, null, null, UNKNOWN_THEME); + 0, null, null, null, null, null, null, null, null); return spellCheckerProximityInfo; } @@ -86,7 +90,8 @@ public class ProximityInfo { private native int setProximityInfoNative(int maxProximityCharsSize, int displayWidth, int displayHeight, int gridWidth, int gridHeight, int[] proximityCharsArray, int keyCount, int[] keyXCoordinates, int[] keyYCoordinates, - int[] keyWidths, int[] keyHeights, int[] keyCharCodes, int themeId); + int[] keyWidths, int[] keyHeights, int[] keyCharCodes, + float[] sweetSpotCenterX, float[] sweetSpotCenterY, float[] sweetSpotRadii); private native void releaseProximityInfoNative(int nativeProximityInfo); private final void setProximityInfo(int[][] gridNeighborKeyIndexes, int keyboardWidth, @@ -101,12 +106,11 @@ public class ProximityInfo { } } final int keyCount = keys.size(); - int[] keyXCoordinates = new int[keyCount]; - int[] keyYCoordinates = new int[keyCount]; - int[] keyWidths = new int[keyCount]; - int[] keyHeights = new int[keyCount]; - int[] keyCharCodes = new int[keyCount]; - final int themeId = 5; // TODO: Use real theme id. + final int[] keyXCoordinates = new int[keyCount]; + final int[] keyYCoordinates = new int[keyCount]; + final int[] keyWidths = new int[keyCount]; + final int[] keyHeights = new int[keyCount]; + final int[] keyCharCodes = new int[keyCount]; for (int i = 0; i < keyCount; ++i) { final Key key = keys.get(i); keyXCoordinates[i] = key.mX; @@ -115,10 +119,51 @@ public class ProximityInfo { keyHeights[i] = key.mHeight; keyCharCodes[i] = key.mCode; } + + final boolean hasTouchPositionCorrectionData = + mTouchPositionCorrectionXs != null + && mTouchPositionCorrectionYs != null + && mTouchPositionCorrectionRadii != null + && mTouchPositionCorrectionXs.length > 0 + && mTouchPositionCorrectionYs.length > 0 + && mTouchPositionCorrectionRadii.length > 0; + final float[] sweetSpotCenterXs = + hasTouchPositionCorrectionData ? new float[keyCount] : null; + final float[] sweetSpotCenterYs = + hasTouchPositionCorrectionData ? new float[keyCount] : null; + final float[] sweetSpotRadii = + hasTouchPositionCorrectionData ? new float[keyCount] : null; + if (hasTouchPositionCorrectionData) { + calculateSweetSpot(keys, sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii); + } + mNativeProximityInfo = setProximityInfoNative(MAX_PROXIMITY_CHARS_SIZE, keyboardWidth, keyboardHeight, mGridWidth, mGridHeight, proximityCharsArray, keyCount, keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes, - themeId); + sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii); + } + + private void calculateSweetSpot(List<Key> keys, float[] sweetSpotCenterXs, + float[] sweetSpotCenterYs, float[] sweetSpotRadii) { + final int keyCount = keys.size(); + for (int i = 0; i < keyCount; ++i) { + final Key key = keys.get(i); + final Rect hitBox = key.mHitBox; + final int row = hitBox.top / mKeyHeight; + if (row < mTouchPositionCorrectionRadii.length) { + final float hitBoxCenterX = (hitBox.left + hitBox.right) * 0.5f; + final float hitBoxCenterY = (hitBox.top + hitBox.bottom) * 0.5f; + final float hitBoxWidth = hitBox.right - hitBox.left; + final float hitBoxHeight = hitBox.bottom - hitBox.top; + final float x = mTouchPositionCorrectionXs[row]; + final float y = mTouchPositionCorrectionYs[row]; + final float radius = mTouchPositionCorrectionRadii[row]; + sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth; + sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight; + sweetSpotRadii[i] = radius + * (float)Math.sqrt(hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight); + } + } } public int getNativeProximityInfo() { diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 6a6a0a4ee..ab9edb110 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -61,6 +61,8 @@ public class BinaryDictionary extends Dictionary { public static final Flag FLAG_REQUIRES_GERMAN_UMLAUT_PROCESSING = new Flag(R.bool.config_require_umlaut_processing, 0x1); + public static final Flag FLAG_USE_FULL_EDIT_DISTANCE = new Flag(0x2); + // Can create a new flag from extravalue : // public static final Flag FLAG_MYFLAG = // new Flag("my_flag", 0x02); diff --git a/java/src/com/android/inputmethod/latin/Flag.java b/java/src/com/android/inputmethod/latin/Flag.java index 3cb8f7e17..4ba6c80f5 100644 --- a/java/src/com/android/inputmethod/latin/Flag.java +++ b/java/src/com/android/inputmethod/latin/Flag.java @@ -25,8 +25,9 @@ public class Flag { public final int mMask; public final int mSource; - static private final int SOURCE_CONFIG = 1; - static private final int SOURCE_EXTRAVALUE = 2; + private static final int SOURCE_CONFIG = 1; + private static final int SOURCE_EXTRAVALUE = 2; + private static final int SOURCE_PARAM = 3; public Flag(int resourceId, int mask) { mName = null; @@ -42,6 +43,13 @@ public class Flag { mMask = mask; } + public Flag(int mask) { + mName = null; + mResource = 0; + mSource = SOURCE_PARAM; + mMask = mask; + } + // If context/switcher are null, set all related flags in flagArray to on. public static int initFlags(Flag[] flagArray, Context context, SubtypeSwitcher switcher) { int flags = 0; @@ -57,6 +65,9 @@ public class Flag { switcher.currentSubtypeContainsExtraValueKey(entry.mName)) flags |= entry.mMask; break; + case Flag.SOURCE_PARAM: + flags |= entry.mMask; + break; } } return flags; diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 37145b257..1d5986ef9 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -70,11 +70,17 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private Map<String, Dictionary> mUserDictionaries = Collections.synchronizedMap(new TreeMap<String, Dictionary>()); - private double mTypoThreshold; + // The threshold for a candidate to be offered as a suggestion. + private double mSuggestionThreshold; + // The threshold for a suggestion to be considered "likely". + private double mLikelyThreshold; @Override public void onCreate() { super.onCreate(); - mTypoThreshold = Double.parseDouble(getString(R.string.spellchecker_typo_threshold_value)); + mSuggestionThreshold = + Double.parseDouble(getString(R.string.spellchecker_suggestion_threshold_value)); + mLikelyThreshold = + Double.parseDouble(getString(R.string.spellchecker_likely_threshold_value)); } @Override @@ -96,7 +102,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private final ArrayList<CharSequence> mSuggestions; private final int[] mScores; private final String mOriginalText; - private final double mThreshold; + private final double mSuggestionThreshold; + private final double mLikelyThreshold; private final int mMaxLength; private int mLength = 0; @@ -105,10 +112,11 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private String mBestSuggestion = null; private int mBestScore = Integer.MIN_VALUE; // As small as possible - SuggestionsGatherer(final String originalText, final double threshold, - final int maxLength) { + SuggestionsGatherer(final String originalText, final double suggestionThreshold, + final double likelyThreshold, final int maxLength) { mOriginalText = originalText; - mThreshold = threshold; + mSuggestionThreshold = suggestionThreshold; + mLikelyThreshold = likelyThreshold; mMaxLength = maxLength; mSuggestions = new ArrayList<CharSequence>(maxLength + 1); mScores = new int[mMaxLength]; @@ -122,28 +130,42 @@ public class AndroidSpellCheckerService extends SpellCheckerService { // if it doesn't. See documentation for binarySearch. final int insertIndex = positionIndex >= 0 ? positionIndex : -positionIndex - 1; + if (insertIndex == 0 && mLength >= mMaxLength) { + // In the future, we may want to keep track of the best suggestion score even if + // we are asked for 0 suggestions. In this case, we can use the following + // (tested) code to keep it: + // If the maxLength is 0 (should never be less, but if it is, it's treated as 0) + // then we need to keep track of the best suggestion in mBestScore and + // mBestSuggestion. This is so that we know whether the best suggestion makes + // the score cutoff, since we need to know that to return a meaningful + // looksLikeTypo. + // if (0 >= mMaxLength) { + // if (score > mBestScore) { + // mBestScore = score; + // mBestSuggestion = new String(word, wordOffset, wordLength); + // } + // } + return true; + } + + // Compute the normalized score and skip this word if it's normalized score does not + // make the threshold. + final String wordString = new String(word, wordOffset, wordLength); + final double normalizedScore = + Utils.calcNormalizedScore(mOriginalText, wordString, score); + if (normalizedScore < mSuggestionThreshold) { + if (DBG) Log.i(TAG, wordString + " does not make the score threshold"); + return true; + } + if (mLength < mMaxLength) { final int copyLen = mLength - insertIndex; ++mLength; System.arraycopy(mScores, insertIndex, mScores, insertIndex + 1, copyLen); - mSuggestions.add(insertIndex, new String(word, wordOffset, wordLength)); + mSuggestions.add(insertIndex, wordString); } else { - if (insertIndex == 0) { - // If the maxLength is 0 (should never be less, but if it is, it's treated as 0) - // then we need to keep track of the best suggestion in mBestScore and - // mBestSuggestion. This is so that we know whether the best suggestion makes - // the score cutoff, since we need to know that to return a meaningful - // looksLikeTypo. - if (0 >= mMaxLength) { - if (score > mBestScore) { - mBestScore = score; - mBestSuggestion = new String(word, wordOffset, wordLength); - } - } - return true; - } System.arraycopy(mScores, 1, mScores, 0, insertIndex); - mSuggestions.add(insertIndex, new String(word, wordOffset, wordLength)); + mSuggestions.add(insertIndex, wordString); mSuggestions.remove(0); } mScores[insertIndex] = score; @@ -165,7 +187,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService { gatheredSuggestions = EMPTY_STRING_ARRAY; final double normalizedScore = Utils.calcNormalizedScore(mOriginalText, mBestSuggestion, mBestScore); - hasLikelySuggestions = (normalizedScore > mThreshold); + hasLikelySuggestions = (normalizedScore > mLikelyThreshold); } } else { if (DBG) { @@ -199,10 +221,11 @@ public class AndroidSpellCheckerService extends SpellCheckerService { final CharSequence bestSuggestion = mSuggestions.get(0); final double normalizedScore = Utils.calcNormalizedScore(mOriginalText, bestSuggestion, bestScore); - hasLikelySuggestions = (normalizedScore > mThreshold); + hasLikelySuggestions = (normalizedScore > mLikelyThreshold); if (DBG) { Log.i(TAG, "Best suggestion : " + bestSuggestion + ", score " + bestScore); - Log.i(TAG, "Normalized score = " + normalizedScore + " (threshold " + mThreshold + Log.i(TAG, "Normalized score = " + normalizedScore + + " (threshold " + mLikelyThreshold + ") => hasLikelySuggestions = " + hasLikelySuggestions); } } @@ -354,8 +377,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService { } // TODO: Don't gather suggestions if the limit is <= 0 unless necessary - final SuggestionsGatherer suggestionsGatherer = - new SuggestionsGatherer(text, mService.mTypoThreshold, suggestionsLimit); + final SuggestionsGatherer suggestionsGatherer = new SuggestionsGatherer(text, + mService.mSuggestionThreshold, mService.mLikelyThreshold, suggestionsLimit); final WordComposer composer = new WordComposer(); final int length = text.length(); for (int i = 0; i < length; ++i) { |