diff options
Diffstat (limited to 'java/src')
8 files changed, 187 insertions, 141 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index 06d248e3a..7ae3467f9 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -82,8 +82,6 @@ public class Key { /** The visual insets */ public final int mVisualInsetsLeft; public final int mVisualInsetsRight; - /** Whether this key is sticky, i.e., a toggle key */ - public final boolean mSticky; /** X coordinate of the key in the keyboard layout */ public final int mX; /** Y coordinate of the key in the keyboard layout */ @@ -102,8 +100,14 @@ public class Key { * {@link Keyboard#EDGE_TOP} and {@link Keyboard#EDGE_BOTTOM}. */ private int mEdgeFlags; - /** Whether this is a functional key which has different key top than normal key */ - public final boolean mFunctional; + + /** Background type that represents different key background visual than normal one. */ + public final int mBackgroundType; + public static final int BACKGROUND_TYPE_NORMAL = 0; + public static final int BACKGROUND_TYPE_FUNCTIONAL = 1; + public static final int BACKGROUND_TYPE_ACTION = 2; + public static final int BACKGROUND_TYPE_STICKY = 3; + /** Whether this key repeats itself when held down */ public final boolean mRepeatable; @@ -121,44 +125,6 @@ public class Key { private static final int KEYWIDTH_FILL_RIGHT = -1; private static final int KEYWIDTH_FILL_BOTH = -2; - private final static int[] KEY_STATE_NORMAL_ON = { - android.R.attr.state_checkable, - android.R.attr.state_checked - }; - - private final static int[] KEY_STATE_PRESSED_ON = { - android.R.attr.state_pressed, - android.R.attr.state_checkable, - android.R.attr.state_checked - }; - - private final static int[] KEY_STATE_NORMAL_OFF = { - android.R.attr.state_checkable - }; - - private final static int[] KEY_STATE_PRESSED_OFF = { - android.R.attr.state_pressed, - android.R.attr.state_checkable - }; - - private final static int[] KEY_STATE_NORMAL = { - }; - - private final static int[] KEY_STATE_PRESSED = { - android.R.attr.state_pressed - }; - - // functional normal state (with properties) - private static final int[] KEY_STATE_FUNCTIONAL_NORMAL = { - android.R.attr.state_single - }; - - // functional pressed state (with properties) - private static final int[] KEY_STATE_FUNCTIONAL_PRESSED = { - android.R.attr.state_single, - android.R.attr.state_pressed - }; - // RTL parenthesis character swapping map. private static final Map<Integer, Integer> sRtlParenthesisMap = new HashMap<Integer, Integer>(); @@ -225,8 +191,7 @@ public class Key { mEdgeFlags = edgeFlags; mHintLabel = hintLabel; mLabelOption = 0; - mFunctional = false; - mSticky = false; + mBackgroundType = BACKGROUND_TYPE_NORMAL; mRepeatable = false; mMoreKeys = null; mMaxMoreKeysColumn = 0; @@ -325,9 +290,9 @@ public class Key { mMaxMoreKeysColumn = style.getInt(keyboardAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMiniKeyboardColumn); + mBackgroundType = style.getInt( + keyAttr, R.styleable.Keyboard_Key_backgroundType, BACKGROUND_TYPE_NORMAL); mRepeatable = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable, false); - mFunctional = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isFunctional, false); - mSticky = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isSticky, false); mEnabled = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_enabled, true); mEdgeFlags = 0; @@ -371,6 +336,10 @@ public class Key { mEdgeFlags |= flags; } + public boolean isSticky() { + return mBackgroundType == BACKGROUND_TYPE_STICKY; + } + public boolean isSpacer() { return false; } @@ -533,6 +502,55 @@ public class Key { return dx * dx + dy * dy; } + private final static int[] KEY_STATE_NORMAL_HIGHLIGHT_ON = { + android.R.attr.state_checkable, + android.R.attr.state_checked + }; + + private final static int[] KEY_STATE_PRESSED_HIGHLIGHT_ON = { + android.R.attr.state_pressed, + android.R.attr.state_checkable, + android.R.attr.state_checked + }; + + private final static int[] KEY_STATE_NORMAL_HIGHLIGHT_OFF = { + android.R.attr.state_checkable + }; + + private final static int[] KEY_STATE_PRESSED_HIGHLIGHT_OFF = { + android.R.attr.state_pressed, + android.R.attr.state_checkable + }; + + private final static int[] KEY_STATE_NORMAL = { + }; + + private final static int[] KEY_STATE_PRESSED = { + android.R.attr.state_pressed + }; + + // functional normal state (with properties) + private static final int[] KEY_STATE_FUNCTIONAL_NORMAL = { + android.R.attr.state_single + }; + + // functional pressed state (with properties) + private static final int[] KEY_STATE_FUNCTIONAL_PRESSED = { + android.R.attr.state_single, + android.R.attr.state_pressed + }; + + // action normal state (with properties) + private static final int[] KEY_STATE_ACTIVE_NORMAL = { + android.R.attr.state_active + }; + + // action pressed state (with properties) + private static final int[] KEY_STATE_ACTIVE_PRESSED = { + android.R.attr.state_active, + android.R.attr.state_pressed + }; + /** * Returns the drawable state for the key, based on the current state and type of the key. * @return the drawable state of the key. @@ -540,36 +558,21 @@ public class Key { */ public int[] getCurrentDrawableState() { final boolean pressed = mPressed; - if (!mSticky && mFunctional) { - if (pressed) { - return KEY_STATE_FUNCTIONAL_PRESSED; - } else { - return KEY_STATE_FUNCTIONAL_NORMAL; - } - } - - int[] states = KEY_STATE_NORMAL; - if (mHighlightOn) { - if (pressed) { - states = KEY_STATE_PRESSED_ON; - } else { - states = KEY_STATE_NORMAL_ON; - } - } else { - if (mSticky) { - if (pressed) { - states = KEY_STATE_PRESSED_OFF; - } else { - states = KEY_STATE_NORMAL_OFF; - } + switch (mBackgroundType) { + case BACKGROUND_TYPE_FUNCTIONAL: + return pressed ? KEY_STATE_FUNCTIONAL_PRESSED : KEY_STATE_FUNCTIONAL_NORMAL; + case BACKGROUND_TYPE_ACTION: + return pressed ? KEY_STATE_ACTIVE_PRESSED : KEY_STATE_ACTIVE_NORMAL; + case BACKGROUND_TYPE_STICKY: + if (mHighlightOn) { + return pressed ? KEY_STATE_PRESSED_HIGHLIGHT_ON : KEY_STATE_NORMAL_HIGHLIGHT_ON; } else { - if (pressed) { - states = KEY_STATE_PRESSED; - } + return pressed ? KEY_STATE_PRESSED_HIGHLIGHT_OFF : KEY_STATE_NORMAL_HIGHLIGHT_OFF; } + default: /* BACKGROUND_TYPE_NORMAL */ + return pressed ? KEY_STATE_PRESSED : KEY_STATE_NORMAL; } - return states; } public static class Spacer extends Key { diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java index 6d78e8533..3d2d77cf4 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java @@ -172,8 +172,7 @@ public class KeyStyles { readInt(keyAttr, R.styleable.Keyboard_Key_keyIconPreview); readInt(keyAttr, R.styleable.Keyboard_Key_keyIconShifted); readInt(keyAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn); - readBoolean(keyAttr, R.styleable.Keyboard_Key_isFunctional); - readBoolean(keyAttr, R.styleable.Keyboard_Key_isSticky); + readInt(keyAttr, R.styleable.Keyboard_Key_backgroundType); readBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable); readBoolean(keyAttr, R.styleable.Keyboard_Key_enabled); } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java index 4432ee121..593c3dc5b 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java @@ -78,7 +78,7 @@ public class KeyboardParams { updateHistogram(key); if (key.mCode == Keyboard.CODE_SHIFT) { mShiftKeys.add(key); - if (key.mSticky) { + if (key.isSticky()) { mShiftLockKeys.add(key); } } diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 93933f1bc..16dccf824 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -306,12 +306,10 @@ public class Suggest implements Dictionary.WordCallback { Arrays.fill(mScores, 0); // Save a lowercase version of the original word - CharSequence typedWord = wordComposer.getTypedWord(); + String typedWord = wordComposer.getTypedWord(); if (typedWord != null) { - final String typedWordString = typedWord.toString(); - typedWord = typedWordString; // Treating USER_TYPED as UNIGRAM suggestion for logging now. - LatinImeLogger.onAddSuggestedWord(typedWordString, Suggest.DIC_USER_TYPED, + LatinImeLogger.onAddSuggestedWord(typedWord, Suggest.DIC_USER_TYPED, Dictionary.DataType.UNIGRAM); } mTypedWord = typedWord; diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java index 4a812b3a9..b526fe510 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java @@ -23,7 +23,12 @@ import com.android.inputmethod.keyboard.ProximityInfo; public class SynchronouslyLoadedUserDictionary extends UserDictionary { public SynchronouslyLoadedUserDictionary(final Context context, final String locale) { - super(context, locale); + this(context, locale, false); + } + + public SynchronouslyLoadedUserDictionary(final Context context, final String locale, + final boolean alsoUseMoreRestrictiveLocales) { + super(context, locale, alsoUseMoreRestrictiveLocales); } @Override diff --git a/java/src/com/android/inputmethod/latin/UserDictionary.java b/java/src/com/android/inputmethod/latin/UserDictionary.java index d696a6158..67da4fa50 100644 --- a/java/src/com/android/inputmethod/latin/UserDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserDictionary.java @@ -29,6 +29,8 @@ import android.text.TextUtils; import com.android.inputmethod.keyboard.ProximityInfo; +import java.util.Arrays; + public class UserDictionary extends ExpandableDictionary { private static final String[] PROJECTION_QUERY = { @@ -44,11 +46,18 @@ public class UserDictionary extends ExpandableDictionary { private ContentObserver mObserver; final private String mLocale; + final private boolean mAlsoUseMoreRestrictiveLocales; + + public UserDictionary(final Context context, final String locale) { + this(context, locale, false); + } - public UserDictionary(Context context, String locale) { + public UserDictionary(final Context context, final String locale, + final boolean alsoUseMoreRestrictiveLocales) { super(context, Suggest.DIC_USER); if (null == locale) throw new NullPointerException(); // Catch the error earlier mLocale = locale; + mAlsoUseMoreRestrictiveLocales = alsoUseMoreRestrictiveLocales; // Perform a managed query. The Activity will handle closing and re-querying the cursor // when needed. ContentResolver cres = context.getContentResolver(); @@ -81,12 +90,13 @@ public class UserDictionary extends ExpandableDictionary { // For this example, we'll look at the "en_US_POSIX" case. final String[] localeElements = TextUtils.isEmpty(mLocale) ? new String[] {} : mLocale.split("_", 3); + final int length = localeElements.length; final StringBuilder request = new StringBuilder("(locale is NULL)"); String localeSoFar = ""; // At start, localeElements = ["en", "US", "POSIX"] ; localeSoFar = "" ; // and request = "(locale is NULL)" - for (int i = 0; i < localeElements.length; ++i) { + for (int i = 0; i < length; ++i) { // i | localeSoFar | localeElements // 0 | "" | ["en", "US", "POSIX"] // 1 | "en_" | ["en", "US", "POSIX"] @@ -101,9 +111,29 @@ public class UserDictionary extends ExpandableDictionary { } // At the end, localeElements = ["en", "en_US", "en_US_POSIX"]; localeSoFar = en_US_POSIX_" // and request = "(locale is NULL) or (locale=?) or (locale=?) or (locale=?)" - Cursor cursor = getContext().getContentResolver() + + final String[] requestArguments; + // If length == 3, we already have all the arguments we need (common prefix is meaningless + // inside variants + if (mAlsoUseMoreRestrictiveLocales && length < 3) { + request.append(" or (locale like ?)"); + // The following creates an array with one more (null) position + final String[] localeElementsWithMoreRestrictiveLocalesIncluded = + Arrays.copyOf(localeElements, length + 1); + localeElementsWithMoreRestrictiveLocalesIncluded[length] = + localeElements[length - 1] + "_%"; + requestArguments = localeElementsWithMoreRestrictiveLocalesIncluded; + // If for example localeElements = ["en"] + // then requestArguments = ["en", "en_%"] + // and request = (locale is NULL) or (locale=?) or (locale like ?) + // If localeElements = ["en", "en_US"] + // then requestArguments = ["en", "en_US", "en_US_%"] + } else { + requestArguments = localeElements; + } + final Cursor cursor = getContext().getContentResolver() .query(Words.CONTENT_URI, PROJECTION_QUERY, request.toString(), - localeElements, null); + requestArguments, null); addWords(cursor); } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 24519ad92..a79e6dc7f 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -164,11 +164,11 @@ public class WordComposer { * Returns the word as it was typed, without any correction applied. * @return the word that was typed so far */ - public CharSequence getTypedWord() { + public String getTypedWord() { if (size() == 0) { return null; } - return mTypedWord; + return mTypedWord.toString(); } /** diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index dfa0abf1b..1e5b87763 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -237,7 +237,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService { final String localeStr = locale.toString(); Dictionary userDict = mUserDictionaries.get(localeStr); if (null == userDict) { - userDict = new SynchronouslyLoadedUserDictionary(this, localeStr); + userDict = new SynchronouslyLoadedUserDictionary(this, localeStr, true); mUserDictionaries.put(localeStr, userDict); } dictionaryCollection.addDictionary(userDict); @@ -327,67 +327,78 @@ public class AndroidSpellCheckerService extends SpellCheckerService { @Override public SuggestionsInfo onGetSuggestions(final TextInfo textInfo, final int suggestionsLimit) { - final String text = textInfo.getText(); - - if (shouldFilterOut(text)) return EMPTY_SUGGESTIONS_INFO; - - final SuggestionsGatherer suggestionsGatherer = - new SuggestionsGatherer(suggestionsLimit); - final WordComposer composer = new WordComposer(); - final int length = text.length(); - for (int i = 0; i < length; ++i) { - final int character = text.codePointAt(i); - final int proximityIndex = SpellCheckerProximityInfo.getIndexOf(character); - final int[] proximities; - if (-1 == proximityIndex) { - proximities = new int[] { character }; - } else { - proximities = Arrays.copyOfRange(SpellCheckerProximityInfo.PROXIMITY, - proximityIndex, proximityIndex + SpellCheckerProximityInfo.ROW_SIZE); - } - composer.add(character, proximities, - WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); - } - - final int capitalizeType = getCapitalizationType(text); - boolean isInDict = true; try { - final DictAndProximity dictInfo = mDictionaryPool.take(); - dictInfo.mDictionary.getWords(composer, suggestionsGatherer, - dictInfo.mProximityInfo); - isInDict = dictInfo.mDictionary.isValidWord(text); - if (!isInDict && CAPITALIZE_NONE != capitalizeType) { - // We want to test the word again if it's all caps or first caps only. - // If it's fully down, we already tested it, if it's mixed case, we don't - // want to test a lowercase version of it. - isInDict = dictInfo.mDictionary.isValidWord(text.toLowerCase(mLocale)); + final String text = textInfo.getText(); + + if (shouldFilterOut(text)) return EMPTY_SUGGESTIONS_INFO; + + final SuggestionsGatherer suggestionsGatherer = + new SuggestionsGatherer(suggestionsLimit); + final WordComposer composer = new WordComposer(); + final int length = text.length(); + for (int i = 0; i < length; ++i) { + final int character = text.codePointAt(i); + final int proximityIndex = SpellCheckerProximityInfo.getIndexOf(character); + final int[] proximities; + if (-1 == proximityIndex) { + proximities = new int[] { character }; + } else { + proximities = Arrays.copyOfRange(SpellCheckerProximityInfo.PROXIMITY, + proximityIndex, + proximityIndex + SpellCheckerProximityInfo.ROW_SIZE); + } + composer.add(character, proximities, + WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); } - if (!mDictionaryPool.offer(dictInfo)) { - Log.e(TAG, "Can't re-insert a dictionary into its pool"); + + final int capitalizeType = getCapitalizationType(text); + boolean isInDict = true; + try { + final DictAndProximity dictInfo = mDictionaryPool.take(); + dictInfo.mDictionary.getWords(composer, suggestionsGatherer, + dictInfo.mProximityInfo); + isInDict = dictInfo.mDictionary.isValidWord(text); + if (!isInDict && CAPITALIZE_NONE != capitalizeType) { + // We want to test the word again if it's all caps or first caps only. + // If it's fully down, we already tested it, if it's mixed case, we don't + // want to test a lowercase version of it. + 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 EMPTY_SUGGESTIONS_INFO; } - } catch (InterruptedException e) { - // I don't think this can happen. - return EMPTY_SUGGESTIONS_INFO; - } - final SuggestionsGatherer.Result result = suggestionsGatherer.getResults(text, - mService.mTypoThreshold, capitalizeType, mLocale); + final SuggestionsGatherer.Result result = suggestionsGatherer.getResults(text, + mService.mTypoThreshold, capitalizeType, mLocale); + + if (DBG) { + Log.i(TAG, "Spell checking results for " + text + " with suggestion limit " + + suggestionsLimit); + Log.i(TAG, "IsInDict = " + result.mLooksLikeTypo); + Log.i(TAG, "LooksLikeTypo = " + result.mLooksLikeTypo); + for (String suggestion : result.mSuggestions) { + Log.i(TAG, suggestion); + } + } - if (DBG) { - Log.i(TAG, "Spell checking results for " + text + " with suggestion limit " - + suggestionsLimit); - Log.i(TAG, "IsInDict = " + result.mLooksLikeTypo); - Log.i(TAG, "LooksLikeTypo = " + result.mLooksLikeTypo); - for (String suggestion : result.mSuggestions) { - Log.i(TAG, suggestion); + final int flags = + (isInDict ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY : 0) + | (result.mLooksLikeTypo + ? SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO : 0); + return new SuggestionsInfo(flags, result.mSuggestions); + } catch (RuntimeException e) { + // Don't kill the keyboard if there is a bug in the spell checker + if (DBG) { + throw e; + } else { + Log.e(TAG, "Exception while spellcheking: " + e); + return EMPTY_SUGGESTIONS_INFO; } } - - final int flags = - (isInDict ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY : 0) - | (result.mLooksLikeTypo - ? SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO : 0); - return new SuggestionsInfo(flags, result.mSuggestions); } } } |