diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java')
-rw-r--r-- | java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java | 127 |
1 files changed, 111 insertions, 16 deletions
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 4a822d7b0..848dcbed5 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -16,35 +16,130 @@ package com.android.inputmethod.latin.spellcheck; +import android.content.res.Resources; import android.service.textservice.SpellCheckerService; import android.util.Log; import android.view.textservice.SuggestionsInfo; import android.view.textservice.TextInfo; +import com.android.inputmethod.compat.ArraysCompatUtils; +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.ProximityInfo; +import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.latin.Dictionary.DataType; +import com.android.inputmethod.latin.Dictionary.WordCallback; +import com.android.inputmethod.latin.DictionaryFactory; +import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.WordComposer; + +import java.util.Collections; +import java.util.List; +import java.util.LinkedList; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; + /** * Service for spell checking, using LatinIME's dictionaries and mechanisms. */ public class AndroidSpellCheckerService extends SpellCheckerService { private static final String TAG = AndroidSpellCheckerService.class.getSimpleName(); private static final boolean DBG = true; + + private final static String[] emptyArray = new String[0]; + private final ProximityInfo mProximityInfo = ProximityInfo.getDummyProximityInfo(); + private final Map<String, Dictionary> mDictionaries = + Collections.synchronizedMap(new TreeMap<String, Dictionary>()); + + private static class SuggestionsGatherer implements WordCallback { + private final int DEFAULT_SUGGESTION_LENGTH = 16; + private final String[] mSuggestions; + private final int[] mScores; + private final int mMaxLength; + private int mLength = 0; + + SuggestionsGatherer(final int maxLength) { + mMaxLength = maxLength; + mSuggestions = new String[mMaxLength]; + mScores = new int[mMaxLength]; + } + + @Override + synchronized public boolean addWord(char[] word, int wordOffset, int wordLength, int score, + int dicTypeId, DataType dataType) { + final int positionIndex = ArraysCompatUtils.binarySearch(mScores, 0, mLength, score); + // binarySearch returns the index if the element exists, and -<insertion index> - 1 + // if it doesn't. See documentation for binarySearch. + final int insertIndex = positionIndex >= 0 ? positionIndex : -positionIndex - 1; + + 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); + } else { + if (insertIndex == 0) return true; + System.arraycopy(mScores, 1, mScores, 0, insertIndex); + System.arraycopy(mSuggestions, 1, mSuggestions, 0, insertIndex); + } + mScores[insertIndex] = score; + mSuggestions[insertIndex] = new String(word, wordOffset, wordLength); + + return true; + } + + public String[] getGatheredSuggestions() { + if (0 == mLength) return null; + + final String[] results = new String[mLength]; + for (int i = mLength - 1; i >= 0; --i) { + results[mLength - i - 1] = mSuggestions[i]; + } + return results; + } + } + + private Dictionary getDictionary(final String locale) { + Dictionary dictionary = mDictionaries.get(locale); + if (null == dictionary) { + final Resources resources = getResources(); + final int fallbackResourceId = Utils.getMainDictionaryResourceId(resources); + final Locale localeObject = Utils.constructLocaleFromString(locale); + dictionary = DictionaryFactory.createDictionaryFromManager(this, localeObject, + fallbackResourceId); + mDictionaries.put(locale, dictionary); + } + return dictionary; + } + + // Note : this must be reentrant + /** + * Gets a list of suggestions for a specific string. + * + * This returns a list of possible corrections for the text passed as an + * arguments. It may split or group words, and even perform grammatical + * analysis. + */ @Override - public SuggestionsInfo getSuggestions(TextInfo textInfo, int suggestionsLimit, - String locale) { - // TODO: implement this + public SuggestionsInfo getSuggestions(final TextInfo textInfo, final int suggestionsLimit, + final String locale) { + final Dictionary dictionary = getDictionary(locale); final String text = textInfo.getText(); - if (DBG) { - Log.w(TAG, "getSuggestions: " + text); - } - String[] candidates0 = new String[] {text, "candidate1", "candidate2", "candidate3"}; - String[] candidates1 = new String[] {text, "candidateA", "candidateB"}; - final int textLength = textInfo.getText().length() % 3; - if (textLength % 3 == 0) { - return new SuggestionsInfo(2 - | SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY, candidates0); - } else if (textLength % 3 == 1) { - return new SuggestionsInfo(SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY, candidates1); - } else { - return new SuggestionsInfo(0, null); + + final SuggestionsGatherer suggestionsGatherer = new SuggestionsGatherer(suggestionsLimit); + final WordComposer composer = new WordComposer(); + final int length = text.length(); + for (int i = 0; i < length; ++i) { + int character = text.codePointAt(i); + composer.add(character, new int[] { character }, + WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); } + dictionary.getWords(composer, suggestionsGatherer, mProximityInfo); + final boolean isInDict = dictionary.isValidWord(text); + final String[] suggestions = suggestionsGatherer.getGatheredSuggestions(); + + final int flags = (isInDict ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY : 0) + | (null != suggestions ? SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO : 0); + return new SuggestionsInfo(flags, suggestions); } } |