diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin/spellcheck')
-rw-r--r-- | java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java | 64 |
1 files changed, 51 insertions, 13 deletions
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index ec82f9e80..502ebb52a 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -23,6 +23,7 @@ import android.service.textservice.SpellCheckerService.Session; import android.util.Log; import android.view.textservice.SuggestionsInfo; import android.view.textservice.TextInfo; +import android.text.TextUtils; import com.android.inputmethod.compat.ArraysCompatUtils; import com.android.inputmethod.keyboard.Key; @@ -36,6 +37,7 @@ import com.android.inputmethod.latin.UserDictionary; import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.WordComposer; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Locale; @@ -50,7 +52,9 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private static final boolean DBG = false; private static final int POOL_SIZE = 2; - private final static String[] emptyArray = new String[0]; + private final static String[] EMPTY_STRING_ARRAY = new String[0]; + private final static SuggestionsInfo EMPTY_SUGGESTIONS_INFO = + new SuggestionsInfo(0, EMPTY_STRING_ARRAY); private Map<String, DictionaryPool> mDictionaryPools = Collections.synchronizedMap(new TreeMap<String, DictionaryPool>()); private Map<String, Dictionary> mUserDictionaries = @@ -63,14 +67,15 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private static class SuggestionsGatherer implements WordCallback { private final int DEFAULT_SUGGESTION_LENGTH = 16; - private final String[] mSuggestions; + private final ArrayList<CharSequence> mSuggestions; private final int[] mScores; private final int mMaxLength; private int mLength = 0; + private boolean mSeenSuggestions = false; SuggestionsGatherer(final int maxLength) { mMaxLength = maxLength; - mSuggestions = new String[mMaxLength]; + mSuggestions = new ArrayList<CharSequence>(maxLength + 1); mScores = new int[mMaxLength]; } @@ -82,30 +87,37 @@ public class AndroidSpellCheckerService extends SpellCheckerService { // if it doesn't. See documentation for binarySearch. final int insertIndex = positionIndex >= 0 ? positionIndex : -positionIndex - 1; + mSeenSuggestions = true; if (mLength < mMaxLength) { final int copyLen = mLength - insertIndex; ++mLength; System.arraycopy(mScores, insertIndex, mScores, insertIndex + 1, copyLen); - System.arraycopy(mSuggestions, insertIndex, mSuggestions, insertIndex + 1, copyLen); + mSuggestions.add(insertIndex, new String(word, wordOffset, wordLength)); } else { if (insertIndex == 0) return true; System.arraycopy(mScores, 1, mScores, 0, insertIndex); - System.arraycopy(mSuggestions, 1, mSuggestions, 0, insertIndex); + mSuggestions.add(insertIndex, new String(word, wordOffset, wordLength)); + mSuggestions.remove(0); } mScores[insertIndex] = score; - mSuggestions[insertIndex] = new String(word, wordOffset, wordLength); return true; } public String[] getGatheredSuggestions() { - if (0 == mLength) return null; + if (!mSeenSuggestions) return null; + if (0 == mLength) return EMPTY_STRING_ARRAY; - final String[] results = new String[mLength]; - for (int i = mLength - 1; i >= 0; --i) { - results[mLength - i - 1] = mSuggestions[i]; + if (DBG) { + if (mLength != mSuggestions.size()) { + Log.e(TAG, "Suggestion size is not the same as stored mLength"); + } } - return results; + Collections.reverse(mSuggestions); + Utils.removeDupes(mSuggestions); + // This returns a String[], while toArray() returns an Object[] which cannot be cast + // into a String[]. + return mSuggestions.toArray(EMPTY_STRING_ARRAY); } } @@ -153,10 +165,14 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private class AndroidSpellCheckerSession extends Session { // Immutable, but need the locale which is not available in the constructor yet DictionaryPool mDictionaryPool; + // Likewise + Locale mLocale; @Override public void onCreate() { - mDictionaryPool = getDictionaryPool(getLocale()); + final String localeString = getLocale(); + mDictionaryPool = getDictionaryPool(localeString); + mLocale = Utils.constructLocaleFromString(localeString); } // Note : this must be reentrant @@ -170,6 +186,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService { final int suggestionsLimit) { final String text = textInfo.getText(); + if (TextUtils.isEmpty(text)) return EMPTY_SUGGESTIONS_INFO; + final SuggestionsGatherer suggestionsGatherer = new SuggestionsGatherer(suggestionsLimit); final WordComposer composer = new WordComposer(); @@ -194,12 +212,32 @@ public class AndroidSpellCheckerService extends SpellCheckerService { dictInfo.mDictionary.getWords(composer, suggestionsGatherer, dictInfo.mProximityInfo); isInDict = dictInfo.mDictionary.isValidWord(text); + if (!isInDict && Character.isUpperCase(text.codePointAt(0))) { + // If the first char is not uppercase, then the word is either all lower case, + // in which case we already tested it, or mixed case, in which case we don't + // want to test a lower-case version of it. Hence the test above. + // Also note that by isEmpty() test at the top of the method codePointAt(0) is + // guaranteed to be there. + final int len = text.codePointCount(0, text.length()); + int capsCount = 1; + for (int i = 1; i < len; ++i) { + if (1 != capsCount && i != capsCount) break; + if (Character.isUpperCase(text.codePointAt(i))) ++capsCount; + } + // We know the first char is upper case. So we want to test if either everything + // else is lower case, or if everything else is upper case. If the string is + // exactly one char long, then we will arrive here with capsCount 0, and this is + // correct, too. + if (1 == capsCount || len == capsCount) { + isInDict = dictInfo.mDictionary.isValidWord(text.toLowerCase(mLocale)); + } + } if (!mDictionaryPool.offer(dictInfo)) { Log.e(TAG, "Can't re-insert a dictionary into its pool"); } } catch (InterruptedException e) { // I don't think this can happen. - return new SuggestionsInfo(0, new String[0]); + return EMPTY_SUGGESTIONS_INFO; } final String[] suggestions = suggestionsGatherer.getGatheredSuggestions(); |