From ea843f2a2404f4bc04fda494e475520162cfca27 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Tue, 13 Sep 2011 17:46:23 +0900 Subject: Make WordComposer aware of capitalized word Change-Id: If6c0edef2334f018f2e04c6034f8ce747206f150 --- .../android/inputmethod/latin/WordComposer.java | 79 ++++++++-------------- 1 file changed, 27 insertions(+), 52 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index af5e4b179..24519ad92 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -33,15 +33,9 @@ public class WordComposer { */ private ArrayList mCodes; - private int mTypedLength; private int[] mXCoordinates; private int[] mYCoordinates; - /** - * The word chosen from the candidate list, until it is committed. - */ - private String mPreferredWord; - private StringBuilder mTypedWord; private int mCapsCount; @@ -57,7 +51,6 @@ public class WordComposer { final int N = BinaryDictionary.MAX_WORD_LENGTH; mCodes = new ArrayList(N); mTypedWord = new StringBuilder(N); - mTypedLength = 0; mXCoordinates = new int[N]; mYCoordinates = new int[N]; } @@ -68,14 +61,12 @@ public class WordComposer { public void init(WordComposer source) { mCodes = new ArrayList(source.mCodes); - mPreferredWord = source.mPreferredWord; mTypedWord = new StringBuilder(source.mTypedWord); - mCapsCount = source.mCapsCount; - mAutoCapitalized = source.mAutoCapitalized; - mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; - mTypedLength = source.mTypedLength; mXCoordinates = source.mXCoordinates; mYCoordinates = source.mYCoordinates; + mCapsCount = source.mCapsCount; + mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; + mAutoCapitalized = source.mAutoCapitalized; } /** @@ -83,19 +74,17 @@ public class WordComposer { */ public void reset() { mCodes.clear(); - mTypedLength = 0; - mIsFirstCharCapitalized = false; - mPreferredWord = null; mTypedWord.setLength(0); mCapsCount = 0; + mIsFirstCharCapitalized = false; } /** * Number of keystrokes in the composing word. * @return the number of keystrokes */ - public int size() { - return mCodes.size(); + public final int size() { + return mTypedWord.length(); } /** @@ -115,21 +104,28 @@ public class WordComposer { return mYCoordinates; } + private static boolean isFirstCharCapitalized(int index, int codePoint, boolean previous) { + if (index == 0) return Character.isUpperCase(codePoint); + return previous && Character.isLowerCase(codePoint); + } + /** * Add a new keystroke, with codes[0] containing the pressed key's unicode and the rest of * the array containing unicode for adjacent keys, sorted by reducing probability/proximity. * @param codes the array of unicode values */ public void add(int primaryCode, int[] codes, int x, int y) { + final int newIndex = size(); mTypedWord.append((char) primaryCode); correctPrimaryJuxtapos(primaryCode, codes); mCodes.add(codes); - if (mTypedLength < BinaryDictionary.MAX_WORD_LENGTH) { - mXCoordinates[mTypedLength] = x; - mYCoordinates[mTypedLength] = y; + if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { + mXCoordinates[newIndex] = x; + mYCoordinates[newIndex] = y; } - ++mTypedLength; - if (Character.isUpperCase((char) primaryCode)) mCapsCount++; + mIsFirstCharCapitalized = isFirstCharCapitalized( + newIndex, primaryCode, mIsFirstCharCapitalized); + if (Character.isUpperCase(primaryCode)) mCapsCount++; } /** @@ -151,16 +147,16 @@ public class WordComposer { * Delete the last keystroke as a result of hitting backspace. */ public void deleteLast() { - final int codesSize = mCodes.size(); - if (codesSize > 0) { - mCodes.remove(codesSize - 1); - final int lastPos = mTypedWord.length() - 1; - char last = mTypedWord.charAt(lastPos); + final int size = size(); + if (size > 0) { + final int lastPos = size - 1; + char lastChar = mTypedWord.charAt(lastPos); + mCodes.remove(lastPos); mTypedWord.deleteCharAt(lastPos); - if (Character.isUpperCase(last)) mCapsCount--; + if (Character.isUpperCase(lastChar)) mCapsCount--; } - if (mTypedLength > 0) { - --mTypedLength; + if (size() == 0) { + mIsFirstCharCapitalized = false; } } @@ -169,17 +165,12 @@ public class WordComposer { * @return the word that was typed so far */ public CharSequence getTypedWord() { - int wordSize = mCodes.size(); - if (wordSize == 0) { + if (size() == 0) { return null; } return mTypedWord; } - public void setFirstCharCapitalized(boolean capitalized) { - mIsFirstCharCapitalized = capitalized; - } - /** * Whether or not the user typed a capital letter as the first letter in the word * @return capitalization preference @@ -196,22 +187,6 @@ public class WordComposer { return (mCapsCount > 0) && (mCapsCount == size()); } - /** - * Stores the user's selected word, before it is actually committed to the text field. - * @param preferred - */ - public void setPreferredWord(String preferred) { - mPreferredWord = preferred; - } - - /** - * Return the word chosen by the user, or the typed word if no other word was chosen. - * @return the preferred word - */ - public CharSequence getPreferredWord() { - return mPreferredWord != null ? mPreferredWord : getTypedWord(); - } - /** * Returns true if more than one character is upper case, otherwise returns false. */ -- cgit v1.2.3-83-g751a From 5c08151c227d98031abe27c3f0a8f43a7126ae9d Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 15 Sep 2011 15:42:21 +0900 Subject: Avoid returning an object that's still used internally There is no definite path known for this to end up being touched by other classes, but we could imagine through some way or some other it ends up shoved in the stringbuilder pool, leading to catastrophic results. Hopefully related to Bug: 5248688 Change-Id: Ib8abfc31263cbf31d515ed607ced5d8253971938 --- java/src/com/android/inputmethod/latin/Suggest.java | 6 ++---- java/src/com/android/inputmethod/latin/WordComposer.java | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') 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/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(); } /** -- cgit v1.2.3-83-g751a From 436a645ea837d36f7e0f81948d343fa6e166f33a Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Fri, 16 Sep 2011 12:28:13 +0900 Subject: Fix checking capitalized word code This is a follow up change of If6c0edef. Bug: 5328922 Change-Id: Idb415f53f3fea6660c7802577d08b4d89d4e7842 --- java/src/com/android/inputmethod/latin/WordComposer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index a79e6dc7f..adc5637f6 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -106,7 +106,7 @@ public class WordComposer { private static boolean isFirstCharCapitalized(int index, int codePoint, boolean previous) { if (index == 0) return Character.isUpperCase(codePoint); - return previous && Character.isLowerCase(codePoint); + return previous && !Character.isUpperCase(codePoint); } /** -- cgit v1.2.3-83-g751a From 8fbf29e2d54027a17993cd0d4ad486e3454b56f6 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Fri, 28 Oct 2011 13:31:31 +0900 Subject: Make some private method static Change-Id: Ia23765268be0ef89d7fe7c3f5372ed32d6615765 --- .../compat/InputMethodManagerCompatWrapper.java | 3 +-- java/src/com/android/inputmethod/keyboard/Key.java | 2 +- .../android/inputmethod/keyboard/internal/KeyStyles.java | 2 +- .../com/android/inputmethod/latin/AutoCorrection.java | 2 +- java/src/com/android/inputmethod/latin/LatinIME.java | 16 ++++++---------- java/src/com/android/inputmethod/latin/Suggest.java | 5 +++-- .../android/inputmethod/latin/UserBigramDictionary.java | 8 ++++---- .../android/inputmethod/latin/UserUnigramDictionary.java | 4 ++-- java/src/com/android/inputmethod/latin/Utils.java | 4 ++-- java/src/com/android/inputmethod/latin/WordComposer.java | 2 +- .../latin/spellcheck/AndroidSpellCheckerService.java | 2 +- 11 files changed, 23 insertions(+), 27 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java index 51dc4cd37..0e5f8c80a 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java @@ -153,8 +153,7 @@ public class InputMethodManagerCompatWrapper { return Utils.getInputMethodInfo(this, mLatinImePackageName); } - @SuppressWarnings("unused") - private InputMethodSubtypeCompatWrapper getLastResortSubtype(String mode) { + private static InputMethodSubtypeCompatWrapper getLastResortSubtype(String mode) { if (VOICE_MODE.equals(mode) && !FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES) return null; Locale inputLocale = SubtypeSwitcher.getInstance().getInputLocale(); diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index f1ae0b313..f2014b771 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -223,7 +223,7 @@ public class Key { if (style == null) throw new ParseException("Unknown key style: " + styleName, parser); } else { - style = keyStyles.getEmptyKeyStyle(); + style = KeyStyles.getEmptyKeyStyle(); } final float keyXPos = row.getKeyX(keyAttr); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java index b385b7a04..39fb521ea 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java @@ -235,7 +235,7 @@ public class KeyStyles { return mStyles.get(styleName); } - public KeyStyle getEmptyKeyStyle() { + public static KeyStyle getEmptyKeyStyle() { return EMPTY_KEY_STYLE; } } diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java index 485ec511f..cd066a3d1 100644 --- a/java/src/com/android/inputmethod/latin/AutoCorrection.java +++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java @@ -98,7 +98,7 @@ public class AutoCorrection { return whiteListedWord != null; } - private boolean hasAutoCorrectionForTypedWord(Map dictionaries, + private static boolean hasAutoCorrectionForTypedWord(Map dictionaries, WordComposer wordComposer, ArrayList suggestions, CharSequence typedWord, int correctionMode) { if (TextUtils.isEmpty(typedWord)) return false; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 1666fc191..70e0a1852 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1178,7 +1178,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } // "ic" must not be null - private void maybeRemovePreviousPeriod(final InputConnection ic, CharSequence text) { + private static void maybeRemovePreviousPeriod(final InputConnection ic, CharSequence text) { // When the text's first character is '.', remove the previous period // if there is one. final CharSequence lastOne = ic.getTextBeforeCursor(1, 0); @@ -1190,7 +1190,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } // "ic" may be null - private void removeTrailingSpaceWhileInBatchEdit(final InputConnection ic) { + private static void removeTrailingSpaceWhileInBatchEdit(final InputConnection ic) { if (ic == null) return; final CharSequence lastOne = ic.getTextBeforeCursor(1, 0); if (lastOne != null && lastOne.length() == 1 @@ -1208,12 +1208,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return true; } - private boolean isAlphabet(int code) { - if (Character.isLetter(code)) { - return true; - } else { - return false; - } + private static boolean isAlphabet(int code) { + return Character.isLetter(code); } private void onSettingsKeyPressed() { @@ -2075,7 +2071,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } // "ic" must not be null - private boolean sameAsTextBeforeCursor(final InputConnection ic, CharSequence text) { + private static boolean sameAsTextBeforeCursor(final InputConnection ic, CharSequence text) { CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0); return TextUtils.equals(text, beforeText); } @@ -2129,7 +2125,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return true; } - private boolean revertSwapPunctuation(final InputConnection ic) { + private static boolean revertSwapPunctuation(final InputConnection ic) { // Here we test whether we indeed have a space and something else before us. This should not // be needed, but it's there just in case something went wrong. final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0); diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index caa5aac51..97e91745c 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -144,7 +144,7 @@ public class Suggest implements Dictionary.WordCallback { initWhitelistAndAutocorrectAndPool(context, locale); } - private void addOrReplaceDictionary(Map dictionaries, String key, + private static void addOrReplaceDictionary(Map dictionaries, String key, Dictionary dict) { final Dictionary oldDict = (dict == null) ? dictionaries.remove(key) @@ -518,7 +518,8 @@ public class Suggest implements Dictionary.WordCallback { return -1; } - private void collectGarbage(ArrayList suggestions, int prefMaxSuggestions) { + private static void collectGarbage(ArrayList suggestions, + int prefMaxSuggestions) { int poolSize = StringBuilderPool.getSize(); int garbageSize = suggestions.size(); while (poolSize < prefMaxSuggestions && garbageSize > 0) { diff --git a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java index 9e656675e..3a1af9311 100644 --- a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java @@ -238,7 +238,7 @@ public class UserBigramDictionary extends ExpandableDictionary { /** * Query the database */ - private Cursor query(String selection, String[] selectionArgs) { + private static Cursor query(String selection, String[] selectionArgs) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); // main INNER JOIN frequency ON (main._id=freq.pair_id) @@ -310,7 +310,7 @@ public class UserBigramDictionary extends ExpandableDictionary { } /** Prune any old data if the database is getting too big. */ - private void checkPruneData(SQLiteDatabase db) { + private static void checkPruneData(SQLiteDatabase db) { db.execSQL("PRAGMA foreign_keys = ON;"); Cursor c = db.query(FREQ_TABLE_NAME, new String[] { FREQ_COLUMN_PAIR_ID }, null, null, null, null, null); @@ -380,7 +380,7 @@ public class UserBigramDictionary extends ExpandableDictionary { return null; } - private ContentValues getContentValues(String word1, String word2, String locale) { + private static ContentValues getContentValues(String word1, String word2, String locale) { ContentValues values = new ContentValues(3); values.put(MAIN_COLUMN_WORD1, word1); values.put(MAIN_COLUMN_WORD2, word2); @@ -388,7 +388,7 @@ public class UserBigramDictionary extends ExpandableDictionary { return values; } - private ContentValues getFrequencyContentValues(int pairId, int frequency) { + private static ContentValues getFrequencyContentValues(int pairId, int frequency) { ContentValues values = new ContentValues(2); values.put(FREQ_COLUMN_PAIR_ID, pairId); values.put(FREQ_COLUMN_FREQUENCY, frequency); diff --git a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java index e41230b3c..de7cb5716 100644 --- a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java @@ -206,7 +206,7 @@ public class UserUnigramDictionary extends ExpandableDictionary { } } - private Cursor query(String selection, String[] selectionArgs) { + private static Cursor query(String selection, String[] selectionArgs) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables(USER_UNIGRAM_DICT_TABLE_NAME); qb.setProjectionMap(sDictProjectionMap); @@ -251,7 +251,7 @@ public class UserUnigramDictionary extends ExpandableDictionary { return null; } - private ContentValues getContentValues(String word, int frequency, String locale) { + private static ContentValues getContentValues(String word, int frequency, String locale) { ContentValues values = new ContentValues(4); values.put(COLUMN_WORD, word); values.put(COLUMN_FREQUENCY, frequency); diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index b29ff1975..3d0aa09f1 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -242,7 +242,7 @@ public class Utils { UsabilityStudyLogUtils.getInstance().init(context); return sRingCharBuffer; } - private int normalize(int in) { + private static int normalize(int in) { int ret = in % BUFSIZE; return ret < 0 ? ret + BUFSIZE : ret; } @@ -465,7 +465,7 @@ public class Utils { } } - public void writeBackSpace() { + public static void writeBackSpace() { UsabilityStudyLogUtils.getInstance().write("\t0\t0"); } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index adc5637f6..7f3a54244 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -135,7 +135,7 @@ public class WordComposer { * @param primaryCode the preferred character * @param codes array of codes based on distance from touch point */ - private void correctPrimaryJuxtapos(int primaryCode, int[] codes) { + private static void correctPrimaryJuxtapos(int primaryCode, int[] codes) { if (codes.length < 2) return; if (codes[0] > 0 && codes[1] > 0 && codes[0] != primaryCode && codes[1] == primaryCode) { codes[1] = codes[0]; diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 095c2c51c..5d296f892 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -368,7 +368,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService { * @param text the string to evaluate. * @return true if we should filter this text out, false otherwise */ - private boolean shouldFilterOut(final String text) { + private static boolean shouldFilterOut(final String text) { if (TextUtils.isEmpty(text) || text.length() <= 1) return true; // TODO: check if an equivalent processing can't be done more quickly with a -- cgit v1.2.3-83-g751a From c83359f9746ca6f0269a1a7017b585c1a5cab9b8 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 18 Nov 2011 20:03:38 +0900 Subject: Special case quotes at start and end of words Single quote at start of word is not considered a part of a word any more. Single quote at the end of a word now behave like capitalization: lookup in the dictionary is done *disregarding* a final quote, and it is forcefully added back into the suggestions afterwards. Bug: 5566368 Change-Id: I14dd3815f4b743edba56d64a3abdf4b73d863a6a --- .../com/android/inputmethod/latin/LatinIME.java | 13 ++++++- .../src/com/android/inputmethod/latin/Suggest.java | 43 +++++++++++++++------- .../android/inputmethod/latin/WordComposer.java | 22 +++++++++-- 3 files changed, 61 insertions(+), 17 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 167e500f6..d72f8652d 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1503,6 +1503,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mComposingStateManager.onFinishComposingText(); } } + if (code == Keyboard.CODE_SINGLE_QUOTE && !isCursorTouchingWord()) { + mHasUncommittedTypedChars = false; + } final KeyboardSwitcher switcher = mKeyboardSwitcher; if (switcher.isShiftedOrShiftLocked()) { if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT @@ -1775,7 +1778,15 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // a boolean flag. Right now this is handled with a slight hack in // WhitelistDictionary#shouldForciblyAutoCorrectFrom. final boolean allowsToBeAutoCorrected = AutoCorrection.allowsToBeAutoCorrected( - mSuggest.getUnigramDictionaries(), typedWord, preferCapitalization()); + mSuggest.getUnigramDictionaries(), + // If the typed string ends with a single quote, for dictionary lookup purposes + // we behave as if the single quote was not here. Here, we are looking up the + // typed string in the dictionary (to avoid autocorrecting from an existing + // word, so for consistency this lookup should be made WITHOUT the trailing + // single quote. + wordComposer.isLastCharASingleQuote() + ? typedWord.subSequence(0, typedWord.length() - 1) : typedWord, + preferCapitalization()); if (mCorrectionMode == Suggest.CORRECTION_FULL || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) { autoCorrectionAvailable |= (!allowsToBeAutoCorrected); diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 97e91745c..5a3c348a9 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -20,6 +20,7 @@ import android.content.Context; import android.text.TextUtils; import android.util.Log; +import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.ProximityInfo; import java.io.File; @@ -81,6 +82,8 @@ public class Suggest implements Dictionary.WordCallback { public static final String DICT_KEY_USER_BIGRAM = "user_bigram"; public static final String DICT_KEY_WHITELIST ="whitelist"; + private static String SINGLE_QUOTE_AS_STRING = String.valueOf((char)Keyboard.CODE_SINGLE_QUOTE); + private static final boolean DBG = LatinImeLogger.sDBG; private AutoCorrection mAutoCorrection; @@ -101,11 +104,12 @@ public class Suggest implements Dictionary.WordCallback { private ArrayList mSuggestions = new ArrayList(); ArrayList mBigramSuggestions = new ArrayList(); - private CharSequence mTypedWord; + private CharSequence mConsideredWord; // TODO: Remove these member variables by passing more context to addWord() callback method private boolean mIsFirstCharCapitalized; private boolean mIsAllUpperCase; + private boolean mIsLastCharASingleQuote; private int mCorrectionMode = CORRECTION_BASIC; @@ -295,17 +299,19 @@ public class Suggest implements Dictionary.WordCallback { mAutoCorrection.init(); mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); mIsAllUpperCase = wordComposer.isAllUpperCase(); + mIsLastCharASingleQuote = wordComposer.isLastCharASingleQuote(); collectGarbage(mSuggestions, mPrefMaxSuggestions); Arrays.fill(mScores, 0); - // Save a lowercase version of the original word - String typedWord = wordComposer.getTypedWord(); + final String typedWord = wordComposer.getTypedWord(); + final String consideredWord = mIsLastCharASingleQuote + ? typedWord.substring(0, typedWord.length() - 1) : typedWord; if (typedWord != null) { // Treating USER_TYPED as UNIGRAM suggestion for logging now. LatinImeLogger.onAddSuggestedWord(typedWord, Suggest.DIC_USER_TYPED, Dictionary.DataType.UNIGRAM); } - mTypedWord = typedWord; + mConsideredWord = consideredWord; if (wordComposer.size() <= 1 && (mCorrectionMode == CORRECTION_FULL_BIGRAM || mCorrectionMode == CORRECTION_BASIC)) { @@ -321,7 +327,7 @@ public class Suggest implements Dictionary.WordCallback { for (final Dictionary dictionary : mBigramDictionaries.values()) { dictionary.getBigrams(wordComposer, prevWordForBigram, this); } - if (TextUtils.isEmpty(typedWord)) { + if (TextUtils.isEmpty(consideredWord)) { // Nothing entered: return all bigrams for the previous word int insertCount = Math.min(mBigramSuggestions.size(), mPrefMaxSuggestions); for (int i = 0; i < insertCount; ++i) { @@ -330,7 +336,7 @@ public class Suggest implements Dictionary.WordCallback { } else { // Word entered: return only bigrams that match the first char of the typed word @SuppressWarnings("null") - final char currentChar = typedWord.charAt(0); + final char currentChar = consideredWord.charAt(0); // TODO: Must pay attention to locale when changing case. final char currentCharUpper = Character.toUpperCase(currentChar); int count = 0; @@ -354,24 +360,32 @@ public class Suggest implements Dictionary.WordCallback { if (key.equals(DICT_KEY_USER_UNIGRAM) || key.equals(DICT_KEY_WHITELIST)) continue; final Dictionary dictionary = mUnigramDictionaries.get(key); - dictionary.getWords(wordComposer, this, proximityInfo); + if (mIsLastCharASingleQuote) { + final WordComposer tmpWordComposer = new WordComposer(wordComposer); + tmpWordComposer.deleteLast(); + dictionary.getWords(tmpWordComposer, this, proximityInfo); + } else { + dictionary.getWords(wordComposer, this, proximityInfo); + } } } - final String typedWordString = typedWord == null ? null : typedWord.toString(); + final String consideredWordString = + consideredWord == null ? null : consideredWord.toString(); CharSequence whitelistedWord = capitalizeWord(mIsAllUpperCase, mIsFirstCharCapitalized, - mWhiteListDictionary.getWhitelistedWord(typedWordString)); + mWhiteListDictionary.getWhitelistedWord(consideredWordString)); mAutoCorrection.updateAutoCorrectionStatus(mUnigramDictionaries, wordComposer, - mSuggestions, mScores, typedWord, mAutoCorrectionThreshold, mCorrectionMode, + mSuggestions, mScores, consideredWord, mAutoCorrectionThreshold, mCorrectionMode, whitelistedWord); if (whitelistedWord != null) { - mSuggestions.add(0, whitelistedWord); + mSuggestions.add(0, mIsLastCharASingleQuote + ? whitelistedWord + SINGLE_QUOTE_AS_STRING : whitelistedWord); } if (typedWord != null) { - mSuggestions.add(0, typedWordString); + mSuggestions.add(0, typedWord.toString()); } Utils.removeDupes(mSuggestions); @@ -424,7 +438,7 @@ public class Suggest implements Dictionary.WordCallback { int pos = 0; // Check if it's the same word, only caps are different - if (Utils.equalsIgnoreCase(mTypedWord, word, offset, length)) { + if (Utils.equalsIgnoreCase(mConsideredWord, word, offset, length)) { // TODO: remove this surrounding if clause and move this logic to // getSuggestedWordBuilder. if (suggestions.size() > 0) { @@ -486,6 +500,9 @@ public class Suggest implements Dictionary.WordCallback { } else { sb.append(word, offset, length); } + if (mIsLastCharASingleQuote) { + sb.appendCodePoint(Keyboard.CODE_SINGLE_QUOTE); + } suggestions.add(pos, sb); if (suggestions.size() > prefMaxSuggestions) { final CharSequence garbage = suggestions.remove(prefMaxSuggestions); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 7f3a54244..612b16071 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -16,9 +16,11 @@ package com.android.inputmethod.latin; +import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyDetector; import java.util.ArrayList; +import java.util.Arrays; /** * A place to store the currently composing word with information such as adjacent key codes as well @@ -41,7 +43,9 @@ public class WordComposer { private int mCapsCount; private boolean mAutoCapitalized; - + // Cache this value for performance + private boolean mIsLastCharASingleQuote; + /** * Whether the user chose to capitalize the first char of the word. */ @@ -53,6 +57,7 @@ public class WordComposer { mTypedWord = new StringBuilder(N); mXCoordinates = new int[N]; mYCoordinates = new int[N]; + mIsLastCharASingleQuote = false; } public WordComposer(WordComposer source) { @@ -62,11 +67,12 @@ public class WordComposer { public void init(WordComposer source) { mCodes = new ArrayList(source.mCodes); mTypedWord = new StringBuilder(source.mTypedWord); - mXCoordinates = source.mXCoordinates; - mYCoordinates = source.mYCoordinates; + mXCoordinates = Arrays.copyOf(source.mXCoordinates, source.mXCoordinates.length); + mYCoordinates = Arrays.copyOf(source.mYCoordinates, source.mYCoordinates.length); mCapsCount = source.mCapsCount; mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; + mIsLastCharASingleQuote = source.mIsLastCharASingleQuote; } /** @@ -77,6 +83,7 @@ public class WordComposer { mTypedWord.setLength(0); mCapsCount = 0; mIsFirstCharCapitalized = false; + mIsLastCharASingleQuote = false; } /** @@ -126,6 +133,7 @@ public class WordComposer { mIsFirstCharCapitalized = isFirstCharCapitalized( newIndex, primaryCode, mIsFirstCharCapitalized); if (Character.isUpperCase(primaryCode)) mCapsCount++; + mIsLastCharASingleQuote = Keyboard.CODE_SINGLE_QUOTE == primaryCode; } /** @@ -157,6 +165,10 @@ public class WordComposer { } if (size() == 0) { mIsFirstCharCapitalized = false; + mIsLastCharASingleQuote = false; + } else { + mIsLastCharASingleQuote = + Keyboard.CODE_SINGLE_QUOTE == mTypedWord.codePointAt(mTypedWord.length() - 1); } } @@ -179,6 +191,10 @@ public class WordComposer { return mIsFirstCharCapitalized; } + public boolean isLastCharASingleQuote() { + return mIsLastCharASingleQuote; + } + /** * Whether or not all of the user typed chars are upper case * @return true if all user typed chars are upper case, false otherwise -- cgit v1.2.3-83-g751a From 117fc18ed46496c81596f8207bba30a09c7317d1 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 29 Nov 2011 14:15:41 +0900 Subject: Keep count of the trailing single quotes for suggestions Bug: 5665809 Change-Id: I4d9100dbe980861ccb55c78464524be670cac1f7 --- .../com/android/inputmethod/latin/LatinIME.java | 5 ++-- .../src/com/android/inputmethod/latin/Suggest.java | 30 ++++++++++++++-------- .../android/inputmethod/latin/WordComposer.java | 28 ++++++++++++-------- 3 files changed, 40 insertions(+), 23 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index f7a77cae7..52b15cec8 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1793,6 +1793,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // The whitelist should be case-insensitive, so it's not possible to be consistent with // a boolean flag. Right now this is handled with a slight hack in // WhitelistDictionary#shouldForciblyAutoCorrectFrom. + final int quotesCount = wordComposer.trailingSingleQuotesCount(); final boolean allowsToBeAutoCorrected = AutoCorrection.allowsToBeAutoCorrected( mSuggest.getUnigramDictionaries(), // If the typed string ends with a single quote, for dictionary lookup purposes @@ -1800,8 +1801,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // typed string in the dictionary (to avoid autocorrecting from an existing // word, so for consistency this lookup should be made WITHOUT the trailing // single quote. - wordComposer.isLastCharASingleQuote() - ? typedWord.subSequence(0, typedWord.length() - 1) : typedWord, + quotesCount > 0 + ? typedWord.subSequence(0, typedWord.length() - quotesCount) : typedWord, preferCapitalization()); if (mCorrectionMode == Suggest.CORRECTION_FULL || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) { diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 5a3c348a9..2a36f8266 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -82,8 +82,6 @@ public class Suggest implements Dictionary.WordCallback { public static final String DICT_KEY_USER_BIGRAM = "user_bigram"; public static final String DICT_KEY_WHITELIST ="whitelist"; - private static String SINGLE_QUOTE_AS_STRING = String.valueOf((char)Keyboard.CODE_SINGLE_QUOTE); - private static final boolean DBG = LatinImeLogger.sDBG; private AutoCorrection mAutoCorrection; @@ -109,7 +107,7 @@ public class Suggest implements Dictionary.WordCallback { // TODO: Remove these member variables by passing more context to addWord() callback method private boolean mIsFirstCharCapitalized; private boolean mIsAllUpperCase; - private boolean mIsLastCharASingleQuote; + private int mTrailingSingleQuotesCount; private int mCorrectionMode = CORRECTION_BASIC; @@ -299,13 +297,14 @@ public class Suggest implements Dictionary.WordCallback { mAutoCorrection.init(); mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); mIsAllUpperCase = wordComposer.isAllUpperCase(); - mIsLastCharASingleQuote = wordComposer.isLastCharASingleQuote(); + mTrailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount(); collectGarbage(mSuggestions, mPrefMaxSuggestions); Arrays.fill(mScores, 0); final String typedWord = wordComposer.getTypedWord(); - final String consideredWord = mIsLastCharASingleQuote - ? typedWord.substring(0, typedWord.length() - 1) : typedWord; + final String consideredWord = mTrailingSingleQuotesCount > 0 + ? typedWord.substring(0, typedWord.length() - mTrailingSingleQuotesCount) + : typedWord; if (typedWord != null) { // Treating USER_TYPED as UNIGRAM suggestion for logging now. LatinImeLogger.onAddSuggestedWord(typedWord, Suggest.DIC_USER_TYPED, @@ -360,9 +359,11 @@ public class Suggest implements Dictionary.WordCallback { if (key.equals(DICT_KEY_USER_UNIGRAM) || key.equals(DICT_KEY_WHITELIST)) continue; final Dictionary dictionary = mUnigramDictionaries.get(key); - if (mIsLastCharASingleQuote) { + if (mTrailingSingleQuotesCount > 0) { final WordComposer tmpWordComposer = new WordComposer(wordComposer); - tmpWordComposer.deleteLast(); + for (int i = mTrailingSingleQuotesCount - 1; i >= 0; --i) { + tmpWordComposer.deleteLast(); + } dictionary.getWords(tmpWordComposer, this, proximityInfo); } else { dictionary.getWords(wordComposer, this, proximityInfo); @@ -380,8 +381,15 @@ public class Suggest implements Dictionary.WordCallback { whitelistedWord); if (whitelistedWord != null) { - mSuggestions.add(0, mIsLastCharASingleQuote - ? whitelistedWord + SINGLE_QUOTE_AS_STRING : whitelistedWord); + if (mTrailingSingleQuotesCount > 0) { + final StringBuilder sb = new StringBuilder(whitelistedWord); + for (int i = mTrailingSingleQuotesCount - 1; i >= 0; --i) { + sb.appendCodePoint(Keyboard.CODE_SINGLE_QUOTE); + } + mSuggestions.add(0, sb.toString()); + } else { + mSuggestions.add(0, whitelistedWord); + } } if (typedWord != null) { @@ -500,7 +508,7 @@ public class Suggest implements Dictionary.WordCallback { } else { sb.append(word, offset, length); } - if (mIsLastCharASingleQuote) { + for (int i = mTrailingSingleQuotesCount - 1; i >= 0; --i) { sb.appendCodePoint(Keyboard.CODE_SINGLE_QUOTE); } suggestions.add(pos, sb); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 612b16071..f4d0c1e4f 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -44,7 +44,7 @@ public class WordComposer { private boolean mAutoCapitalized; // Cache this value for performance - private boolean mIsLastCharASingleQuote; + private int mTrailingSingleQuotesCount; /** * Whether the user chose to capitalize the first char of the word. @@ -57,7 +57,7 @@ public class WordComposer { mTypedWord = new StringBuilder(N); mXCoordinates = new int[N]; mYCoordinates = new int[N]; - mIsLastCharASingleQuote = false; + mTrailingSingleQuotesCount = 0; } public WordComposer(WordComposer source) { @@ -72,7 +72,7 @@ public class WordComposer { mCapsCount = source.mCapsCount; mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; - mIsLastCharASingleQuote = source.mIsLastCharASingleQuote; + mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount; } /** @@ -83,7 +83,7 @@ public class WordComposer { mTypedWord.setLength(0); mCapsCount = 0; mIsFirstCharCapitalized = false; - mIsLastCharASingleQuote = false; + mTrailingSingleQuotesCount = 0; } /** @@ -133,7 +133,11 @@ public class WordComposer { mIsFirstCharCapitalized = isFirstCharCapitalized( newIndex, primaryCode, mIsFirstCharCapitalized); if (Character.isUpperCase(primaryCode)) mCapsCount++; - mIsLastCharASingleQuote = Keyboard.CODE_SINGLE_QUOTE == primaryCode; + if (Keyboard.CODE_SINGLE_QUOTE == primaryCode) { + ++mTrailingSingleQuotesCount; + } else { + mTrailingSingleQuotesCount = 0; + } } /** @@ -165,10 +169,14 @@ public class WordComposer { } if (size() == 0) { mIsFirstCharCapitalized = false; - mIsLastCharASingleQuote = false; + } + if (mTrailingSingleQuotesCount > 0) { + --mTrailingSingleQuotesCount; } else { - mIsLastCharASingleQuote = - Keyboard.CODE_SINGLE_QUOTE == mTypedWord.codePointAt(mTypedWord.length() - 1); + for (int i = mTypedWord.length() - 1; i >= 0; --i) { + if (Keyboard.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break; + ++mTrailingSingleQuotesCount; + } } } @@ -191,8 +199,8 @@ public class WordComposer { return mIsFirstCharCapitalized; } - public boolean isLastCharASingleQuote() { - return mIsLastCharASingleQuote; + public int trailingSingleQuotesCount() { + return mTrailingSingleQuotesCount; } /** -- cgit v1.2.3-83-g751a From 6b1f500da451de56932a8b2a99c63857994ece85 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 22 Nov 2011 11:35:40 +0900 Subject: Resume suggestion when backspacing to the end of a word Bug: 5515381 Change-Id: I26fea896feaf2e9716c7ae3d4f2630360f23ac50 --- .../com/android/inputmethod/latin/LatinIME.java | 60 +++++++++++++++++++++- .../android/inputmethod/latin/TextEntryState.java | 15 ++++++ .../android/inputmethod/latin/WordComposer.java | 46 +++++++++++++++++ .../android/inputmethod/latin/SuggestHelper.java | 19 +------ 4 files changed, 120 insertions(+), 20 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index f7a77cae7..4f26a21f9 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -948,6 +948,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } mExpectingUpdateSelection = false; mHandler.postUpdateShiftKeyState(); + // TODO: Decide to call restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() or not + // here. It would probably be too expensive to call directly here but we may want to post a + // message to delay it. The point would be to unify behavior between backspace to the + // end of a word and manually put the pointer at the end of the word. // Make a note of the cursor position mLastSelectionStart = newSelStart; @@ -1466,10 +1470,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // inconsistent with backspacing after selecting other suggestions. revertLastWord(ic); } else { - sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); + ic.deleteSurroundingText(1, 0); if (mDeleteCount > DELETE_ACCELERATE_AT) { - sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); + ic.deleteSurroundingText(1, 0); } + restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(ic); } } ic.endBatchEdit(); @@ -2117,6 +2122,53 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return TextUtils.equals(text, beforeText); } + // "ic" must not be null + /** + * Check if the cursor is actually at the end of a word. If so, restart suggestions on this + * word, else do nothing. + */ + private void restartSuggestionsOnWordBeforeCursorIfAtEndOfWord( + final InputConnection ic) { + // Bail out if the cursor is not at the end of a word (cursor must be preceded by + // non-whitespace, non-separator, non-start-of-text) + // Example ("|" is the cursor here) : "|a" " |a" " | " all get rejected here. + final CharSequence textBeforeCursor = ic.getTextBeforeCursor(1, 0); + if (TextUtils.isEmpty(textBeforeCursor) + || mSettingsValues.isWordSeparator(textBeforeCursor.charAt(0))) return; + + // Bail out if the cursor is in the middle of a word (cursor must be followed by whitespace, + // separator or end of line/text) + // Example: "test|" "te|st" get rejected here + final CharSequence textAfterCursor = ic.getTextAfterCursor(1, 0); + if (!TextUtils.isEmpty(textAfterCursor) + && !mSettingsValues.isWordSeparator(textAfterCursor.charAt(0))) return; + + // Bail out if word before cursor is 0-length or a single non letter (like an apostrophe) + // Example: " '|" gets rejected here but "I'|" and "I|" are okay + final CharSequence word = EditingUtils.getWordAtCursor(ic, mSettingsValues.mWordSeparators); + if (TextUtils.isEmpty(word)) return; + if (word.length() == 1 && !Character.isLetter(word.charAt(0))) return; + + // Okay, we are at the end of a word. Restart suggestions. + restartSuggestionsOnWordBeforeCursor(ic, word); + } + + // "ic" must not be null + private void restartSuggestionsOnWordBeforeCursor(final InputConnection ic, + final CharSequence word) { + mWordComposer.setComposingWord(word, mKeyboardSwitcher.getLatinKeyboard()); + mComposingStringBuilder.setLength(0); + mComposingStringBuilder.append(word); + // mBestWord will be set appropriately by updateSuggestions() called by the handler + mBestWord = null; + mHasUncommittedTypedChars = true; + mComposingStateManager.onStartComposingText(); + TextEntryState.restartSuggestionsOnWordBeforeCursor(); + ic.deleteSurroundingText(word.length(), 0); + ic.setComposingText(word, 1); + mHandler.postUpdateSuggestions(); + } + // "ic" must not be null private void revertLastWord(final InputConnection ic) { if (mHasUncommittedTypedChars || mComposingStringBuilder.length() <= 0) { @@ -2143,6 +2195,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Clear composing text mComposingStringBuilder.setLength(0); } else { + // Note: this relies on the last word still being held in the WordComposer + // Note: in the interest of code simplicity, we may want to just call + // restartSuggestionsOnWordBeforeCursorIfAtEndOfWord instead, but retrieving + // the old WordComposer allows to reuse the actual typed coordinates. mHasUncommittedTypedChars = true; ic.setComposingText(mComposingStringBuilder, 1); TextEntryState.backspace(); diff --git a/java/src/com/android/inputmethod/latin/TextEntryState.java b/java/src/com/android/inputmethod/latin/TextEntryState.java index 82242f87e..a6041b310 100644 --- a/java/src/com/android/inputmethod/latin/TextEntryState.java +++ b/java/src/com/android/inputmethod/latin/TextEntryState.java @@ -146,9 +146,24 @@ public class TextEntryState { } else if (sState == UNDO_COMMIT) { setState(IN_WORD); } + // TODO: tidy up this logic. At the moment, for example, writing a word goes to + // ACCEPTED_DEFAULT, backspace will go to UNDO_COMMIT, another backspace will go to IN_WORD, + // and subsequent backspaces will leave the status at IN_WORD, even if the user backspaces + // past the end of the word. We are not in a word any more but the state is still IN_WORD. if (DEBUG) displayState("backspace"); } + public static void restartSuggestionsOnWordBeforeCursor() { + if (UNKNOWN == sState || ACCEPTED_DEFAULT == sState) { + // Here we can come from pretty much any state, except the ones that we can't + // come from after backspace, so supposedly anything except UNKNOWN and + // ACCEPTED_DEFAULT. Note : we could be in UNDO_COMMIT if + // LatinIME#revertLastWord() was calling LatinIME#restartSuggestions...() + Log.e(TAG, "Strange state change : coming from state " + sState); + } + setState(IN_WORD); + } + public static void reset() { setState(START); if (DEBUG) displayState("reset"); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 612b16071..ef2e4d378 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -17,7 +17,9 @@ package com.android.inputmethod.latin; import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; +import com.android.inputmethod.keyboard.LatinKeyboard; import java.util.ArrayList; import java.util.Arrays; @@ -136,6 +138,50 @@ public class WordComposer { mIsLastCharASingleQuote = Keyboard.CODE_SINGLE_QUOTE == primaryCode; } + /** + * Internal method to retrieve reasonable proximity info for a character. + */ + private void addKeyInfo(final int codePoint, final LatinKeyboard keyboard, + final KeyDetector keyDetector) { + for (final Key key : keyboard.mKeys) { + if (key.mCode == codePoint) { + final int x = key.mX + key.mWidth / 2; + final int y = key.mY + key.mHeight / 2; + final int[] codes = keyDetector.newCodeArray(); + keyDetector.getKeyIndexAndNearbyCodes(x, y, codes); + add(codePoint, codes, x, y); + return; + } + } + add(codePoint, new int[] { codePoint }, + WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); + } + + /** + * Set the currently composing word to the one passed as an argument. + * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. + */ + public void setComposingWord(final CharSequence word, final LatinKeyboard keyboard, + final KeyDetector keyDetector) { + reset(); + final int length = word.length(); + for (int i = 0; i < length; ++i) { + int codePoint = word.charAt(i); + addKeyInfo(codePoint, keyboard, keyDetector); + } + } + + /** + * Shortcut for the above method, this will create a new KeyDetector for the passed keyboard. + */ + public void setComposingWord(final CharSequence word, final LatinKeyboard keyboard) { + final KeyDetector keyDetector = new KeyDetector(0); + keyDetector.setKeyboard(keyboard, 0, 0); + keyDetector.setProximityCorrectionEnabled(true); + keyDetector.setProximityThreshold(keyboard.mMostCommonKeyWidth); + setComposingWord(word, keyboard, keyDetector); + } + /** * Swaps the first and second values in the codes array if the primary code is not the first * value in the array but the second. This happens when the preferred key is not the key that diff --git a/tests/src/com/android/inputmethod/latin/SuggestHelper.java b/tests/src/com/android/inputmethod/latin/SuggestHelper.java index 464930f4c..a1f16c9ca 100644 --- a/tests/src/com/android/inputmethod/latin/SuggestHelper.java +++ b/tests/src/com/android/inputmethod/latin/SuggestHelper.java @@ -65,26 +65,9 @@ public class SuggestHelper { return mSuggest.hasMainDictionary(); } - private void addKeyInfo(WordComposer word, char c) { - for (final Key key : mKeyboard.mKeys) { - if (key.mCode == c) { - final int x = key.mX + key.mWidth / 2; - final int y = key.mY + key.mHeight / 2; - final int[] codes = mKeyDetector.newCodeArray(); - mKeyDetector.getKeyIndexAndNearbyCodes(x, y, codes); - word.add(c, codes, x, y); - return; - } - } - word.add(c, new int[] { c }, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); - } - protected WordComposer createWordComposer(CharSequence s) { WordComposer word = new WordComposer(); - for (int i = 0; i < s.length(); i++) { - final char c = s.charAt(i); - addKeyInfo(word, c); - } + word.setComposingWord(s, mKeyboard, mKeyDetector); return word; } -- cgit v1.2.3-83-g751a From e22baaadd314c80f835e2e96fb0dfc73838ac2cd Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Tue, 29 Nov 2011 16:56:27 +0900 Subject: Get rid of usage of key index Change-Id: I7596ce3ae52fde436d06c2dd95ae873c7aa5ef7f --- .../accessibility/AccessibleKeyboardViewProxy.java | 22 +- java/src/com/android/inputmethod/keyboard/Key.java | 8 + .../android/inputmethod/keyboard/KeyDetector.java | 37 ++-- .../android/inputmethod/keyboard/KeyboardView.java | 19 +- .../inputmethod/keyboard/LatinKeyboardView.java | 31 +-- .../inputmethod/keyboard/MoreKeysDetector.java | 23 +-- .../inputmethod/keyboard/PointerTracker.java | 225 +++++++++------------ .../android/inputmethod/latin/WordComposer.java | 2 +- .../android/inputmethod/latin/SuggestHelper.java | 1 - 9 files changed, 172 insertions(+), 196 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java index cef82267f..4cb2f20b9 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java @@ -29,7 +29,6 @@ import android.view.inputmethod.EditorInfo; import com.android.inputmethod.compat.AccessibilityEventCompatUtils; import com.android.inputmethod.compat.MotionEventCompatUtils; import com.android.inputmethod.keyboard.Key; -import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.LatinKeyboardView; import com.android.inputmethod.keyboard.PointerTracker; @@ -42,7 +41,7 @@ public class AccessibleKeyboardViewProxy { private LatinKeyboardView mView; private AccessibleKeyboardActionListener mListener; - private int mLastHoverKeyIndex = KeyDetector.NOT_A_KEY; + private Key mLastHoverKey = null; public static void init(InputMethodService inputMethod, SharedPreferences prefs) { sInstance.initInternal(inputMethod, prefs); @@ -81,7 +80,7 @@ public class AccessibleKeyboardViewProxy { switch (event.getEventType()) { case AccessibilityEventCompatUtils.TYPE_VIEW_HOVER_ENTER: - final Key key = tracker.getKey(mLastHoverKeyIndex); + final Key key = mLastHoverKey; if (key == null) break; @@ -130,12 +129,12 @@ public class AccessibleKeyboardViewProxy { switch (event.getAction()) { case MotionEventCompatUtils.ACTION_HOVER_ENTER: case MotionEventCompatUtils.ACTION_HOVER_MOVE: - final int keyIndex = tracker.getKeyIndexOn(x, y); + final Key key = tracker.getKeyOn(x, y); - if (keyIndex != mLastHoverKeyIndex) { - fireKeyHoverEvent(tracker, mLastHoverKeyIndex, false); - mLastHoverKeyIndex = keyIndex; - fireKeyHoverEvent(tracker, mLastHoverKeyIndex, true); + if (key != mLastHoverKey) { + fireKeyHoverEvent(tracker, mLastHoverKey, false); + mLastHoverKey = key; + fireKeyHoverEvent(tracker, mLastHoverKey, true); } return true; @@ -144,7 +143,7 @@ public class AccessibleKeyboardViewProxy { return false; } - private void fireKeyHoverEvent(PointerTracker tracker, int keyIndex, boolean entering) { + private void fireKeyHoverEvent(PointerTracker tracker, Key key, boolean entering) { if (mListener == null) { Log.e(TAG, "No accessible keyboard action listener set!"); return; @@ -155,11 +154,6 @@ public class AccessibleKeyboardViewProxy { return; } - if (keyIndex == KeyDetector.NOT_A_KEY) - return; - - final Key key = tracker.getKey(keyIndex); - if (key == null) return; diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index ce5f29d73..84f2be585 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -318,6 +318,14 @@ public class Key { return false; } + public boolean isShift() { + return mCode == Keyboard.CODE_SHIFT; + } + + public boolean isModifier() { + return mCode == Keyboard.CODE_SHIFT || mCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL; + } + public boolean isRepeatable() { return (mActionFlags & ACTION_FLAGS_IS_REPEATABLE) != 0; } diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index 3298c41cf..4b708a771 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -26,7 +26,7 @@ public class KeyDetector { private static final boolean DEBUG = false; public static final int NOT_A_CODE = -1; - public static final int NOT_A_KEY = -1; + private static final int NOT_A_KEY = -1; private final int mKeyHysteresisDistanceSquared; @@ -96,22 +96,22 @@ public class KeyDetector { } /** - * Computes maximum size of the array that can contain all nearby key indices returned by - * {@link #getKeyIndexAndNearbyCodes}. + * Computes maximum size of the array that can contain all nearby key codes returned by + * {@link #getKeyAndNearbyCodes}. * - * @return Returns maximum size of the array that can contain all nearby key indices returned - * by {@link #getKeyIndexAndNearbyCodes}. + * @return Returns maximum size of the array that can contain all nearby key codes returned + * by {@link #getKeyAndNearbyCodes}. */ protected int getMaxNearbyKeys() { return MAX_NEARBY_KEYS; } /** - * Allocates array that can hold all key indices returned by {@link #getKeyIndexAndNearbyCodes} + * Allocates array that can hold all key codes returned by {@link #getKeyAndNearbyCodes} * method. The maximum size of the array should be computed by {@link #getMaxNearbyKeys}. * - * @return Allocates and returns an array that can hold all key indices returned by - * {@link #getKeyIndexAndNearbyCodes} method. All elements in the returned array are + * @return Allocates and returns an array that can hold all key codes returned by + * {@link #getKeyAndNearbyCodes} method. All elements in the returned array are * initialized by {@link #NOT_A_CODE} value. */ public int[] newCodeArray() { @@ -180,31 +180,32 @@ public class KeyDetector { } /** - * Finds all possible nearby key indices around a touch event point and returns the nearest key - * index. The algorithm to determine the nearby keys depends on the threshold set by + * Finds all possible nearby key codes around a touch event point and returns the nearest key. + * The algorithm to determine the nearby keys depends on the threshold set by * {@link #setProximityThreshold(int)} and the mode set by * {@link #setProximityCorrectionEnabled(boolean)}. * * @param x The x-coordinate of a touch point * @param y The y-coordinate of a touch point - * @param allCodes All nearby key code except functional key are returned in this array - * @return The nearest key index + * @param allCodes All nearby key codes except functional key are returned in this array + * @return The nearest key */ - public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) { + public Key getKeyAndNearbyCodes(int x, int y, final int[] allCodes) { final List keys = getKeyboard().mKeys; final int touchX = getTouchX(x); final int touchY = getTouchY(y); initializeNearbyKeys(); - int primaryIndex = NOT_A_KEY; + Key primaryKey = null; for (final int index : mKeyboard.getNearestKeys(touchX, touchY)) { final Key key = keys.get(index); final boolean isOnKey = key.isOnKey(touchX, touchY); final int distance = key.squaredDistanceToEdge(touchX, touchY); if (isOnKey || (mProximityCorrectOn && distance < mProximityThresholdSquare)) { final int insertedPosition = sortNearbyKeys(index, distance, isOnKey); - if (insertedPosition == 0 && isOnKey) - primaryIndex = index; + if (insertedPosition == 0 && isOnKey) { + primaryKey = key; + } } } @@ -213,11 +214,11 @@ public class KeyDetector { if (DEBUG) { Log.d(TAG, "x=" + x + " y=" + y + " primary=" - + (primaryIndex == NOT_A_KEY ? "none" : keys.get(primaryIndex).mCode) + + (primaryKey == null ? "none" : primaryKey.mCode) + " codes=" + Arrays.toString(allCodes)); } } - return primaryIndex; + return primaryKey; } } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 3ce184941..d2741edec 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -148,7 +148,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { final PointerTracker tracker = (PointerTracker) msg.obj; switch (msg.what) { case MSG_SHOW_KEY_PREVIEW: - keyboardView.showKey(msg.arg1, tracker); + keyboardView.showKey(tracker); break; case MSG_DISMISS_KEY_PREVIEW: tracker.getKeyPreviewText().setVisibility(View.INVISIBLE); @@ -156,16 +156,15 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } } - public void showKeyPreview(long delay, int keyIndex, PointerTracker tracker) { + public void showKeyPreview(long delay, PointerTracker tracker) { removeMessages(MSG_SHOW_KEY_PREVIEW); final KeyboardView keyboardView = getOuterInstance(); if (keyboardView == null) return; if (tracker.getKeyPreviewText().getVisibility() == VISIBLE || delay == 0) { // Show right away, if it's already visible and finger is moving around - keyboardView.showKey(keyIndex, tracker); + keyboardView.showKey(tracker); } else { - sendMessageDelayed( - obtainMessage(MSG_SHOW_KEY_PREVIEW, keyIndex, 0, tracker), delay); + sendMessageDelayed(obtainMessage(MSG_SHOW_KEY_PREVIEW, tracker), delay); } } @@ -830,9 +829,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } @Override - public void showKeyPreview(int keyIndex, PointerTracker tracker) { + public void showKeyPreview(PointerTracker tracker) { if (mShowKeyPreviewPopup) { - mDrawingHandler.showKeyPreview(mDelayBeforePreview, keyIndex, tracker); + mDrawingHandler.showKeyPreview(mDelayBeforePreview, tracker); } } @@ -858,7 +857,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { keyPreview, FrameLayoutCompatUtils.newLayoutParam(mPreviewPlacer, 0, 0)); } - private void showKey(final int keyIndex, PointerTracker tracker) { + private void showKey(PointerTracker tracker) { final TextView previewText = tracker.getKeyPreviewText(); // If the key preview has no parent view yet, add it to the ViewGroup which can place // key preview absolutely in SoftInputWindow. @@ -867,8 +866,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } mDrawingHandler.cancelDismissKeyPreview(tracker); - final Key key = tracker.getKey(keyIndex); - // If keyIndex is invalid or IME is already closed, we must not show key preview. + final Key key = tracker.getKey(); + // If key is invalid or IME is already closed, we must not show key preview. // Trying to show key preview while root window is closed causes // WindowManager.BadTokenException. if (key == null) diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 60631e867..9ddf40119 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -74,7 +74,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke private final boolean mHasDistinctMultitouch; private int mOldPointerCount = 1; - private int mOldKeyIndex; + private Key mOldKey; private final boolean mConfigShowMiniKeyboardAtTouchedPoint; protected KeyDetector mKeyDetector; @@ -103,19 +103,19 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke final PointerTracker tracker = (PointerTracker) msg.obj; switch (msg.what) { case MSG_REPEAT_KEY: - tracker.onRepeatKey(msg.arg1); - startKeyRepeatTimer(keyboardView.mKeyRepeatInterval, msg.arg1, tracker); + tracker.onRepeatKey(tracker.getKey()); + startKeyRepeatTimer(keyboardView.mKeyRepeatInterval, tracker); break; case MSG_LONGPRESS_KEY: - keyboardView.openMiniKeyboardIfRequired(msg.arg1, tracker); + keyboardView.openMiniKeyboardIfRequired(tracker.getKey(), tracker); break; } } @Override - public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) { + public void startKeyRepeatTimer(long delay, PointerTracker tracker) { mInKeyRepeat = true; - sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, keyIndex, 0, tracker), delay); + sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, tracker), delay); } public void cancelKeyRepeatTimer() { @@ -128,9 +128,9 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } @Override - public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) { + public void startLongPressTimer(long delay, PointerTracker tracker) { cancelLongPressTimer(); - sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, keyIndex, 0, tracker), delay); + sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, tracker), delay); } @Override @@ -181,8 +181,9 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke final int pointerIndex = firstDown.getActionIndex(); final int id = firstDown.getPointerId(pointerIndex); final PointerTracker tracker = getPointerTracker(id); + final Key key = tracker.getKeyOn((int)firstDown.getX(), (int)firstDown.getY()); // If the first down event is on shift key. - if (tracker.isOnShiftKey((int) firstDown.getX(), (int) firstDown.getY())) { + if (key != null && key.isShift()) { mProcessingShiftDoubleTapEvent = true; return true; } @@ -199,8 +200,9 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke final int pointerIndex = secondDown.getActionIndex(); final int id = secondDown.getPointerId(pointerIndex); final PointerTracker tracker = getPointerTracker(id); + final Key key = tracker.getKeyOn((int)secondDown.getX(), (int)secondDown.getY()); // If the second down event is also on shift key. - if (tracker.isOnShiftKey((int) secondDown.getX(), (int) secondDown.getY())) { + if (key != null && key.isShift()) { // Detected a double tap on shift key. If we are in the ignoring double tap // mode, it means we have already turned off caps lock in // {@link KeyboardSwitcher#onReleaseShift} . @@ -326,7 +328,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke super.cancelAllMessages(); } - private boolean openMiniKeyboardIfRequired(int keyIndex, PointerTracker tracker) { + private boolean openMiniKeyboardIfRequired(Key parentKey, PointerTracker tracker) { // Check if we have a popup layout specified first. if (mMoreKeysLayout == 0) { return false; @@ -335,7 +337,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke // Check if we are already displaying popup panel. if (mMoreKeysPanel != null) return false; - final Key parentKey = tracker.getKey(keyIndex); if (parentKey == null) return false; return onLongPress(parentKey, tracker); @@ -546,8 +547,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke // Multi-touch to single touch transition. // Send a down event for the latest pointer if the key is different from the // previous key. - final int newKeyIndex = tracker.getKeyIndexOn(x, y); - if (mOldKeyIndex != newKeyIndex) { + final Key newKey = tracker.getKeyOn(x, y); + if (mOldKey != newKey) { tracker.onDownEvent(x, y, eventTime, this); if (action == MotionEvent.ACTION_UP) tracker.onUpEvent(x, y, eventTime); @@ -557,7 +558,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke // Send an up event for the last pointer. final int lastX = tracker.getLastX(); final int lastY = tracker.getLastY(); - mOldKeyIndex = tracker.getKeyIndexOn(lastX, lastY); + mOldKey = tracker.getKeyOn(lastX, lastY); tracker.onUpEvent(lastX, lastY, eventTime); } else if (pointerCount == 1 && oldPointerCount == 1) { tracker.processMotionEvent(action, x, y, eventTime, this); diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java index d20204611..742ee98d7 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java @@ -16,8 +16,6 @@ package com.android.inputmethod.keyboard; -import java.util.List; - public class MoreKeysDetector extends KeyDetector { private final int mSlideAllowanceSquare; private final int mSlideAllowanceSquareTop; @@ -41,24 +39,23 @@ public class MoreKeysDetector extends KeyDetector { } @Override - public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) { - final List keys = getKeyboard().mKeys; + public Key getKeyAndNearbyCodes(int x, int y, final int[] allCodes) { final int touchX = getTouchX(x); final int touchY = getTouchY(y); - int nearestIndex = NOT_A_KEY; + Key nearestKey = null; int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare; - final int keyCount = keys.size(); - for (int index = 0; index < keyCount; index++) { - final int dist = keys.get(index).squaredDistanceToEdge(touchX, touchY); + for (final Key key : getKeyboard().mKeys) { + final int dist = key.squaredDistanceToEdge(touchX, touchY); if (dist < nearestDist) { - nearestIndex = index; + nearestKey = key; nearestDist = dist; } } - if (allCodes != null && nearestIndex != NOT_A_KEY) - allCodes[0] = keys.get(nearestIndex).mCode; - return nearestIndex; + if (allCodes != null && nearestKey != null) { + allCodes[0] = nearestKey.mCode; + } + return nearestKey; } -} \ No newline at end of file +} diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index f7a0d97ae..da60af3be 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -68,7 +68,7 @@ public class PointerTracker { public interface DrawingProxy extends MoreKeysPanel.Controller { public void invalidateKey(Key key); public TextView inflateKeyPreviewText(); - public void showKeyPreview(int keyIndex, PointerTracker tracker); + public void showKeyPreview(PointerTracker tracker); public void cancelShowKeyPreview(PointerTracker tracker); public void dismissKeyPreview(PointerTracker tracker); } @@ -76,8 +76,8 @@ public class PointerTracker { public interface TimerProxy { public void startKeyTypedTimer(long delay); public boolean isTyping(); - public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker); - public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker); + public void startKeyRepeatTimer(long delay, PointerTracker tracker); + public void startLongPressTimer(long delay, PointerTracker tracker); public void cancelLongPressTimer(); public void cancelKeyTimers(); @@ -87,9 +87,9 @@ public class PointerTracker { @Override public boolean isTyping() { return false; } @Override - public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) {} + public void startKeyRepeatTimer(long delay, PointerTracker tracker) {} @Override - public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) {} + public void startLongPressTimer(long delay, PointerTracker tracker) {} @Override public void cancelLongPressTimer() {} @Override @@ -127,9 +127,9 @@ public class PointerTracker { private long mDownTime; private long mUpTime; - // The current key index where this pointer is. - private int mKeyIndex = KeyDetector.NOT_A_KEY; - // The position where mKeyIndex was recognized for the first time. + // The current key where this pointer is. + private Key mCurrentKey = null; + // The position where the current key was recognized for the first time. private int mKeyX; private int mKeyY; @@ -217,7 +217,7 @@ public class PointerTracker { public static void dismissAllKeyPreviews() { for (final PointerTracker tracker : sTrackers) { - tracker.setReleasedKeyGraphics(tracker.mKeyIndex); + tracker.setReleasedKeyGraphics(tracker.mCurrentKey); } } @@ -238,7 +238,7 @@ public class PointerTracker { // Returns true if keyboard has been changed by this callback. private boolean callListenerOnPressAndCheckKeyboardLayoutChange(Key key, boolean withSliding) { - final boolean ignoreModifierKey = mIgnoreModifierKey && isModifierCode(key.mCode); + final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); if (DEBUG_LISTENER) Log.d(TAG, "onPress : " + keyCodePrintable(key.mCode) + " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey); @@ -257,13 +257,14 @@ public class PointerTracker { // Note that we need primaryCode argument because the keyboard may in shifted state and the // primaryCode is different from {@link Key#mCode}. private void callListenerOnCodeInput(Key key, int primaryCode, int[] keyCodes, int x, int y) { - final boolean ignoreModifierKey = mIgnoreModifierKey && isModifierCode(key.mCode); + final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); if (DEBUG_LISTENER) Log.d(TAG, "onCodeInput: " + keyCodePrintable(primaryCode) + " codes="+ Arrays.toString(keyCodes) + " x=" + x + " y=" + y + " ignoreModifier=" + ignoreModifierKey); - if (ignoreModifierKey) + if (ignoreModifierKey) { return; + } if (key.isEnabled()) { mListener.onCodeInput(primaryCode, keyCodes, x, y); } @@ -280,12 +281,13 @@ public class PointerTracker { // Note that we need primaryCode argument because the keyboard may in shifted state and the // primaryCode is different from {@link Key#mCode}. private void callListenerOnRelease(Key key, int primaryCode, boolean withSliding) { - final boolean ignoreModifierKey = mIgnoreModifierKey && isModifierCode(key.mCode); + final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); if (DEBUG_LISTENER) Log.d(TAG, "onRelease : " + keyCodePrintable(primaryCode) + " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey); - if (ignoreModifierKey) + if (ignoreModifierKey) { return; + } if (key.isEnabled()) { mListener.onRelease(primaryCode, withSliding); } @@ -309,55 +311,30 @@ public class PointerTracker { return mIsInSlidingKeyInput; } - private boolean isValidKeyIndex(int keyIndex) { - return keyIndex >= 0 && keyIndex < mKeys.size(); - } - - public Key getKey(int keyIndex) { - return isValidKeyIndex(keyIndex) ? mKeys.get(keyIndex) : null; - } - - private static boolean isModifierCode(int primaryCode) { - return primaryCode == Keyboard.CODE_SHIFT - || primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL; - } - - private boolean isModifierInternal(int keyIndex) { - final Key key = getKey(keyIndex); - return key == null ? false : isModifierCode(key.mCode); + public Key getKey() { + return mCurrentKey; } public boolean isModifier() { - return isModifierInternal(mKeyIndex); + return mCurrentKey != null && mCurrentKey.isModifier(); } - private boolean isOnModifierKey(int x, int y) { - return isModifierInternal(mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null)); + public Key getKeyOn(int x, int y) { + return mKeyDetector.getKeyAndNearbyCodes(x, y, null); } - public boolean isOnShiftKey(int x, int y) { - final Key key = getKey(mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null)); - return key != null && key.mCode == Keyboard.CODE_SHIFT; - } - - public int getKeyIndexOn(int x, int y) { - return mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); - } - - private void setReleasedKeyGraphics(int keyIndex) { + private void setReleasedKeyGraphics(Key key) { mDrawingProxy.dismissKeyPreview(this); - final Key key = getKey(keyIndex); if (key != null && key.isEnabled()) { key.onReleased(); mDrawingProxy.invalidateKey(key); } } - private void setPressedKeyGraphics(int keyIndex) { - final Key key = getKey(keyIndex); + private void setPressedKeyGraphics(Key key) { if (key != null && key.isEnabled()) { if (!key.noKeyPreview()) { - mDrawingProxy.showKeyPreview(keyIndex, this); + mDrawingProxy.showKeyPreview(this); } key.onPressed(); mDrawingProxy.invalidateKey(key); @@ -376,31 +353,31 @@ public class PointerTracker { return mDownTime; } - private int onDownKey(int x, int y, long eventTime) { + private Key onDownKey(int x, int y, long eventTime) { mDownTime = eventTime; return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); } - private int onMoveKeyInternal(int x, int y) { + private Key onMoveKeyInternal(int x, int y) { mLastX = x; mLastY = y; - return mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); + return mKeyDetector.getKeyAndNearbyCodes(x, y, null); } - private int onMoveKey(int x, int y) { + private Key onMoveKey(int x, int y) { return onMoveKeyInternal(x, y); } - private int onMoveToNewKey(int keyIndex, int x, int y) { - mKeyIndex = keyIndex; + private Key onMoveToNewKey(Key newKey, int x, int y) { + mCurrentKey = newKey; mKeyX = x; mKeyY = y; - return keyIndex; + return newKey; } - private int onUpKey(int x, int y, long eventTime) { + private Key onUpKey(int x, int y, long eventTime) { mUpTime = eventTime; - mKeyIndex = KeyDetector.NOT_A_KEY; + mCurrentKey = null; return onMoveKeyInternal(x, y); } @@ -449,7 +426,8 @@ public class PointerTracker { final PointerTrackerQueue queue = sPointerTrackerQueue; if (queue != null) { - if (isOnModifierKey(x, y)) { + final Key key = getKeyOn(x, y); + if (key != null && key.isModifier()) { // Before processing a down event of modifier key, all pointers already being // tracked should be released. queue.releaseAllPointers(eventTime); @@ -460,32 +438,34 @@ public class PointerTracker { } private void onDownEventInternal(int x, int y, long eventTime) { - int keyIndex = onDownKey(x, y, eventTime); + Key key = onDownKey(x, y, eventTime); // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding // from modifier key, or 3) this pointer's KeyDetector always allows sliding input. - mIsAllowedSlidingKeyInput = sConfigSlidingKeyInputEnabled || isModifierInternal(keyIndex) + mIsAllowedSlidingKeyInput = sConfigSlidingKeyInputEnabled || key.isModifier() || mKeyDetector.alwaysAllowsSlidingInput(); mKeyboardLayoutHasBeenChanged = false; mKeyAlreadyProcessed = false; mIsRepeatableKey = false; mIsInSlidingKeyInput = false; mIgnoreModifierKey = false; - if (isValidKeyIndex(keyIndex)) { + if (key != null) { // This onPress call may have changed keyboard layout. Those cases are detected at - // {@link #setKeyboard}. In those cases, we should update keyIndex according to the new + // {@link #setKeyboard}. In those cases, we should update key according to the new // keyboard layout. - if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), false)) - keyIndex = onDownKey(x, y, eventTime); + if (callListenerOnPressAndCheckKeyboardLayoutChange(key, false)) { + key = onDownKey(x, y, eventTime); + } - startRepeatKey(keyIndex); - startLongPressTimer(keyIndex); - setPressedKeyGraphics(keyIndex); + startRepeatKey(key); + startLongPressTimer(key); + setPressedKeyGraphics(key); } } private void startSlidingKeyInput(Key key) { - if (!mIsInSlidingKeyInput) - mIgnoreModifierKey = isModifierCode(key.mCode); + if (!mIsInSlidingKeyInput) { + mIgnoreModifierKey = key.isModifier(); + } mIsInSlidingKeyInput = true; } @@ -497,39 +477,40 @@ public class PointerTracker { final int lastX = mLastX; final int lastY = mLastY; - final int oldKeyIndex = mKeyIndex; - final Key oldKey = getKey(oldKeyIndex); - int keyIndex = onMoveKey(x, y); - if (isValidKeyIndex(keyIndex)) { + final Key oldKey = mCurrentKey; + Key key = onMoveKey(x, y); + if (key != null) { if (oldKey == null) { // The pointer has been slid in to the new key, but the finger was not on any keys. // In this case, we must call onPress() to notify that the new key is being pressed. // This onPress call may have changed keyboard layout. Those cases are detected at - // {@link #setKeyboard}. In those cases, we should update keyIndex according to the + // {@link #setKeyboard}. In those cases, we should update key according to the // new keyboard layout. - if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), true)) - keyIndex = onMoveKey(x, y); - onMoveToNewKey(keyIndex, x, y); - startLongPressTimer(keyIndex); - setPressedKeyGraphics(keyIndex); - } else if (isMajorEnoughMoveToBeOnNewKey(x, y, keyIndex)) { + if (callListenerOnPressAndCheckKeyboardLayoutChange(key, true)) { + key = onMoveKey(x, y); + } + onMoveToNewKey(key, x, y); + startLongPressTimer(key); + setPressedKeyGraphics(key); + } else if (isMajorEnoughMoveToBeOnNewKey(x, y, key)) { // The pointer has been slid in to the new key from the previous key, we must call // onRelease() first to notify that the previous key has been released, then call // onPress() to notify that the new key is being pressed. - setReleasedKeyGraphics(oldKeyIndex); + setReleasedKeyGraphics(oldKey); callListenerOnRelease(oldKey, oldKey.mCode, true); startSlidingKeyInput(oldKey); mTimerProxy.cancelKeyTimers(); - startRepeatKey(keyIndex); + startRepeatKey(key); if (mIsAllowedSlidingKeyInput) { // This onPress call may have changed keyboard layout. Those cases are detected - // at {@link #setKeyboard}. In those cases, we should update keyIndex according + // at {@link #setKeyboard}. In those cases, we should update key according // to the new keyboard layout. - if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), true)) - keyIndex = onMoveKey(x, y); - onMoveToNewKey(keyIndex, x, y); - startLongPressTimer(keyIndex); - setPressedKeyGraphics(keyIndex); + if (callListenerOnPressAndCheckKeyboardLayoutChange(key, true)) { + key = onMoveKey(x, y); + } + onMoveToNewKey(key, x, y); + startLongPressTimer(key); + setPressedKeyGraphics(key); } else { // HACK: On some devices, quick successive touches may be translated to sudden // move by touch panel firmware. This hack detects the case and translates the @@ -545,20 +526,20 @@ public class PointerTracker { onDownEventInternal(x, y, eventTime); } else { mKeyAlreadyProcessed = true; - setReleasedKeyGraphics(oldKeyIndex); + setReleasedKeyGraphics(oldKey); } } } } else { - if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, keyIndex)) { + if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, key)) { // The pointer has been slid out from the previous key, we must call onRelease() to // notify that the previous key has been released. - setReleasedKeyGraphics(oldKeyIndex); + setReleasedKeyGraphics(oldKey); callListenerOnRelease(oldKey, oldKey.mCode, true); startSlidingKeyInput(oldKey); mTimerProxy.cancelLongPressTimer(); if (mIsAllowedSlidingKeyInput) { - onMoveToNewKey(keyIndex, x, y); + onMoveToNewKey(key, x, y); } else { mKeyAlreadyProcessed = true; } @@ -572,7 +553,7 @@ public class PointerTracker { final PointerTrackerQueue queue = sPointerTrackerQueue; if (queue != null) { - if (isModifier()) { + if (mCurrentKey != null && mCurrentKey.isModifier()) { // Before processing an up event of modifier key, all pointers already being // tracked should be released. queue.releaseAllPointersExcept(this, eventTime); @@ -607,8 +588,8 @@ public class PointerTracker { keyX = mKeyX; keyY = mKeyY; } - final int keyIndex = onUpKey(keyX, keyY, eventTime); - setReleasedKeyGraphics(keyIndex); + final Key key = onUpKey(keyX, keyY, eventTime); + setReleasedKeyGraphics(key); if (mIsShowingMoreKeysPanel) { mDrawingProxy.dismissMoreKeysPanel(); mIsShowingMoreKeysPanel = false; @@ -616,7 +597,7 @@ public class PointerTracker { if (mKeyAlreadyProcessed) return; if (!mIsRepeatableKey) { - detectAndSendKey(keyIndex, keyX, keyY); + detectAndSendKey(key, keyX, keyY); } } @@ -628,7 +609,7 @@ public class PointerTracker { public void onLongPressed() { mKeyAlreadyProcessed = true; - setReleasedKeyGraphics(mKeyIndex); + setReleasedKeyGraphics(mCurrentKey); final PointerTrackerQueue queue = sPointerTrackerQueue; if (queue != null) { queue.remove(this); @@ -650,7 +631,7 @@ public class PointerTracker { private void onCancelEventInternal() { mTimerProxy.cancelKeyTimers(); mDrawingProxy.cancelShowKeyPreview(this); - setReleasedKeyGraphics(mKeyIndex); + setReleasedKeyGraphics(mCurrentKey); mIsInSlidingKeyInput = false; if (mIsShowingMoreKeysPanel) { mDrawingProxy.dismissMoreKeysPanel(); @@ -658,48 +639,45 @@ public class PointerTracker { } } - private void startRepeatKey(int keyIndex) { - final Key key = getKey(keyIndex); + private void startRepeatKey(Key key) { if (key != null && key.isRepeatable()) { - onRepeatKey(keyIndex); - mTimerProxy.startKeyRepeatTimer(sDelayBeforeKeyRepeatStart, keyIndex, this); + onRepeatKey(key); + mTimerProxy.startKeyRepeatTimer(sDelayBeforeKeyRepeatStart, this); mIsRepeatableKey = true; } else { mIsRepeatableKey = false; } } - public void onRepeatKey(int keyIndex) { - Key key = getKey(keyIndex); + public void onRepeatKey(Key key) { if (key != null) { - detectAndSendKey(keyIndex, key.mX, key.mY); + detectAndSendKey(key, key.mX, key.mY); } } - private boolean isMajorEnoughMoveToBeOnNewKey(int x, int y, int newKey) { + private boolean isMajorEnoughMoveToBeOnNewKey(int x, int y, Key newKey) { if (mKeys == null || mKeyDetector == null) throw new NullPointerException("keyboard and/or key detector not set"); - int curKey = mKeyIndex; + Key curKey = mCurrentKey; if (newKey == curKey) { return false; - } else if (isValidKeyIndex(curKey)) { - return mKeys.get(curKey).squaredDistanceToEdge(x, y) + } else if (curKey != null) { + return curKey.squaredDistanceToEdge(x, y) >= mKeyDetector.getKeyHysteresisDistanceSquared(); } else { return true; } } - private void startLongPressTimer(int keyIndex) { - Key key = getKey(keyIndex); + private void startLongPressTimer(Key key) { if (key == null) return; if (key.mCode == Keyboard.CODE_SHIFT) { if (sLongPressShiftKeyTimeout > 0) { - mTimerProxy.startLongPressTimer(sLongPressShiftKeyTimeout, keyIndex, this); + mTimerProxy.startLongPressTimer(sLongPressShiftKeyTimeout, this); } } else if (key.mCode == Keyboard.CODE_SPACE) { if (sLongPressSpaceKeyTimeout > 0) { - mTimerProxy.startLongPressTimer(sLongPressSpaceKeyTimeout, keyIndex, this); + mTimerProxy.startLongPressTimer(sLongPressSpaceKeyTimeout, this); } } else if (key.hasUppercaseLetter() && mKeyboard.isManualTemporaryUpperCase()) { // We need not start long press timer on the key which has manual temporary upper case @@ -707,14 +685,13 @@ public class PointerTracker { return; } else if (sKeyboardSwitcher.isInMomentarySwitchState()) { // We use longer timeout for sliding finger input started from the symbols mode key. - mTimerProxy.startLongPressTimer(sLongPressKeyTimeout * 3, keyIndex, this); + mTimerProxy.startLongPressTimer(sLongPressKeyTimeout * 3, this); } else { - mTimerProxy.startLongPressTimer(sLongPressKeyTimeout, keyIndex, this); + mTimerProxy.startLongPressTimer(sLongPressKeyTimeout, this); } } - private void detectAndSendKey(int keyIndex, int x, int y) { - final Key key = getKey(keyIndex); + private void detectAndSendKey(Key key, int x, int y) { if (key == null) { callListenerOnCancelInput(); return; @@ -731,7 +708,7 @@ public class PointerTracker { } else { int code = key.mCode; final int[] codes = mKeyDetector.newCodeArray(); - mKeyDetector.getKeyIndexAndNearbyCodes(x, y, codes); + mKeyDetector.getKeyAndNearbyCodes(x, y, codes); // If keyboard is in manual temporary upper case state and key has manual temporary // uppercase letter as key hint letter, alternate character code should be sent. @@ -754,7 +731,7 @@ public class PointerTracker { callListenerOnCodeInput(key, code, codes, x, y); } callListenerOnRelease(key, code, false); - if (!key.ignoreWhileTyping() && !isModifierCode(code)) { + if (!key.ignoreWhileTyping() && !key.isModifier()) { mTimerProxy.startKeyTypedTimer(sIgnoreSpecialKeyTimeout); } } @@ -763,17 +740,17 @@ public class PointerTracker { private long mPreviousEventTime; private void printTouchEvent(String title, int x, int y, long eventTime) { - final int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); - final Key key = getKey(keyIndex); + final Key key = mKeyDetector.getKeyAndNearbyCodes(x, y, null); final String code = (key == null) ? "----" : keyCodePrintable(key.mCode); final long delta = eventTime - mPreviousEventTime; - Log.d(TAG, String.format("%s%s[%d] %4d %4d %5d %3d(%s)", title, - (mKeyAlreadyProcessed ? "-" : " "), mPointerId, x, y, delta, keyIndex, code)); + Log.d(TAG, String.format("%s%s[%d] %4d %4d %5d %s", title, + (mKeyAlreadyProcessed ? "-" : " "), mPointerId, x, y, delta, code)); mPreviousEventTime = eventTime; } private static String keyCodePrintable(int primaryCode) { - final String modifier = isModifierCode(primaryCode) ? " modifier" : ""; - return String.format((primaryCode < 0) ? "%4d" : "0x%02x", primaryCode) + modifier; + if (primaryCode < 0) return String.format("%4d", primaryCode); + if (primaryCode < 0x100) return String.format("\\u%02x", primaryCode); + return String.format("\\u04x", primaryCode); } } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index c9314ee50..44c89f73c 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -152,7 +152,7 @@ public class WordComposer { final int x = key.mX + key.mWidth / 2; final int y = key.mY + key.mHeight / 2; final int[] codes = keyDetector.newCodeArray(); - keyDetector.getKeyIndexAndNearbyCodes(x, y, codes); + keyDetector.getKeyAndNearbyCodes(x, y, codes); add(codePoint, codes, x, y); return; } diff --git a/tests/src/com/android/inputmethod/latin/SuggestHelper.java b/tests/src/com/android/inputmethod/latin/SuggestHelper.java index a1f16c9ca..0d90e0ef3 100644 --- a/tests/src/com/android/inputmethod/latin/SuggestHelper.java +++ b/tests/src/com/android/inputmethod/latin/SuggestHelper.java @@ -19,7 +19,6 @@ package com.android.inputmethod.latin; import android.content.Context; import android.text.TextUtils; -import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.LatinKeyboard; -- cgit v1.2.3-83-g751a From 3651220327c051d8017045aa5e8919461507b3f8 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 9 Dec 2011 23:15:49 +0900 Subject: Remove a duplicated variable. This is awesome cleanup. Change-Id: I35ce8940a13f3084630dc26d6e7e397acfdaac36 --- .../com/android/inputmethod/latin/LatinIME.java | 56 ++++++++++------------ .../android/inputmethod/latin/TextEntryState.java | 5 +- .../android/inputmethod/latin/WordComposer.java | 3 -- 3 files changed, 27 insertions(+), 37 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 5d075b175..c47cae160 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -203,7 +203,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private boolean mIsSettingsSuggestionStripOn; private boolean mApplicationSpecifiedCompletionOn; - private final StringBuilder mComposingStringBuilder = new StringBuilder(); private WordComposer mWordComposer = new WordComposer(); private CharSequence mBestWord; private boolean mHasUncommittedTypedChars; @@ -756,7 +755,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar inputView.closing(); mEnteredText = null; - mComposingStringBuilder.setLength(0); + mWordComposer.reset(); mHasUncommittedTypedChars = false; mDeleteCount = 0; mSpaceState = SPACE_STATE_NONE; @@ -928,10 +927,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // newly inserted punctuation. mSpaceState = SPACE_STATE_NONE; } - if (((mComposingStringBuilder.length() > 0 && mHasUncommittedTypedChars) + if (((mWordComposer.size() > 0 && mHasUncommittedTypedChars) || mVoiceProxy.isVoiceInputHighlighted()) && (selectionChanged || candidatesCleared)) { - mComposingStringBuilder.setLength(0); + mWordComposer.reset(); mHasUncommittedTypedChars = false; TextEntryState.reset(); updateSuggestions(); @@ -1146,13 +1145,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public void commitTyped(final InputConnection ic) { if (!mHasUncommittedTypedChars) return; mHasUncommittedTypedChars = false; - if (mComposingStringBuilder.length() > 0) { + final CharSequence typedWord = mWordComposer.getTypedWord(); + if (typedWord.length() > 0) { if (ic != null) { - ic.commitText(mComposingStringBuilder, 1); + ic.commitText(typedWord, 1); } - mCommittedLength = mComposingStringBuilder.length(); - TextEntryState.acceptedTyped(mComposingStringBuilder); - addToUserUnigramAndBigramDictionaries(mComposingStringBuilder, + mCommittedLength = typedWord.length(); + TextEntryState.acceptedTyped(typedWord); + addToUserUnigramAndBigramDictionaries(typedWord, UserUnigramDictionary.FREQUENCY_FOR_TYPED); } updateSuggestions(); @@ -1408,17 +1408,16 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final boolean deleteChar = !mHasUncommittedTypedChars; if (mHasUncommittedTypedChars) { - final int length = mComposingStringBuilder.length(); + final int length = mWordComposer.size(); if (length > 0) { - mComposingStringBuilder.delete(length - 1, length); mWordComposer.deleteLast(); final CharSequence textWithUnderline = mComposingStateManager.isAutoCorrectionIndicatorOn() ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline( - this, mComposingStringBuilder) - : mComposingStringBuilder; + this, mWordComposer.getTypedWord()) + : mWordComposer.getTypedWord(); ic.setComposingText(textWithUnderline, 1); - if (mComposingStringBuilder.length() == 0) { + if (mWordComposer.size() == 0) { mHasUncommittedTypedChars = false; } if (1 == length) { @@ -1521,7 +1520,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Reset entirely the composing state anyway, then start composing a new word unless // the character is a single quote. mHasUncommittedTypedChars = (Keyboard.CODE_SINGLE_QUOTE != code); - mComposingStringBuilder.setLength(0); mWordComposer.reset(); clearSuggestions(); mComposingStateManager.onFinishComposingText(); @@ -1551,7 +1549,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } if (mHasUncommittedTypedChars) { - mComposingStringBuilder.append((char) code); mWordComposer.add(code, keyCodes, x, y); if (ic != null) { // If it's the first letter, make note of auto-caps state @@ -1562,8 +1559,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final CharSequence textWithUnderline = mComposingStateManager.isAutoCorrectionIndicatorOn() ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline( - this, mComposingStringBuilder) - : mComposingStringBuilder; + this, mWordComposer.getTypedWord()) + : mWordComposer.getTypedWord(); ic.setComposingText(textWithUnderline, 1); } mHandler.postUpdateSuggestions(); @@ -1751,8 +1748,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } final CharSequence textWithUnderline = newAutoCorrectionIndicator ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline( - this, mComposingStringBuilder) - : mComposingStringBuilder; + this, mWordComposer.getTypedWord()) + : mWordComposer.getTypedWord(); if (!TextUtils.isEmpty(textWithUnderline)) { ic.setComposingText(textWithUnderline, 1); } @@ -1945,9 +1942,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { addToOnlyBigramDictionary(suggestion, 1); } - LatinImeLogger.logOnManualSuggestion(mComposingStringBuilder.toString(), + LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(), suggestion.toString(), index, suggestions.mWords); - TextEntryState.acceptedSuggestion(mComposingStringBuilder.toString(), suggestion); + TextEntryState.acceptedSuggestion(mWordComposer.getTypedWord().toString(), suggestion); // Follow it with a space if (mInsertSpaceOnPickSuggestionManually) { sendMagicSpace(); @@ -2157,8 +2154,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void restartSuggestionsOnWordBeforeCursor(final InputConnection ic, final CharSequence word) { mWordComposer.setComposingWord(word, mKeyboardSwitcher.getLatinKeyboard()); - mComposingStringBuilder.setLength(0); - mComposingStringBuilder.append(word); // mBestWord will be set appropriately by updateSuggestions() called by the handler mBestWord = null; mHasUncommittedTypedChars = true; @@ -2171,7 +2166,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // "ic" must not be null private void revertLastWord(final InputConnection ic) { - if (mHasUncommittedTypedChars || mComposingStringBuilder.length() <= 0) { + if (mHasUncommittedTypedChars || mWordComposer.size() <= 0) { sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); return; } @@ -2186,21 +2181,19 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // the cursor. if (!TextUtils.isEmpty(separator) && mSettingsValues.isWordSeparator(separator.charAt(0)) - && !TextUtils.equals(mComposingStringBuilder, textToTheLeft)) { - ic.commitText(mComposingStringBuilder, 1); - TextEntryState.acceptedTyped(mComposingStringBuilder); + && !TextUtils.equals(mWordComposer.getTypedWord(), textToTheLeft)) { + ic.commitText(mWordComposer.getTypedWord(), 1); + TextEntryState.acceptedTyped(mWordComposer.getTypedWord()); ic.commitText(separator, 1); TextEntryState.typedCharacter(separator.charAt(0), true, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); - // Clear composing text - mComposingStringBuilder.setLength(0); } else { // Note: this relies on the last word still being held in the WordComposer // Note: in the interest of code simplicity, we may want to just call // restartSuggestionsOnWordBeforeCursorIfAtEndOfWord instead, but retrieving // the old WordComposer allows to reuse the actual typed coordinates. mHasUncommittedTypedChars = true; - ic.setComposingText(mComposingStringBuilder, 1); + ic.setComposingText(mWordComposer.getTypedWord(), 1); TextEntryState.backspace(); } mHandler.cancelUpdateBigramPredictions(); @@ -2479,7 +2472,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final Keyboard keyboard = mKeyboardSwitcher.getLatinKeyboard(); final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1; p.println(" Keyboard mode = " + keyboardMode); - p.println(" mComposingStringBuilder=" + mComposingStringBuilder.toString()); p.println(" mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn); p.println(" mCorrectionMode=" + mCorrectionMode); p.println(" mHasUncommittedTypedChars=" + mHasUncommittedTypedChars); diff --git a/java/src/com/android/inputmethod/latin/TextEntryState.java b/java/src/com/android/inputmethod/latin/TextEntryState.java index a6041b310..6b44fc500 100644 --- a/java/src/com/android/inputmethod/latin/TextEntryState.java +++ b/java/src/com/android/inputmethod/latin/TextEntryState.java @@ -19,6 +19,7 @@ package com.android.inputmethod.latin; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.Utils.RingCharBuffer; +import android.text.TextUtils; import android.util.Log; public class TextEntryState { @@ -45,7 +46,7 @@ public class TextEntryState { public static void acceptedDefault(CharSequence typedWord, CharSequence actualWord, int separatorCode) { - if (typedWord == null) return; + if (TextUtils.isEmpty(typedWord)) return; setState(ACCEPTED_DEFAULT); LatinImeLogger.logOnAutoCorrection( typedWord.toString(), actualWord.toString(), separatorCode); @@ -57,7 +58,7 @@ public class TextEntryState { // (see "case ACCEPTED_DEFAULT" in typedCharacter() below), // and should be restored back to State.ACCEPTED_DEFAULT after processing for each sub-state. public static void backToAcceptedDefault(CharSequence typedWord) { - if (typedWord == null) return; + if (TextUtils.isEmpty(typedWord)) return; switch (sState) { case SPACE_AFTER_ACCEPTED: case PUNCTUATION_AFTER_ACCEPTED: diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 44c89f73c..dfb00c8ab 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -231,9 +231,6 @@ public class WordComposer { * @return the word that was typed so far */ public String getTypedWord() { - if (size() == 0) { - return null; - } return mTypedWord.toString(); } -- cgit v1.2.3-83-g751a From 117fc93f373cb86d4120c1261f9d0562c6529fec Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 13 Dec 2011 19:38:36 +0900 Subject: Move mBestWord to the word composer. mBestWord has a confusing name - it's actually an auto-correction. It's cleaner if it lives in the word composer because an auto-correction should be tied to a specific user input, and should be reset each time the user input changes to avoid race conditions. Change-Id: I718d29395bc747372067e6440e090c6a181994ae --- .../com/android/inputmethod/latin/LatinIME.java | 43 +++++++++++++--------- .../android/inputmethod/latin/WordComposer.java | 31 +++++++++++++++- 2 files changed, 55 insertions(+), 19 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index a8f4e3179..80f6c150d 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -203,7 +203,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private boolean mApplicationSpecifiedCompletionOn; private WordComposer mWordComposer = new WordComposer(); - private CharSequence mBestWord; private boolean mHasUncommittedTypedChars; private int mCorrectionMode; @@ -1019,7 +1018,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar .setHasMinimalSuggestion(false); // When in fullscreen mode, show completions generated by the application setSuggestions(builder.build()); - mBestWord = null; + mWordComposer.deleteAutoCorrection(); setSuggestionStripShown(true); } } @@ -1649,10 +1648,18 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar Utils.Stats.onSeparator((char)primaryCode, x, y); if (pickedDefault) { - CharSequence typedWord = mWordComposer.getTypedWord(); - if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) { + final CharSequence autoCorrection = mWordComposer.getAutoCorrectionOrNull(); + final String typedWord = mWordComposer.getTypedWord(); + if (TextUtils.isEmpty(typedWord)) { + throw new RuntimeException("We have non-committed chars but the typed word " + + "is empty? Impossible! I must commit suicide."); + } + if (!typedWord.equals(autoCorrection)) { + // TODO: if the commitCorrection method is not supported by the platform + // this will do nothing and the correction will not be committed at all. What + // happens on Froyo/Gingerbread, where this API is not present? InputConnectionCompatUtils.commitCorrection( - ic, mLastSelectionEnd - typedWord.length(), typedWord, mBestWord); + ic, mLastSelectionEnd - typedWord.length(), typedWord, autoCorrection); } } mKeyboardSwitcher.updateShiftState(); @@ -1847,14 +1854,15 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar setSuggestions(suggestedWords); if (suggestedWords.size() > 0) { if (shouldBlockAutoCorrectionBySafetyNet) { - mBestWord = typedWord; + mWordComposer.setAutoCorrection(typedWord); } else if (suggestedWords.hasAutoCorrectionWord()) { - mBestWord = suggestedWords.getWord(1); + mWordComposer.setAutoCorrection(suggestedWords.getWord(1)); } else { - mBestWord = typedWord; + mWordComposer.setAutoCorrection(typedWord); } } else { - mBestWord = null; + // TODO: replace with mWordComposer.deleteAutoCorrection()? + mWordComposer.setAutoCorrection(null); } setSuggestionStripShown(isSuggestionsStripVisible()); } @@ -1865,16 +1873,17 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mHandler.cancelUpdateSuggestions(); updateSuggestions(); } - if (mBestWord != null && mBestWord.length() > 0) { - Utils.Stats.onAutoCorrection(mWordComposer.getTypedWord(), mBestWord.toString(), - separatorCode); + final CharSequence autoCorrection = mWordComposer.getAutoCorrectionOrNull(); + if (autoCorrection != null) { + final String typedWord = mWordComposer.getTypedWord(); + Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCode); mExpectingUpdateSelection = true; - commitBestWord(mBestWord); - if (!mBestWord.equals(mWordComposer.getTypedWord())) { - mWordSavedForAutoCorrectCancellation = mBestWord.toString(); + commitBestWord(autoCorrection); + if (!autoCorrection.equals(typedWord)) { + mWordSavedForAutoCorrectCancellation = autoCorrection.toString(); } // Add the word to the user unigram dictionary if it's not a known word - addToUserUnigramAndBigramDictionaries(mBestWord, + addToUserUnigramAndBigramDictionaries(autoCorrection, UserUnigramDictionary.FREQUENCY_FOR_TYPED); return true; } @@ -2153,8 +2162,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void restartSuggestionsOnWordBeforeCursor(final InputConnection ic, final CharSequence word) { mWordComposer.setComposingWord(word, mKeyboardSwitcher.getLatinKeyboard()); - // mBestWord will be set appropriately by updateSuggestions() called by the handler - mBestWord = null; mHasUncommittedTypedChars = true; mComposingStateManager.onStartComposingText(); ic.deleteSurroundingText(word.length(), 0); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index dfb00c8ab..fcaf81cd5 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -41,6 +41,8 @@ public class WordComposer { private int[] mYCoordinates; private StringBuilder mTypedWord; + // An auto-correction for this word out of the dictionary. + private CharSequence mAutoCorrection; private int mCapsCount; @@ -60,6 +62,7 @@ public class WordComposer { mXCoordinates = new int[N]; mYCoordinates = new int[N]; mTrailingSingleQuotesCount = 0; + mAutoCorrection = null; } public WordComposer(WordComposer source) { @@ -75,6 +78,7 @@ public class WordComposer { mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount; + mAutoCorrection = null; } /** @@ -86,6 +90,7 @@ public class WordComposer { mCapsCount = 0; mIsFirstCharCapitalized = false; mTrailingSingleQuotesCount = 0; + mAutoCorrection = null; } /** @@ -140,6 +145,7 @@ public class WordComposer { } else { mTrailingSingleQuotesCount = 0; } + mAutoCorrection = null; } /** @@ -173,6 +179,7 @@ public class WordComposer { int codePoint = word.charAt(i); addKeyInfo(codePoint, keyboard, keyDetector); } + mAutoCorrection = null; } /** @@ -224,11 +231,12 @@ public class WordComposer { ++mTrailingSingleQuotesCount; } } + mAutoCorrection = null; } /** * Returns the word as it was typed, without any correction applied. - * @return the word that was typed so far + * @return the word that was typed so far. Never returns null. */ public String getTypedWord() { return mTypedWord.toString(); @@ -277,4 +285,25 @@ public class WordComposer { public boolean isAutoCapitalized() { return mAutoCapitalized; } + + /** + * Sets the auto-correction for this word. + */ + public void setAutoCorrection(final CharSequence correction) { + mAutoCorrection = correction; + } + + /** + * Remove any auto-correction that may have been set. + */ + public void deleteAutoCorrection() { + mAutoCorrection = null; + } + + /** + * @return the auto-correction for this world, or null if none. + */ + public CharSequence getAutoCorrectionOrNull() { + return mAutoCorrection; + } } -- cgit v1.2.3-83-g751a From f7d6517d6b1a1dd88e2142e1a15703bb839be01b Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 13 Dec 2011 23:08:12 +0900 Subject: Various mini-cleanups - Stop the word composer from escaping - take a page from the law of Demeter and only report what is actually needed. - Fix typos in comments. - Add a comment for a fishy processing. - Remove a useless local variable. Change-Id: I5fa78901cbb5483fc9683bfb7094f47244b85df6 --- java/src/com/android/inputmethod/latin/LatinIME.java | 15 ++++++++------- .../android/inputmethod/latin/UserBigramDictionary.java | 2 +- .../android/inputmethod/latin/UserUnigramDictionary.java | 2 +- java/src/com/android/inputmethod/latin/WordComposer.java | 2 +- 4 files changed, 11 insertions(+), 10 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 2d7eed7ab..a470897db 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1785,7 +1785,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return; } - final WordComposer wordComposer = mWordComposer; // TODO: May need a better way of retrieving previous word final InputConnection ic = getCurrentInputConnection(); final CharSequence prevWord; @@ -1795,18 +1794,18 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar prevWord = EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators); } // getSuggestedWordBuilder handles gracefully a null value of prevWord - final SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(wordComposer, + final SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(mWordComposer, prevWord, mKeyboardSwitcher.getLatinKeyboard().getProximityInfo(), mCorrectionMode); boolean autoCorrectionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection(); - final CharSequence typedWord = wordComposer.getTypedWord(); + final CharSequence typedWord = mWordComposer.getTypedWord(); // Here, we want to promote a whitelisted word if exists. // TODO: Change this scheme - a boolean is not enough. A whitelisted word may be "valid" // but still autocorrected from - in the case the whitelist only capitalizes the word. // The whitelist should be case-insensitive, so it's not possible to be consistent with // a boolean flag. Right now this is handled with a slight hack in // WhitelistDictionary#shouldForciblyAutoCorrectFrom. - final int quotesCount = wordComposer.trailingSingleQuotesCount(); + final int quotesCount = mWordComposer.trailingSingleQuotesCount(); final boolean allowsToBeAutoCorrected = AutoCorrection.allowsToBeAutoCorrected( mSuggest.getUnigramDictionaries(), // If the typed string ends with a single quote, for dictionary lookup purposes @@ -1822,7 +1821,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar autoCorrectionAvailable |= (!allowsToBeAutoCorrected); } // Don't auto-correct words with multiple capital letter - autoCorrectionAvailable &= !wordComposer.isMostlyCaps(); + autoCorrectionAvailable &= !mWordComposer.isMostlyCaps(); // Basically, we update the suggestion strip only when suggestion count > 1. However, // there is an exception: We update the suggestion strip whenever typed word's length @@ -1959,6 +1958,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { addToOnlyBigramDictionary(suggestion, 1); } + // TODO: the following is fishy, because if !mHasUncommittedTypedChars we are + // going to log an empty string LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(), suggestion.toString(), index, suggestions.mWords); // Follow it with a space @@ -2399,8 +2400,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } - public WordComposer getCurrentWord() { - return mWordComposer; + public boolean isAutoCapitalized() { + return mWordComposer.isAutoCapitalized(); } boolean isSoundOn() { diff --git a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java index 3a1af9311..f80534cb5 100644 --- a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java @@ -159,7 +159,7 @@ public class UserBigramDictionary extends ExpandableDictionary { */ public int addBigrams(String word1, String word2) { // remove caps if second word is autocapitalized - if (mIme != null && mIme.getCurrentWord().isAutoCapitalized()) { + if (mIme != null && mIme.isAutoCapitalized()) { word2 = Character.toLowerCase(word2.charAt(0)) + word2.substring(1); } // Do not insert a word as a bigram of itself diff --git a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java index de7cb5716..6af20c754 100644 --- a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java @@ -149,7 +149,7 @@ public class UserUnigramDictionary extends ExpandableDictionary { final int length = word.length(); // Don't add very short or very long words. if (length < 2 || length > getMaxWordLength()) return; - if (mIme.getCurrentWord().isAutoCapitalized()) { + if (mIme.isAutoCapitalized()) { // Remove caps before adding word = Character.toLowerCase(word.charAt(0)) + word.substring(1); } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index fcaf81cd5..8bbcff758 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -301,7 +301,7 @@ public class WordComposer { } /** - * @return the auto-correction for this world, or null if none. + * @return the auto-correction for this word, or null if none. */ public CharSequence getAutoCorrectionOrNull() { return mAutoCorrection; -- cgit v1.2.3-83-g751a From 27dff63833bf1c8a36eed826746de3c6725d8423 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 13 Dec 2011 22:20:20 +0900 Subject: Group all input-related info into an inner class. Currently, these variables hold the info about the composing word, or maybe some outdated info, and it's not very clear which it is. LatinIME is maintaining the freshness info in a separate boolean, and uses it throughout the code for many, many things, leading to much confusion. The idea in grouping this info is, it can be saved in another instance and restored later. It can be tested against to know whether there is actually outdated but kept info or not, and it should allow to straighten out what is actually currently being typed. Ultimately, it will eliminate the need for LatinIME to keep track of the status of the info in the word composer. Change-Id: I00e2c690f303f8320c9be35590a6df4583e9e456 --- .../android/inputmethod/latin/WordComposer.java | 83 +++++++++++++--------- 1 file changed, 50 insertions(+), 33 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 8bbcff758..60a9685bc 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -32,15 +32,40 @@ public class WordComposer { public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE; public static final int NOT_A_COORDINATE = -1; - /** - * The list of unicode values for each keystroke (including surrounding keys) - */ - private ArrayList mCodes; - - private int[] mXCoordinates; - private int[] mYCoordinates; + // Storage for all the info about the current input. + private static class CharacterStore { + /** + * The list of unicode values for each keystroke (including surrounding keys) + */ + ArrayList mCodes; + int[] mXCoordinates; + int[] mYCoordinates; + StringBuilder mTypedWord; + CharacterStore() { + final int N = BinaryDictionary.MAX_WORD_LENGTH; + mCodes = new ArrayList(N); + mTypedWord = new StringBuilder(N); + mXCoordinates = new int[N]; + mYCoordinates = new int[N]; + } + CharacterStore(final CharacterStore that) { + mCodes = new ArrayList(that.mCodes); + mTypedWord = new StringBuilder(that.mTypedWord); + mXCoordinates = Arrays.copyOf(that.mXCoordinates, that.mXCoordinates.length); + mYCoordinates = Arrays.copyOf(that.mYCoordinates, that.mYCoordinates.length); + } + void reset() { + // For better performance than creating a new character store. + mCodes.clear(); + mTypedWord.setLength(0); + } + } - private StringBuilder mTypedWord; + // The currently typing word. + // NOTE: this is not reset as soon as the word is committed because it may be needed again + // to resume suggestion if backspaced. TODO: separate cleanly what is actually being + // composed and what is kept for possible resuming. + private CharacterStore mCurrentWord; // An auto-correction for this word out of the dictionary. private CharSequence mAutoCorrection; @@ -56,11 +81,7 @@ public class WordComposer { private boolean mIsFirstCharCapitalized; public WordComposer() { - final int N = BinaryDictionary.MAX_WORD_LENGTH; - mCodes = new ArrayList(N); - mTypedWord = new StringBuilder(N); - mXCoordinates = new int[N]; - mYCoordinates = new int[N]; + mCurrentWord = new CharacterStore(); mTrailingSingleQuotesCount = 0; mAutoCorrection = null; } @@ -70,10 +91,7 @@ public class WordComposer { } public void init(WordComposer source) { - mCodes = new ArrayList(source.mCodes); - mTypedWord = new StringBuilder(source.mTypedWord); - mXCoordinates = Arrays.copyOf(source.mXCoordinates, source.mXCoordinates.length); - mYCoordinates = Arrays.copyOf(source.mYCoordinates, source.mYCoordinates.length); + mCurrentWord = new CharacterStore(source.mCurrentWord); mCapsCount = source.mCapsCount; mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; @@ -85,8 +103,7 @@ public class WordComposer { * Clear out the keys registered so far. */ public void reset() { - mCodes.clear(); - mTypedWord.setLength(0); + mCurrentWord.reset(); mCapsCount = 0; mIsFirstCharCapitalized = false; mTrailingSingleQuotesCount = 0; @@ -98,7 +115,7 @@ public class WordComposer { * @return the number of keystrokes */ public final int size() { - return mTypedWord.length(); + return mCurrentWord.mTypedWord.length(); } /** @@ -107,15 +124,15 @@ public class WordComposer { * @return the unicode for the pressed and surrounding keys */ public int[] getCodesAt(int index) { - return mCodes.get(index); + return mCurrentWord.mCodes.get(index); } public int[] getXCoordinates() { - return mXCoordinates; + return mCurrentWord.mXCoordinates; } public int[] getYCoordinates() { - return mYCoordinates; + return mCurrentWord.mYCoordinates; } private static boolean isFirstCharCapitalized(int index, int codePoint, boolean previous) { @@ -130,12 +147,12 @@ public class WordComposer { */ public void add(int primaryCode, int[] codes, int x, int y) { final int newIndex = size(); - mTypedWord.append((char) primaryCode); + mCurrentWord.mTypedWord.append((char) primaryCode); correctPrimaryJuxtapos(primaryCode, codes); - mCodes.add(codes); + mCurrentWord.mCodes.add(codes); if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { - mXCoordinates[newIndex] = x; - mYCoordinates[newIndex] = y; + mCurrentWord.mXCoordinates[newIndex] = x; + mCurrentWord.mYCoordinates[newIndex] = y; } mIsFirstCharCapitalized = isFirstCharCapitalized( newIndex, primaryCode, mIsFirstCharCapitalized); @@ -215,9 +232,9 @@ public class WordComposer { final int size = size(); if (size > 0) { final int lastPos = size - 1; - char lastChar = mTypedWord.charAt(lastPos); - mCodes.remove(lastPos); - mTypedWord.deleteCharAt(lastPos); + char lastChar = mCurrentWord.mTypedWord.charAt(lastPos); + mCurrentWord.mCodes.remove(lastPos); + mCurrentWord.mTypedWord.deleteCharAt(lastPos); if (Character.isUpperCase(lastChar)) mCapsCount--; } if (size() == 0) { @@ -226,8 +243,8 @@ public class WordComposer { if (mTrailingSingleQuotesCount > 0) { --mTrailingSingleQuotesCount; } else { - for (int i = mTypedWord.length() - 1; i >= 0; --i) { - if (Keyboard.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break; + for (int i = mCurrentWord.mTypedWord.length() - 1; i >= 0; --i) { + if (Keyboard.CODE_SINGLE_QUOTE != mCurrentWord.mTypedWord.codePointAt(i)) break; ++mTrailingSingleQuotesCount; } } @@ -239,7 +256,7 @@ public class WordComposer { * @return the word that was typed so far. Never returns null. */ public String getTypedWord() { - return mTypedWord.toString(); + return mCurrentWord.mTypedWord.toString(); } /** -- cgit v1.2.3-83-g751a From c73c26790fa9dcd836a918774d6efa39a05c0152 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 13 Dec 2011 23:12:22 +0900 Subject: Make the word composer aware of commits. Change-Id: I04e691fbc9227d4df195429bca89edea93575347 --- .../com/android/inputmethod/latin/LatinIME.java | 8 +++++-- .../android/inputmethod/latin/WordComposer.java | 27 ++++++++++++++++++---- 2 files changed, 29 insertions(+), 6 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 20c87ad13..20e49fbca 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1148,6 +1148,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (!mHasUncommittedTypedChars) return; mHasUncommittedTypedChars = false; final CharSequence typedWord = mWordComposer.getTypedWord(); + mWordComposer.onCommitWord(); if (typedWord.length() > 0) { if (ic != null) { ic.commitText(typedWord, 1); @@ -2032,6 +2033,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } mHasUncommittedTypedChars = false; + mWordComposer.onCommitWord(); } private static final WordComposer sEmptyWordComposer = new WordComposer(); @@ -2201,10 +2203,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } ic.deleteSurroundingText(cancelLength + 1, 0); - - // Re-insert the separator + mWordComposer.resumeSuggestionOnKeptWord(); ic.commitText(mWordComposer.getTypedWord(), 1); + // Re-insert the separator ic.commitText(separator, 1); + mWordComposer.onCommitWord(); Utils.Stats.onSeparator(separator.charAt(0), WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); mHandler.cancelUpdateBigramPredictions(); @@ -2233,6 +2236,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // restartSuggestionsOnWordBeforeCursorIfAtEndOfWord instead, but retrieving // the old WordComposer allows to reuse the actual typed coordinates. mHasUncommittedTypedChars = true; + mWordComposer.resumeSuggestionOnKeptWord(); ic.setComposingText(mWordComposer.getTypedWord(), 1); mHandler.cancelUpdateBigramPredictions(); mHandler.postUpdateSuggestions(); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 60a9685bc..c0204c2a6 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -61,11 +61,10 @@ public class WordComposer { } } - // The currently typing word. - // NOTE: this is not reset as soon as the word is committed because it may be needed again - // to resume suggestion if backspaced. TODO: separate cleanly what is actually being - // composed and what is kept for possible resuming. + // The currently typing word. May not be null. private CharacterStore mCurrentWord; + // The information being kept for resuming suggestion. May be null if wiped. + private CharacterStore mWordKeptForSuggestionResuming; // An auto-correction for this word out of the dictionary. private CharSequence mAutoCorrection; @@ -82,6 +81,7 @@ public class WordComposer { public WordComposer() { mCurrentWord = new CharacterStore(); + mWordKeptForSuggestionResuming = null; mTrailingSingleQuotesCount = 0; mAutoCorrection = null; } @@ -92,6 +92,7 @@ public class WordComposer { public void init(WordComposer source) { mCurrentWord = new CharacterStore(source.mCurrentWord); + mWordKeptForSuggestionResuming = source.mWordKeptForSuggestionResuming; mCapsCount = source.mCapsCount; mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; @@ -104,6 +105,7 @@ public class WordComposer { */ public void reset() { mCurrentWord.reset(); + mWordKeptForSuggestionResuming = null; mCapsCount = 0; mIsFirstCharCapitalized = false; mTrailingSingleQuotesCount = 0; @@ -323,4 +325,21 @@ public class WordComposer { public CharSequence getAutoCorrectionOrNull() { return mAutoCorrection; } + + // TODO: pass the information about what was committed and how. Was it an auto-correction? + // Was it a completion? Was is what the user typed? + public void onCommitWord() { + mWordKeptForSuggestionResuming = mCurrentWord; + // TODO: improve performance by swapping buffers instead of creating a new object. + mCurrentWord = new CharacterStore(); + } + + public boolean hasWordKeptForSuggestionResuming() { + return null != mWordKeptForSuggestionResuming; + } + + public void resumeSuggestionOnKeptWord() { + mCurrentWord = mWordKeptForSuggestionResuming; + mWordKeptForSuggestionResuming = null; + } } -- cgit v1.2.3-83-g751a From 196d82cdd740580ed79d801483dbc282be85d076 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 13 Dec 2011 23:24:37 +0900 Subject: Use the WordComposer to check if we are composing a word ...instead of the hard-to-understand mHasUncommittedTypedChars. This is possible because now the word composer is actually aware of commits. Change-Id: I36b664ce8402a280f801e87b9ebe161f416b0853 --- .../com/android/inputmethod/latin/LatinIME.java | 32 ++++++++++------------ .../android/inputmethod/latin/WordComposer.java | 4 +++ 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 32eabdb5f..a844df1bf 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -933,7 +933,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // newly inserted punctuation. mSpaceState = SPACE_STATE_NONE; } - if (((mWordComposer.size() > 0 && mHasUncommittedTypedChars) + if (((mWordComposer.isComposingWord()) || mVoiceProxy.isVoiceInputHighlighted()) && (selectionChanged || candidatesCleared)) { mWordComposer.reset(); @@ -945,7 +945,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } mComposingStateManager.onFinishComposingText(); mVoiceProxy.setVoiceInputHighlighted(false); - } else if (!mHasUncommittedTypedChars) { + } else if (!mWordComposer.isComposingWord()) { updateSuggestions(); } } @@ -1146,7 +1146,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } public void commitTyped(final InputConnection ic) { - if (!mHasUncommittedTypedChars) return; + if (!mWordComposer.isComposingWord()) return; mHasUncommittedTypedChars = false; final CharSequence typedWord = mWordComposer.getTypedWord(); mWordComposer.onCommitWord(); @@ -1422,18 +1422,19 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return; } - if (mHasUncommittedTypedChars) { + if (mWordComposer.isComposingWord()) { final int length = mWordComposer.size(); if (length > 0) { mWordComposer.deleteLast(); ic.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); - if (mWordComposer.size() == 0) { + // If we have deleted the last remaining character of a word, then we are not + // isComposingWord() any more. + if (!mWordComposer.isComposingWord()) { mHasUncommittedTypedChars = false; - // Remaining size equals zero means we just erased the last character of the - // word, so we can show bigrams. + // Not composing word any more, so we can show bigrams. mHandler.postUpdateBigramPredictions(); } else { - // length > 1, so we still have letters to deduce a suggestion from. + // Still composing a word, so we still have letters to deduce a suggestion from. mHandler.postUpdateSuggestions(); } } else { @@ -1522,7 +1523,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (null != ic) removeTrailingSpaceWhileInBatchEdit(ic); } - boolean isComposingWord = mHasUncommittedTypedChars; + boolean isComposingWord = mWordComposer.isComposingWord(); int code = primaryCode; if ((isAlphabet(code) || mSettingsValues.isSymbolExcludedFromWordSeparators(code)) && isSuggestionsRequested() && !isCursorTouchingWord()) { @@ -1605,7 +1606,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Reset the saved word in all cases. If this separator causes an autocorrection, // it will overwrite this null with the actual word we need to save. mWordSavedForAutoCorrectCancellation = null; - if (mHasUncommittedTypedChars) { + if (mWordComposer.isComposingWord()) { // In certain languages where single quote is a separator, it's better // not to auto correct, but accept the typed word. For instance, // in Italian dov' should not be expanded to dove' because the elision @@ -1780,7 +1781,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mHandler.cancelUpdateSuggestions(); mHandler.cancelUpdateBigramPredictions(); - if (!mHasUncommittedTypedChars) { + if (!mWordComposer.isComposingWord()) { setPunctuationSuggestions(); return; } @@ -1953,11 +1954,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } return; } - if (!mHasUncommittedTypedChars) { - // If we are not composing a word, then it was a suggestion inferred from - // context - no user input. We should reset the word composer. - mWordComposer.reset(); - } mExpectingUpdateSelection = true; commitBestWord(suggestion); // Add the word to the auto dictionary if it's not a known word @@ -1967,8 +1963,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { addToOnlyBigramDictionary(suggestion, 1); } - // TODO: the following is fishy, because if !mHasUncommittedTypedChars we are - // going to log an empty string + // TODO: the following is fishy, because it seems there may be cases where we are not + // composing a word at all. Maybe throw an exception if !mWordComposer.isComposingWord() ? LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(), suggestion.toString(), index, suggestions.mWords); // Follow it with a space diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index c0204c2a6..b88e73fc7 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -120,6 +120,10 @@ public class WordComposer { return mCurrentWord.mTypedWord.length(); } + public final boolean isComposingWord() { + return size() > 0; + } + /** * Returns the codes at a particular position in the word. * @param index the position in the word -- cgit v1.2.3-83-g751a From 3708787fe91227083d2a1874fa41493d3bc9fe10 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Sun, 18 Dec 2011 08:36:16 +0900 Subject: Remove LatinKeyboard class Change-Id: I68c667b00dadf2ed9f1c62fb7da37d2cf499cd81 --- .../android/inputmethod/keyboard/KeyboardSet.java | 29 ++++++------ .../inputmethod/keyboard/KeyboardSwitcher.java | 28 ++++++------ .../inputmethod/keyboard/LatinKeyboard.java | 53 ---------------------- .../inputmethod/keyboard/LatinKeyboardView.java | 38 +++++++--------- .../com/android/inputmethod/latin/LatinIME.java | 21 ++++----- .../android/inputmethod/latin/WordComposer.java | 9 ++-- .../latin/suggestions/MoreSuggestions.java | 2 +- .../android/inputmethod/latin/SuggestHelper.java | 12 +++-- 8 files changed, 69 insertions(+), 123 deletions(-) delete mode 100644 java/src/com/android/inputmethod/keyboard/LatinKeyboard.java (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java index e15ce06e3..f64ac84ac 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java @@ -24,6 +24,8 @@ import android.util.Log; import android.util.Xml; import android.view.inputmethod.EditorInfo; +import com.android.inputmethod.keyboard.internal.KeyboardBuilder; +import com.android.inputmethod.keyboard.internal.KeyboardParams; import com.android.inputmethod.keyboard.internal.XmlParseUtils; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; @@ -72,8 +74,8 @@ public class KeyboardSet { Params() {} } - private static final HashMap> sKeyboardCache = - new HashMap>(); + private static final HashMap> sKeyboardCache = + new HashMap>(); public static void clearKeyboardCache() { sKeyboardCache.clear(); @@ -84,16 +86,16 @@ public class KeyboardSet { mParams = params; } - public LatinKeyboard getMainKeyboard() { + public Keyboard getMainKeyboard() { return getKeyboard(false, false); } - public LatinKeyboard getSymbolsKeyboard() { + public Keyboard getSymbolsKeyboard() { return getKeyboard(true, false); } - public LatinKeyboard getSymbolsShiftedKeyboard() { - final LatinKeyboard keyboard = getKeyboard(true, true); + public Keyboard getSymbolsShiftedKeyboard() { + final Keyboard keyboard = getKeyboard(true, true); // TODO: Remove this logic once we introduce initial keyboard shift state attribute. // Symbol shift keyboard may have a shift key that has a caps lock style indicator (a.k.a. // sticky shift key). To show or dismiss the indicator, we need to call setShiftLocked() @@ -102,11 +104,11 @@ public class KeyboardSet { return keyboard; } - private LatinKeyboard getKeyboard(boolean isSymbols, boolean isShift) { + private Keyboard getKeyboard(boolean isSymbols, boolean isShift) { final int elementState = Builder.getElementState(mParams.mMode, isSymbols, isShift); final int xmlId = mParams.mElementKeyboards.get(elementState); final KeyboardId id = Builder.getKeyboardId(elementState, isSymbols, mParams); - final LatinKeyboard keyboard = getKeyboard(mContext, xmlId, id); + final Keyboard keyboard = getKeyboard(mContext, xmlId, id); return keyboard; } @@ -115,15 +117,16 @@ public class KeyboardSet { return Builder.getKeyboardId(elementState, false, mParams); } - private static LatinKeyboard getKeyboard(Context context, int xmlId, KeyboardId id) { + private static Keyboard getKeyboard(Context context, int xmlId, KeyboardId id) { final Resources res = context.getResources(); final SubtypeSwitcher subtypeSwitcher = SubtypeSwitcher.getInstance(); - final SoftReference ref = sKeyboardCache.get(id); - LatinKeyboard keyboard = (ref == null) ? null : ref.get(); + final SoftReference ref = sKeyboardCache.get(id); + Keyboard keyboard = (ref == null) ? null : ref.get(); if (keyboard == null) { final Locale savedLocale = LocaleUtils.setSystemLocale(res, id.mLocale); try { - final LatinKeyboard.Builder builder = new LatinKeyboard.Builder(context); + final KeyboardBuilder builder = + new KeyboardBuilder(context, new KeyboardParams()); builder.load(xmlId, id); builder.setTouchPositionCorrectionEnabled( subtypeSwitcher.currentSubtypeContainsExtraValueKey( @@ -132,7 +135,7 @@ public class KeyboardSet { } finally { LocaleUtils.setSystemLocale(res, savedLocale); } - sKeyboardCache.put(id, new SoftReference(keyboard)); + sKeyboardCache.put(id, new SoftReference(keyboard)); if (DEBUG_CACHE) { Log.d(TAG, "keyboard cache size=" + sKeyboardCache.size() + ": " diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 1625d2233..e839fe7a3 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -171,7 +171,7 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, } public boolean isAlphabetMode() { - final Keyboard keyboard = getLatinKeyboard(); + final Keyboard keyboard = getKeyboard(); return keyboard != null && keyboard.mId.isAlphabetKeyboard(); } @@ -180,12 +180,12 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, } public boolean isShiftedOrShiftLocked() { - final Keyboard keyboard = getLatinKeyboard(); + final Keyboard keyboard = getKeyboard(); return keyboard != null && keyboard.isShiftedOrShiftLocked(); } public boolean isManualTemporaryUpperCase() { - final Keyboard keyboard = getLatinKeyboard(); + final Keyboard keyboard = getKeyboard(); return keyboard != null && keyboard.isManualTemporaryUpperCase(); } @@ -195,11 +195,9 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, return false; } - public LatinKeyboard getLatinKeyboard() { + public Keyboard getKeyboard() { if (mKeyboardView != null) { - final Keyboard keyboard = mKeyboardView.getKeyboard(); - if (keyboard instanceof LatinKeyboard) - return (LatinKeyboard)keyboard; + return mKeyboardView.getKeyboard(); } return null; } @@ -208,11 +206,11 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, @Override public void setShifted(int shiftMode) { mInputMethodService.mHandler.cancelUpdateShiftState(); - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard == null) + Keyboard keyboard = getKeyboard(); + if (keyboard == null) return; if (shiftMode == AUTOMATIC_SHIFT) { - latinKeyboard.setAutomaticTemporaryUpperCase(); + keyboard.setAutomaticTemporaryUpperCase(); } else { final boolean shifted = (shiftMode == MANUAL_SHIFT); // On non-distinct multi touch panel device, we should also turn off the shift locked @@ -220,9 +218,9 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, // On the other hand, on distinct multi touch panel device, turning off the shift // locked state with shift key pressing is handled by onReleaseShift(). if (!hasDistinctMultitouch() && !shifted && mState.isShiftLocked()) { - latinKeyboard.setShiftLocked(false); + keyboard.setShiftLocked(false); } - latinKeyboard.setShifted(shifted); + keyboard.setShifted(shifted); } mKeyboardView.invalidateAllKeys(); } @@ -231,10 +229,10 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, @Override public void setShiftLocked(boolean shiftLocked) { mInputMethodService.mHandler.cancelUpdateShiftState(); - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard == null) + Keyboard keyboard = getKeyboard(); + if (keyboard == null) return; - latinKeyboard.setShiftLocked(shiftLocked); + keyboard.setShiftLocked(shiftLocked); mKeyboardView.invalidateAllKeys(); if (!shiftLocked) { // To be able to turn off caps lock by "double tap" on shift key, we should ignore diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java deleted file mode 100644 index 54118f4d8..000000000 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.keyboard; - -import android.content.Context; - -import com.android.inputmethod.keyboard.internal.KeyboardBuilder; -import com.android.inputmethod.keyboard.internal.KeyboardParams; - -// TODO: We should remove this class -public class LatinKeyboard extends Keyboard { - private LatinKeyboard(KeyboardParams params) { - super(params); - } - - public static class Builder extends KeyboardBuilder { - public Builder(Context context) { - super(context, new KeyboardParams()); - } - - @Override - public Builder load(int xmlId, KeyboardId id) { - super.load(xmlId, id); - return this; - } - - @Override - public LatinKeyboard build() { - return new LatinKeyboard(mParams); - } - } - - @Override - public Key[] getNearestKeys(int x, int y) { - // Avoid dead pixels at edges of the keyboard - return super.getNearestKeys(Math.max(0, Math.min(x, mOccupiedWidth - 1)), - Math.max(0, Math.min(y, mOccupiedHeight - 1))); - } -} diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 10a544c21..aefa50b22 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -220,8 +220,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke @Override public boolean onDoubleTap(MotionEvent firstDown) { final Keyboard keyboard = getKeyboard(); - if (ENABLE_CAPSLOCK_BY_DOUBLETAP && keyboard instanceof LatinKeyboard - && ((LatinKeyboard) keyboard).mId.isAlphabetKeyboard()) { + if (ENABLE_CAPSLOCK_BY_DOUBLETAP && keyboard.mId.isAlphabetKeyboard()) { final int pointerIndex = firstDown.getActionIndex(); final int id = firstDown.getPointerId(pointerIndex); final PointerTracker tracker = getPointerTracker(id); @@ -452,29 +451,26 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke protected boolean onLongPress(Key parentKey, PointerTracker tracker) { final int primaryCode = parentKey.mCode; final Keyboard keyboard = getKeyboard(); - if (keyboard instanceof LatinKeyboard) { - final LatinKeyboard latinKeyboard = (LatinKeyboard) keyboard; - if (primaryCode == Keyboard.CODE_DIGIT0 && latinKeyboard.mId.isPhoneKeyboard()) { - tracker.onLongPressed(); - // Long pressing on 0 in phone number keypad gives you a '+'. - invokeCodeInput(Keyboard.CODE_PLUS); - invokeReleaseKey(primaryCode); - return true; - } - if (primaryCode == Keyboard.CODE_SHIFT && latinKeyboard.mId.isAlphabetKeyboard()) { + if (primaryCode == Keyboard.CODE_DIGIT0 && keyboard.mId.isPhoneKeyboard()) { + tracker.onLongPressed(); + // Long pressing on 0 in phone number keypad gives you a '+'. + invokeCodeInput(Keyboard.CODE_PLUS); + invokeReleaseKey(primaryCode); + return true; + } + if (primaryCode == Keyboard.CODE_SHIFT && keyboard.mId.isAlphabetKeyboard()) { + tracker.onLongPressed(); + invokeCodeInput(Keyboard.CODE_CAPSLOCK); + invokeReleaseKey(primaryCode); + return true; + } + if (primaryCode == Keyboard.CODE_SPACE) { + // Long pressing the space key invokes IME switcher dialog. + if (invokeCustomRequest(LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) { tracker.onLongPressed(); - invokeCodeInput(Keyboard.CODE_CAPSLOCK); invokeReleaseKey(primaryCode); return true; } - if (primaryCode == Keyboard.CODE_SPACE) { - // Long pressing the space key invokes IME switcher dialog. - if (invokeCustomRequest(LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) { - tracker.onLongPressed(); - invokeReleaseKey(primaryCode); - return true; - } - } } return openMoreKeysPanel(parentKey, tracker); } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index c868f14fc..59d394b5e 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -65,7 +65,6 @@ import com.android.inputmethod.keyboard.KeyboardActionListener; import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.KeyboardView; -import com.android.inputmethod.keyboard.LatinKeyboard; import com.android.inputmethod.keyboard.LatinKeyboardView; import com.android.inputmethod.latin.suggestions.SuggestionsView; @@ -293,13 +292,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR: setSpacebarTextFadeFactor(inputView, (1.0f + mFinalFadeoutFactorOfLanguageOnSpacebar) / 2, - (LatinKeyboard)msg.obj); + (Keyboard)msg.obj); sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj), mDurationOfFadeoutLanguageOnSpacebar); break; case MSG_DISMISS_LANGUAGE_ON_SPACEBAR: setSpacebarTextFadeFactor(inputView, mFinalFadeoutFactorOfLanguageOnSpacebar, - (LatinKeyboard)msg.obj); + (Keyboard)msg.obj); break; } } @@ -340,10 +339,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } private static void setSpacebarTextFadeFactor(LatinKeyboardView inputView, - float fadeFactor, LatinKeyboard oldKeyboard) { + float fadeFactor, Keyboard oldKeyboard) { if (inputView == null) return; final Keyboard keyboard = inputView.getKeyboard(); - if (keyboard instanceof LatinKeyboard && keyboard == oldKeyboard) { + if (keyboard == oldKeyboard) { inputView.updateSpacebar(fadeFactor, SubtypeSwitcher.getInstance().needsToDisplayLanguage( keyboard.mId.mLocale)); @@ -356,7 +355,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR); final LatinKeyboardView inputView = latinIme.mKeyboardSwitcher.getKeyboardView(); if (inputView != null) { - final LatinKeyboard keyboard = latinIme.mKeyboardSwitcher.getLatinKeyboard(); + final Keyboard keyboard = latinIme.mKeyboardSwitcher.getKeyboard(); // The language is always displayed when the delay is negative. final boolean needsToDisplayLanguage = localeChanged || mDelayBeforeFadeoutLanguageOnSpacebar < 0; @@ -1718,7 +1717,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } // getSuggestedWordBuilder handles gracefully a null value of prevWord final SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(mWordComposer, - prevWord, mKeyboardSwitcher.getLatinKeyboard().getProximityInfo(), mCorrectionMode); + prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), mCorrectionMode); boolean autoCorrectionAvailable = !mInputAttributes.mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection(); @@ -1867,7 +1866,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // pressed space on purpose of displaying the suggestion strip punctuation. final int rawPrimaryCode = suggestion.charAt(0); // Maybe apply the "bidi mirrored" conversions for parentheses - final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard(); + final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); final boolean isRtl = keyboard != null && keyboard.mIsRtlKeyboard; final int primaryCode = Key.getRtlParenthesisCode(rawPrimaryCode, isRtl); @@ -1969,7 +1968,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(), mSettingsValues.mWordSeparators); SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(sEmptyWordComposer, - prevWord, mKeyboardSwitcher.getLatinKeyboard().getProximityInfo(), mCorrectionMode); + prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), mCorrectionMode); if (builder.size() > 0) { // Explicitly supply an empty typed word (the no-second-arg version of @@ -2095,7 +2094,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // "ic" must not be null private void restartSuggestionsOnWordBeforeCursor(final InputConnection ic, final CharSequence word) { - mWordComposer.setComposingWord(word, mKeyboardSwitcher.getLatinKeyboard()); + mWordComposer.setComposingWord(word, mKeyboardSwitcher.getKeyboard()); mComposingStateManager.onStartComposingText(); ic.deleteSurroundingText(word.length(), 0); ic.setComposingText(word, 1); @@ -2436,7 +2435,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final Printer p = new PrintWriterPrinter(fout); p.println("LatinIME state :"); - final Keyboard keyboard = mKeyboardSwitcher.getLatinKeyboard(); + final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1; p.println(" Keyboard mode = " + keyboardMode); p.println(" mIsSuggestionsRequested=" + mInputAttributes.mIsSettingsSuggestionStripOn); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index b88e73fc7..9d6803ef2 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -16,10 +16,9 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; -import com.android.inputmethod.keyboard.LatinKeyboard; +import com.android.inputmethod.keyboard.Keyboard; import java.util.ArrayList; import java.util.Arrays; @@ -174,7 +173,7 @@ public class WordComposer { /** * Internal method to retrieve reasonable proximity info for a character. */ - private void addKeyInfo(final int codePoint, final LatinKeyboard keyboard, + private void addKeyInfo(final int codePoint, final Keyboard keyboard, final KeyDetector keyDetector) { for (final Key key : keyboard.mKeys) { if (key.mCode == codePoint) { @@ -194,7 +193,7 @@ public class WordComposer { * Set the currently composing word to the one passed as an argument. * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. */ - public void setComposingWord(final CharSequence word, final LatinKeyboard keyboard, + public void setComposingWord(final CharSequence word, final Keyboard keyboard, final KeyDetector keyDetector) { reset(); final int length = word.length(); @@ -208,7 +207,7 @@ public class WordComposer { /** * Shortcut for the above method, this will create a new KeyDetector for the passed keyboard. */ - public void setComposingWord(final CharSequence word, final LatinKeyboard keyboard) { + public void setComposingWord(final CharSequence word, final Keyboard keyboard) { final KeyDetector keyDetector = new KeyDetector(0); keyDetector.setKeyboard(keyboard, 0, 0); keyDetector.setProximityCorrectionEnabled(true); diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java index eeabb30e4..b479ff4ce 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java @@ -179,7 +179,7 @@ public class MoreSuggestions extends Keyboard { public Builder layout(SuggestedWords suggestions, int fromPos, int maxWidth, int minWidth, int maxRow) { - final Keyboard keyboard = KeyboardSwitcher.getInstance().getLatinKeyboard(); + final Keyboard keyboard = KeyboardSwitcher.getInstance().getKeyboard(); final int xmlId = R.xml.kbd_suggestions_pane_template; load(xmlId, keyboard.mId); mParams.mVerticalGap = mParams.mTopPadding = keyboard.mVerticalGap / 2; diff --git a/tests/src/com/android/inputmethod/latin/SuggestHelper.java b/tests/src/com/android/inputmethod/latin/SuggestHelper.java index 4d123e5d3..77496db48 100644 --- a/tests/src/com/android/inputmethod/latin/SuggestHelper.java +++ b/tests/src/com/android/inputmethod/latin/SuggestHelper.java @@ -20,8 +20,10 @@ import android.content.Context; import android.text.TextUtils; import com.android.inputmethod.keyboard.KeyDetector; +import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; -import com.android.inputmethod.keyboard.LatinKeyboard; +import com.android.inputmethod.keyboard.internal.KeyboardBuilder; +import com.android.inputmethod.keyboard.internal.KeyboardParams; import java.io.File; import java.util.Locale; @@ -29,7 +31,7 @@ import java.util.Locale; public class SuggestHelper { protected final Suggest mSuggest; protected int mCorrectionMode; - protected final LatinKeyboard mKeyboard; + protected final Keyboard mKeyboard; private final KeyDetector mKeyDetector; public static final int ALPHABET_KEYBOARD = com.android.inputmethod.latin.R.xml.kbd_qwerty; @@ -38,7 +40,8 @@ public class SuggestHelper { // Use null as the locale for Suggest so as to force it to use the internal dictionary // (and not try to find a dictionary provider for a specified locale) mSuggest = new Suggest(context, dictionaryId, null); - mKeyboard = new LatinKeyboard.Builder(context).load(ALPHABET_KEYBOARD, keyboardId).build(); + mKeyboard = new KeyboardBuilder(context, new KeyboardParams()) + .load(ALPHABET_KEYBOARD, keyboardId).build(); mKeyDetector = new KeyDetector(0); init(); } @@ -47,7 +50,8 @@ public class SuggestHelper { final long startOffset, final long length, final KeyboardId keyboardId, final Locale locale) { mSuggest = new Suggest(context, dictionaryPath, startOffset, length, null, locale); - mKeyboard = new LatinKeyboard.Builder(context).load(ALPHABET_KEYBOARD, keyboardId).build(); + mKeyboard = new KeyboardBuilder(context, new KeyboardParams()) + .load(ALPHABET_KEYBOARD, keyboardId).build(); mKeyDetector = new KeyDetector(0); init(); } -- cgit v1.2.3-83-g751a From 9e8761c4402ddc11c942ed2e583bd7d58f70c5ea Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 14 Dec 2011 20:13:16 +0900 Subject: Reorganize the auto-correction memory Change-Id: I31cce9db471dcd4a7b3477bcb037a8ff482b7696 --- .../com/android/inputmethod/latin/LatinIME.java | 31 ++++++--------- .../android/inputmethod/latin/WordComposer.java | 45 +++++++++++++--------- 2 files changed, 38 insertions(+), 38 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 59d394b5e..60f8ce8d8 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -199,7 +199,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private WordComposer mWordComposer = new WordComposer(); private int mCorrectionMode; - private String mWordSavedForAutoCorrectCancellation; // Keep track of the last selection range to decide if we need to show word alternatives private int mLastSelectionStart; private int mLastSelectionEnd; @@ -1308,8 +1307,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mKeyboardSwitcher.updateShiftState(); mKeyboardSwitcher.onCodeInput(Keyboard.CODE_DUMMY); mSpaceState = SPACE_STATE_NONE; - mWordSavedForAutoCorrectCancellation = null; mEnteredText = text; + mWordComposer.reset(); } @Override @@ -1363,13 +1362,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar ic.deleteSurroundingText(1, 0); } } else { - if (null != mWordSavedForAutoCorrectCancellation) { + if (mWordComposer.didAutoCorrectToAnotherWord()) { Utils.Stats.onAutoCorrectionCancellation(); cancelAutoCorrect(ic); - mWordSavedForAutoCorrectCancellation = null; return; - } else { - mWordSavedForAutoCorrectCancellation = null; } if (SPACE_STATE_DOUBLE == spaceState) { @@ -1524,9 +1520,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (ic != null) { ic.beginBatchEdit(); } - // Reset the saved word in all cases. If this separator causes an autocorrection, - // it will overwrite this null with the actual word we need to save. - mWordSavedForAutoCorrectCancellation = null; if (mWordComposer.isComposingWord()) { // In certain languages where single quote is a separator, it's better // not to auto correct, but accept the typed word. For instance, @@ -1810,9 +1803,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint); mExpectingUpdateSelection = true; commitBestWord(autoCorrection); - if (!autoCorrection.equals(typedWord)) { - mWordSavedForAutoCorrectCancellation = autoCorrection.toString(); - } // Add the word to the user unigram dictionary if it's not a known word addToUserUnigramAndBigramDictionaries(autoCorrection, UserUnigramDictionary.FREQUENCY_FOR_TYPED); @@ -2103,28 +2093,31 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // "ic" must not be null private void cancelAutoCorrect(final InputConnection ic) { - final int cancelLength = mWordSavedForAutoCorrectCancellation.length(); + mWordComposer.resumeSuggestionOnKeptWord(); + final String originallyTypedWord = mWordComposer.getTypedWord(); + final CharSequence autoCorrectedTo = mWordComposer.getAutoCorrectionOrNull(); + final int cancelLength = autoCorrectedTo.length(); final CharSequence separator = ic.getTextBeforeCursor(1, 0); if (DEBUG) { final String wordBeforeCursor = ic.getTextBeforeCursor(cancelLength + 1, 0).subSequence(0, cancelLength) .toString(); - if (!mWordSavedForAutoCorrectCancellation.equals(wordBeforeCursor)) { + if (!autoCorrectedTo.equals(wordBeforeCursor)) { throw new RuntimeException("cancelAutoCorrect check failed: we thought we were " - + "reverting \"" + mWordSavedForAutoCorrectCancellation + + "reverting \"" + autoCorrectedTo + "\", but before the cursor we found \"" + wordBeforeCursor + "\""); } - if (mWordComposer.getTypedWord().equals(wordBeforeCursor)) { + if (originallyTypedWord.equals(wordBeforeCursor)) { throw new RuntimeException("cancelAutoCorrect check failed: we wanted to cancel " - + "auto correction and revert to \"" + mWordComposer.getTypedWord() + + "auto correction and revert to \"" + originallyTypedWord + "\" but we found this very string before the cursor"); } } ic.deleteSurroundingText(cancelLength + 1, 0); - mWordComposer.resumeSuggestionOnKeptWord(); - ic.commitText(mWordComposer.getTypedWord(), 1); + ic.commitText(originallyTypedWord, 1); // Re-insert the separator ic.commitText(separator, 1); + mWordComposer.deleteAutoCorrection(); mWordComposer.onCommitWord(); Utils.Stats.onSeparator(separator.charAt(0), WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 9d6803ef2..54d908011 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin; +import android.text.TextUtils; + import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; @@ -40,12 +42,14 @@ public class WordComposer { int[] mXCoordinates; int[] mYCoordinates; StringBuilder mTypedWord; + CharSequence mAutoCorrection; CharacterStore() { final int N = BinaryDictionary.MAX_WORD_LENGTH; mCodes = new ArrayList(N); mTypedWord = new StringBuilder(N); mXCoordinates = new int[N]; mYCoordinates = new int[N]; + mAutoCorrection = null; } CharacterStore(final CharacterStore that) { mCodes = new ArrayList(that.mCodes); @@ -57,15 +61,14 @@ public class WordComposer { // For better performance than creating a new character store. mCodes.clear(); mTypedWord.setLength(0); + mAutoCorrection = null; } } // The currently typing word. May not be null. private CharacterStore mCurrentWord; // The information being kept for resuming suggestion. May be null if wiped. - private CharacterStore mWordKeptForSuggestionResuming; - // An auto-correction for this word out of the dictionary. - private CharSequence mAutoCorrection; + private CharacterStore mCommittedWordSavedForSuggestionResuming; private int mCapsCount; @@ -80,9 +83,8 @@ public class WordComposer { public WordComposer() { mCurrentWord = new CharacterStore(); - mWordKeptForSuggestionResuming = null; + mCommittedWordSavedForSuggestionResuming = null; mTrailingSingleQuotesCount = 0; - mAutoCorrection = null; } public WordComposer(WordComposer source) { @@ -91,12 +93,11 @@ public class WordComposer { public void init(WordComposer source) { mCurrentWord = new CharacterStore(source.mCurrentWord); - mWordKeptForSuggestionResuming = source.mWordKeptForSuggestionResuming; + mCommittedWordSavedForSuggestionResuming = source.mCommittedWordSavedForSuggestionResuming; mCapsCount = source.mCapsCount; mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount; - mAutoCorrection = null; } /** @@ -104,11 +105,10 @@ public class WordComposer { */ public void reset() { mCurrentWord.reset(); - mWordKeptForSuggestionResuming = null; + mCommittedWordSavedForSuggestionResuming = null; mCapsCount = 0; mIsFirstCharCapitalized = false; mTrailingSingleQuotesCount = 0; - mAutoCorrection = null; } /** @@ -167,7 +167,7 @@ public class WordComposer { } else { mTrailingSingleQuotesCount = 0; } - mAutoCorrection = null; + mCurrentWord.mAutoCorrection = null; } /** @@ -201,7 +201,7 @@ public class WordComposer { int codePoint = word.charAt(i); addKeyInfo(codePoint, keyboard, keyDetector); } - mAutoCorrection = null; + mCommittedWordSavedForSuggestionResuming = null; } /** @@ -253,7 +253,7 @@ public class WordComposer { ++mTrailingSingleQuotesCount; } } - mAutoCorrection = null; + mCurrentWord.mAutoCorrection = null; } /** @@ -312,37 +312,44 @@ public class WordComposer { * Sets the auto-correction for this word. */ public void setAutoCorrection(final CharSequence correction) { - mAutoCorrection = correction; + mCurrentWord.mAutoCorrection = correction; } /** * Remove any auto-correction that may have been set. */ public void deleteAutoCorrection() { - mAutoCorrection = null; + mCurrentWord.mAutoCorrection = null; } /** * @return the auto-correction for this word, or null if none. */ public CharSequence getAutoCorrectionOrNull() { - return mAutoCorrection; + return mCurrentWord.mAutoCorrection; } // TODO: pass the information about what was committed and how. Was it an auto-correction? // Was it a completion? Was is what the user typed? public void onCommitWord() { - mWordKeptForSuggestionResuming = mCurrentWord; + mCommittedWordSavedForSuggestionResuming = mCurrentWord; // TODO: improve performance by swapping buffers instead of creating a new object. mCurrentWord = new CharacterStore(); } public boolean hasWordKeptForSuggestionResuming() { - return null != mWordKeptForSuggestionResuming; + return null != mCommittedWordSavedForSuggestionResuming; } public void resumeSuggestionOnKeptWord() { - mCurrentWord = mWordKeptForSuggestionResuming; - mWordKeptForSuggestionResuming = null; + mCurrentWord = mCommittedWordSavedForSuggestionResuming; + mCommittedWordSavedForSuggestionResuming = null; + } + + public boolean didAutoCorrectToAnotherWord() { + return null != mCommittedWordSavedForSuggestionResuming + && !TextUtils.isEmpty(mCommittedWordSavedForSuggestionResuming.mAutoCorrection) + && !TextUtils.equals(mCommittedWordSavedForSuggestionResuming.mTypedWord, + mCommittedWordSavedForSuggestionResuming.mAutoCorrection); } } -- cgit v1.2.3-83-g751a From 0fd625bcfdfac1c10e7bd7f9088bf425fec08989 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 20 Dec 2011 17:52:29 +0900 Subject: Fix a bug with wrong auto-correct cancellation Auto-correct cancellation would sometimes kick in at wrong times, causing crashes. Bug: 5784542 Change-Id: I68dd6b8d9237ce9b66af2dc63e77ba6dd5fd69dd --- .../com/android/inputmethod/latin/LatinIME.java | 16 +++++--- .../android/inputmethod/latin/WordComposer.java | 44 ++++++++++++++++++---- 2 files changed, 47 insertions(+), 13 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 60f8ce8d8..d2b1e9bca 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1071,7 +1071,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public void commitTyped(final InputConnection ic) { if (!mWordComposer.isComposingWord()) return; final CharSequence typedWord = mWordComposer.getTypedWord(); - mWordComposer.onCommitWord(); + mWordComposer.onCommitWord(WordComposer.COMMIT_TYPE_USER_TYPED_WORD); if (typedWord.length() > 0) { if (ic != null) { ic.commitText(typedWord, 1); @@ -1802,7 +1802,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint); mExpectingUpdateSelection = true; - commitBestWord(autoCorrection); + commitChosenWord(autoCorrection, WordComposer.COMMIT_TYPE_DECIDED_WORD); // Add the word to the user unigram dictionary if it's not a known word addToUserUnigramAndBigramDictionaries(autoCorrection, UserUnigramDictionary.FREQUENCY_FOR_TYPED); @@ -1868,7 +1868,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return; } mExpectingUpdateSelection = true; - commitBestWord(suggestion); + commitChosenWord(suggestion, WordComposer.COMMIT_TYPE_MANUAL_PICK); // Add the word to the auto dictionary if it's not a known word if (index == 0) { addToUserUnigramAndBigramDictionaries(suggestion, @@ -1927,7 +1927,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar /** * Commits the chosen word to the text field and saves it for later retrieval. */ - private void commitBestWord(CharSequence bestWord) { + private void commitChosenWord(final CharSequence bestWord, final int commitType) { final KeyboardSwitcher switcher = mKeyboardSwitcher; if (!switcher.isKeyboardAvailable()) return; @@ -1942,7 +1942,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar ic.commitText(bestWord, 1); } } - mWordComposer.onCommitWord(); + // TODO: figure out here if this is an auto-correct or if the best word is actually + // what user typed. Note: currently this is done much later in + // WordComposer#didAutoCorrectToAnotherWord by string equality of the remembered + // strings. + mWordComposer.onCommitWord(commitType); } private static final WordComposer sEmptyWordComposer = new WordComposer(); @@ -2118,7 +2122,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Re-insert the separator ic.commitText(separator, 1); mWordComposer.deleteAutoCorrection(); - mWordComposer.onCommitWord(); + mWordComposer.onCommitWord(WordComposer.COMMIT_TYPE_CANCEL_AUTO_CORRECT); Utils.Stats.onSeparator(separator.charAt(0), WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); mHandler.cancelUpdateBigramPredictions(); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 54d908011..7e844e9f4 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2008 The Android Open Source Project - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -33,6 +33,23 @@ public class WordComposer { public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE; public static final int NOT_A_COORDINATE = -1; + // TODO: Straighten out commit behavior so that the flags here are more understandable, + // and possibly adjust their names. + // COMMIT_TYPE_USER_TYPED_WORD is used when the word committed is the exact typed word, with + // no hinting from the IME. It happens when some external event happens (rotating the device, + // for example) or when auto-correction is off by settings or editor attributes. + public static final int COMMIT_TYPE_USER_TYPED_WORD = 0; + // COMMIT_TYPE_MANUAL_PICK is used when the user pressed a field in the suggestion strip. + public static final int COMMIT_TYPE_MANUAL_PICK = 1; + // COMMIT_TYPE_DECIDED_WORD is used when the IME commits the word it decided was best + // for the current user input. It may be different from what the user typed (true auto-correct) + // or it may be exactly what the user typed if it's in the dictionary or the IME does not have + // enough confidence in any suggestion to auto-correct (auto-correct to typed word). + public static final int COMMIT_TYPE_DECIDED_WORD = 2; + // COMMIT_TYPE_CANCEL_AUTO_CORRECT is used upon committing back the old word upon cancelling + // an auto-correction. + public static final int COMMIT_TYPE_CANCEL_AUTO_CORRECT = 3; + // Storage for all the info about the current input. private static class CharacterStore { /** @@ -291,7 +308,7 @@ public class WordComposer { return mCapsCount > 1; } - /** + /** * Saves the reason why the word is capitalized - whether it was automatic or * due to the user hitting shift in the middle of a sentence. * @param auto whether it was an automatic capitalization due to start of sentence @@ -329,10 +346,23 @@ public class WordComposer { return mCurrentWord.mAutoCorrection; } - // TODO: pass the information about what was committed and how. Was it an auto-correction? - // Was it a completion? Was is what the user typed? - public void onCommitWord() { + // `type' should be one of the COMMIT_TYPE_* constants above. + public void onCommitWord(final int type) { mCommittedWordSavedForSuggestionResuming = mCurrentWord; + // Note: currently, we come here whenever we commit a word. If it's any *other* kind that + // DECIDED_WORD, we should reset mAutoCorrection so that we don't attempt to cancel later. + // If it's a DECIDED_WORD, it may be an actual auto-correction by the IME, or what the user + // typed because the IME decided *not* to auto-correct for whatever reason. + // Ideally we would also null it when it was a DECIDED_WORD that was not an auto-correct. + // As it happens these two cases should behave differently, because the former can be + // canceled while the latter can't. Currently, we figure this out in + // #didAutoCorrectToAnotherWord with #equals(). It would be marginally cleaner to do it + // here, but it would be slower (since we would #equals() for each commit, instead of + // only on cancel), and ultimately we want to figure it out even earlier anyway. + if (type != COMMIT_TYPE_DECIDED_WORD) { + // Only ever revert an auto-correct. + mCommittedWordSavedForSuggestionResuming.mAutoCorrection = null; + } // TODO: improve performance by swapping buffers instead of creating a new object. mCurrentWord = new CharacterStore(); } -- cgit v1.2.3-83-g751a From 0d0f01da674e89e294d14061837711996dc5a693 Mon Sep 17 00:00:00 2001 From: Ken Wakasa Date: Wed, 21 Dec 2011 22:34:08 +0900 Subject: Fix a typo. A follow up to I68dd6b8d Change-Id: I16fa4099c75faac35344b0e4d3c2b866ddac896a --- java/src/com/android/inputmethod/latin/WordComposer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 7e844e9f4..e95dcfdc9 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -349,7 +349,7 @@ public class WordComposer { // `type' should be one of the COMMIT_TYPE_* constants above. public void onCommitWord(final int type) { mCommittedWordSavedForSuggestionResuming = mCurrentWord; - // Note: currently, we come here whenever we commit a word. If it's any *other* kind that + // Note: currently, we come here whenever we commit a word. If it's any *other* kind than // DECIDED_WORD, we should reset mAutoCorrection so that we don't attempt to cancel later. // If it's a DECIDED_WORD, it may be an actual auto-correction by the IME, or what the user // typed because the IME decided *not* to auto-correct for whatever reason. -- cgit v1.2.3-83-g751a From 267563d1bb4d8091293fbd8774f0f95ef59f03c4 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 26 Jan 2012 15:52:55 +0900 Subject: Add a class for previously composed data (A1) Change-Id: I87498799e6a48b8fa65924a098bb0ceb7626dce1 --- .../inputmethod/latin/LastComposedWord.java | 44 ++++++++++++++++++++++ .../com/android/inputmethod/latin/LatinIME.java | 8 ++-- .../android/inputmethod/latin/WordComposer.java | 24 ++---------- 3 files changed, 52 insertions(+), 24 deletions(-) create mode 100644 java/src/com/android/inputmethod/latin/LastComposedWord.java (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java new file mode 100644 index 000000000..dcecdb3b5 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +/** + * This class encapsulates data about a word previously composed, but that has been + * committed already. This is used for resuming suggestion, and cancel auto-correction. + */ +public class LastComposedWord { + // COMMIT_TYPE_USER_TYPED_WORD is used when the word committed is the exact typed word, with + // no hinting from the IME. It happens when some external event happens (rotating the device, + // for example) or when auto-correction is off by settings or editor attributes. + public static final int COMMIT_TYPE_USER_TYPED_WORD = 0; + // COMMIT_TYPE_MANUAL_PICK is used when the user pressed a field in the suggestion strip. + public static final int COMMIT_TYPE_MANUAL_PICK = 1; + // COMMIT_TYPE_DECIDED_WORD is used when the IME commits the word it decided was best + // for the current user input. It may be different from what the user typed (true auto-correct) + // or it may be exactly what the user typed if it's in the dictionary or the IME does not have + // enough confidence in any suggestion to auto-correct (auto-correct to typed word). + public static final int COMMIT_TYPE_DECIDED_WORD = 2; + // COMMIT_TYPE_CANCEL_AUTO_CORRECT is used upon committing back the old word upon cancelling + // an auto-correction. + public static final int COMMIT_TYPE_CANCEL_AUTO_CORRECT = 3; + + public final int mType; + + public LastComposedWord(final int type) { + mType = type; + } +} diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index f2fa7880f..51e3998c4 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1096,7 +1096,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public void commitTyped(final InputConnection ic) { if (!mWordComposer.isComposingWord()) return; final CharSequence typedWord = mWordComposer.getTypedWord(); - mWordComposer.onCommitWord(WordComposer.COMMIT_TYPE_USER_TYPED_WORD); + mWordComposer.onCommitWord(LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD); if (typedWord.length() > 0) { if (ic != null) { ic.commitText(typedWord, 1); @@ -1847,7 +1847,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint); mExpectingUpdateSelection = true; - commitChosenWord(autoCorrection, WordComposer.COMMIT_TYPE_DECIDED_WORD); + commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD); // Add the word to the user unigram dictionary if it's not a known word addToUserUnigramAndBigramDictionaries(autoCorrection, UserUnigramDictionary.FREQUENCY_FOR_TYPED); @@ -1917,7 +1917,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(), suggestion.toString(), index, suggestions.mWords); mExpectingUpdateSelection = true; - commitChosenWord(suggestion, WordComposer.COMMIT_TYPE_MANUAL_PICK); + commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK); // Add the word to the auto dictionary if it's not a known word if (index == 0) { addToUserUnigramAndBigramDictionaries(suggestion, @@ -2176,7 +2176,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Re-insert the separator ic.commitText(separator, 1); mWordComposer.deleteAutoCorrection(); - mWordComposer.onCommitWord(WordComposer.COMMIT_TYPE_CANCEL_AUTO_CORRECT); + mWordComposer.onCommitWord(LastComposedWord.COMMIT_TYPE_CANCEL_AUTO_CORRECT); Utils.Stats.onSeparator(separator.charAt(0), WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); mHandler.cancelUpdateBigramPredictions(); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index e95dcfdc9..02968c934 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -33,23 +33,6 @@ public class WordComposer { public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE; public static final int NOT_A_COORDINATE = -1; - // TODO: Straighten out commit behavior so that the flags here are more understandable, - // and possibly adjust their names. - // COMMIT_TYPE_USER_TYPED_WORD is used when the word committed is the exact typed word, with - // no hinting from the IME. It happens when some external event happens (rotating the device, - // for example) or when auto-correction is off by settings or editor attributes. - public static final int COMMIT_TYPE_USER_TYPED_WORD = 0; - // COMMIT_TYPE_MANUAL_PICK is used when the user pressed a field in the suggestion strip. - public static final int COMMIT_TYPE_MANUAL_PICK = 1; - // COMMIT_TYPE_DECIDED_WORD is used when the IME commits the word it decided was best - // for the current user input. It may be different from what the user typed (true auto-correct) - // or it may be exactly what the user typed if it's in the dictionary or the IME does not have - // enough confidence in any suggestion to auto-correct (auto-correct to typed word). - public static final int COMMIT_TYPE_DECIDED_WORD = 2; - // COMMIT_TYPE_CANCEL_AUTO_CORRECT is used upon committing back the old word upon cancelling - // an auto-correction. - public static final int COMMIT_TYPE_CANCEL_AUTO_CORRECT = 3; - // Storage for all the info about the current input. private static class CharacterStore { /** @@ -346,8 +329,8 @@ public class WordComposer { return mCurrentWord.mAutoCorrection; } - // `type' should be one of the COMMIT_TYPE_* constants above. - public void onCommitWord(final int type) { + // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. + public LastComposedWord onCommitWord(final int type) { mCommittedWordSavedForSuggestionResuming = mCurrentWord; // Note: currently, we come here whenever we commit a word. If it's any *other* kind than // DECIDED_WORD, we should reset mAutoCorrection so that we don't attempt to cancel later. @@ -359,12 +342,13 @@ public class WordComposer { // #didAutoCorrectToAnotherWord with #equals(). It would be marginally cleaner to do it // here, but it would be slower (since we would #equals() for each commit, instead of // only on cancel), and ultimately we want to figure it out even earlier anyway. - if (type != COMMIT_TYPE_DECIDED_WORD) { + if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) { // Only ever revert an auto-correct. mCommittedWordSavedForSuggestionResuming.mAutoCorrection = null; } // TODO: improve performance by swapping buffers instead of creating a new object. mCurrentWord = new CharacterStore(); + return new LastComposedWord(type); } public boolean hasWordKeptForSuggestionResuming() { -- cgit v1.2.3-83-g751a From 1f8fc62ccb5018716457dc309ab11ad3e1506ad1 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 26 Jan 2012 16:05:09 +0900 Subject: Add useful information to LastComposedWord (A2) Change-Id: Idf47f2e2bdd1d6394fc4b1ab7df28d64a808da1e --- .../com/android/inputmethod/latin/LastComposedWord.java | 15 ++++++++++++++- java/src/com/android/inputmethod/latin/WordComposer.java | 5 ++++- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index dcecdb3b5..612ed424d 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin; +import java.util.ArrayList; + /** * This class encapsulates data about a word previously composed, but that has been * committed already. This is used for resuming suggestion, and cancel auto-correction. @@ -37,8 +39,19 @@ public class LastComposedWord { public static final int COMMIT_TYPE_CANCEL_AUTO_CORRECT = 3; public final int mType; + public final ArrayList mCodes; + public final int[] mXCoordinates; + public final int[] mYCoordinates; + public final String mTypedWord; + public final String mAutoCorrection; - public LastComposedWord(final int type) { + public LastComposedWord(final int type, final ArrayList codes, final int[] xCoordinates, + final int[] yCoordinates, final String typedWord, final String autoCorrection) { mType = type; + mCodes = codes; + mXCoordinates = xCoordinates; + mYCoordinates = yCoordinates; + mTypedWord = typedWord; + mAutoCorrection = autoCorrection; } } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 02968c934..adadd9394 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -346,9 +346,12 @@ public class WordComposer { // Only ever revert an auto-correct. mCommittedWordSavedForSuggestionResuming.mAutoCorrection = null; } + final LastComposedWord lastComposedWord = new LastComposedWord(type, mCurrentWord.mCodes, + mCurrentWord.mXCoordinates, mCurrentWord.mYCoordinates, + mCurrentWord.mTypedWord.toString(), mCurrentWord.mAutoCorrection.toString()); // TODO: improve performance by swapping buffers instead of creating a new object. mCurrentWord = new CharacterStore(); - return new LastComposedWord(type); + return lastComposedWord; } public boolean hasWordKeptForSuggestionResuming() { -- cgit v1.2.3-83-g751a From 2692a8700737d8eed268039aa27b22a31669da08 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 26 Jan 2012 16:37:47 +0900 Subject: Move some functionality into LastComposedWord (A3) Change-Id: Ie0ea02a061dd0cb84db5f33113ff433584636bc7 --- .../inputmethod/latin/LastComposedWord.java | 10 +++++++ .../com/android/inputmethod/latin/LatinIME.java | 33 ++++++++++++++++------ .../android/inputmethod/latin/WordComposer.java | 13 +++------ 3 files changed, 38 insertions(+), 18 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index 612ed424d..accc6307a 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin; +import android.text.TextUtils; + import java.util.ArrayList; /** @@ -45,6 +47,9 @@ public class LastComposedWord { public final String mTypedWord; public final String mAutoCorrection; + public static final LastComposedWord NOT_A_COMPOSED_WORD = + new LastComposedWord(COMMIT_TYPE_USER_TYPED_WORD, null, null, null, "", ""); + public LastComposedWord(final int type, final ArrayList codes, final int[] xCoordinates, final int[] yCoordinates, final String typedWord, final String autoCorrection) { mType = type; @@ -54,4 +59,9 @@ public class LastComposedWord { mTypedWord = typedWord; mAutoCorrection = autoCorrection; } + + public boolean didAutoCorrectToAnotherWord() { + return !TextUtils.isEmpty(mAutoCorrection) + && !TextUtils.equals(mTypedWord, mAutoCorrection); + } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 51e3998c4..5ef35dab5 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -199,6 +199,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private UserUnigramDictionary mUserUnigramDictionary; private boolean mIsUserDictionaryAvailable; + private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; private WordComposer mWordComposer = new WordComposer(); private int mCorrectionMode; @@ -769,7 +770,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar inputView.closing(); mEnteredText = null; - mWordComposer.reset(); + resetComposingState(true /* alsoResetLastComposedWord */); mDeleteCount = 0; mSpaceState = SPACE_STATE_NONE; @@ -881,7 +882,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (((mWordComposer.isComposingWord()) || mVoiceProxy.isVoiceInputHighlighted()) && (selectionChanged || candidatesCleared)) { - mWordComposer.reset(); + resetComposingState(true /* alsoResetLastComposedWord */); updateSuggestions(); final InputConnection ic = getCurrentInputConnection(); if (ic != null) { @@ -890,7 +891,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mComposingStateManager.onFinishComposingText(); mVoiceProxy.setVoiceInputHighlighted(false); } else if (!mWordComposer.isComposingWord()) { - mWordComposer.reset(); + // TODO: is the following reset still needed, given that we are not composing + // a word? + resetComposingState(true /* alsoResetLastComposedWord */); updateSuggestions(); } } @@ -975,6 +978,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // When in fullscreen mode, show completions generated by the application setSuggestions(builder.build()); mWordComposer.deleteAutoCorrection(); + mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; setSuggestionStripShown(true); } } @@ -1093,10 +1097,16 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return super.onKeyUp(keyCode, event); } + private void resetComposingState(final boolean alsoResetLastComposedWord) { + mWordComposer.reset(); + if (alsoResetLastComposedWord) + mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; + } + public void commitTyped(final InputConnection ic) { if (!mWordComposer.isComposingWord()) return; final CharSequence typedWord = mWordComposer.getTypedWord(); - mWordComposer.onCommitWord(LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD); + mLastComposedWord = mWordComposer.commitWord(LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD); if (typedWord.length() > 0) { if (ic != null) { ic.commitText(typedWord, 1); @@ -1325,7 +1335,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mKeyboardSwitcher.onCodeInput(Keyboard.CODE_OUTPUT_TEXT); mSpaceState = SPACE_STATE_NONE; mEnteredText = text; - mWordComposer.reset(); + resetComposingState(true /* alsoResetLastComposedWord */); } @Override @@ -1383,7 +1393,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // resuming here. The behavior needs to be different according to text field types, // and it would be much clearer to test for them explicitly here rather than // relying on implicit values like "whether the suggestion strip is displayed". - if (mWordComposer.didAutoCorrectToAnotherWord()) { + if (mLastComposedWord.didAutoCorrectToAnotherWord()) { Utils.Stats.onAutoCorrectionCancellation(); cancelAutoCorrect(ic); return; @@ -1495,7 +1505,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // separator and it should be treated as a normal character, except in the first // position where it should not start composing a word. isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != code); - mWordComposer.reset(); + // Here we don't need to reset the last composed word. It will be reset + // when we commit this one, if we ever do; if on the other hand we backspace + // it entirely and resume suggestions on the previous word, we'd like to still + // have touch coordinates for it. + resetComposingState(false /* alsoResetLastComposedWord */); clearSuggestions(); mComposingStateManager.onFinishComposingText(); } @@ -1987,7 +2001,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // what user typed. Note: currently this is done much later in // WordComposer#didAutoCorrectToAnotherWord by string equality of the remembered // strings. - mWordComposer.onCommitWord(commitType); + mLastComposedWord = mWordComposer.commitWord(commitType); } private static final WordComposer sEmptyWordComposer = new WordComposer(); @@ -2176,7 +2190,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Re-insert the separator ic.commitText(separator, 1); mWordComposer.deleteAutoCorrection(); - mWordComposer.onCommitWord(LastComposedWord.COMMIT_TYPE_CANCEL_AUTO_CORRECT); + mLastComposedWord = + mWordComposer.commitWord(LastComposedWord.COMMIT_TYPE_CANCEL_AUTO_CORRECT); Utils.Stats.onSeparator(separator.charAt(0), WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); mHandler.cancelUpdateBigramPredictions(); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index adadd9394..f97eb52f6 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -330,7 +330,7 @@ public class WordComposer { } // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. - public LastComposedWord onCommitWord(final int type) { + public LastComposedWord commitWord(final int type) { mCommittedWordSavedForSuggestionResuming = mCurrentWord; // Note: currently, we come here whenever we commit a word. If it's any *other* kind than // DECIDED_WORD, we should reset mAutoCorrection so that we don't attempt to cancel later. @@ -348,7 +348,9 @@ public class WordComposer { } final LastComposedWord lastComposedWord = new LastComposedWord(type, mCurrentWord.mCodes, mCurrentWord.mXCoordinates, mCurrentWord.mYCoordinates, - mCurrentWord.mTypedWord.toString(), mCurrentWord.mAutoCorrection.toString()); + mCurrentWord.mTypedWord.toString(), + null == mCurrentWord.mAutoCorrection + ? null : mCurrentWord.mAutoCorrection.toString()); // TODO: improve performance by swapping buffers instead of creating a new object. mCurrentWord = new CharacterStore(); return lastComposedWord; @@ -362,11 +364,4 @@ public class WordComposer { mCurrentWord = mCommittedWordSavedForSuggestionResuming; mCommittedWordSavedForSuggestionResuming = null; } - - public boolean didAutoCorrectToAnotherWord() { - return null != mCommittedWordSavedForSuggestionResuming - && !TextUtils.isEmpty(mCommittedWordSavedForSuggestionResuming.mAutoCorrection) - && !TextUtils.equals(mCommittedWordSavedForSuggestionResuming.mTypedWord, - mCommittedWordSavedForSuggestionResuming.mAutoCorrection); - } } -- cgit v1.2.3-83-g751a From 2712f23acbb197af3b125da4cc47108e71b7446d Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 26 Jan 2012 16:53:38 +0900 Subject: Remove mCommittedWordSavedForSuggestionResuming (A4) Change-Id: Ia62ef33b5c777a258b02280bda1b8368780a7eef --- .../com/android/inputmethod/latin/LatinIME.java | 4 +-- .../android/inputmethod/latin/WordComposer.java | 36 ++++++++-------------- 2 files changed, 15 insertions(+), 25 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 5ef35dab5..62b287e3c 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -2165,7 +2165,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // "ic" must not be null private void cancelAutoCorrect(final InputConnection ic) { - mWordComposer.resumeSuggestionOnKeptWord(); + mWordComposer.resumeSuggestionOnLastComposedWord(mLastComposedWord); final String originallyTypedWord = mWordComposer.getTypedWord(); final CharSequence autoCorrectedTo = mWordComposer.getAutoCorrectionOrNull(); final int cancelLength = autoCorrectedTo.length(); @@ -2205,7 +2205,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Note: in the interest of code simplicity, we may want to just call // restartSuggestionsOnWordBeforeCursorIfAtEndOfWord instead, but retrieving // the old WordComposer allows to reuse the actual typed coordinates. - mWordComposer.resumeSuggestionOnKeptWord(); + mWordComposer.resumeSuggestionOnLastComposedWord(mLastComposedWord); // We resume suggestion, and then we want to set the composing text to the content // of the word composer again. But since we just manually picked a word, there is // no composing text at the moment, so we have to delete the word before we set a diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index f97eb52f6..f994d68e3 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -67,8 +67,6 @@ public class WordComposer { // The currently typing word. May not be null. private CharacterStore mCurrentWord; - // The information being kept for resuming suggestion. May be null if wiped. - private CharacterStore mCommittedWordSavedForSuggestionResuming; private int mCapsCount; @@ -83,7 +81,6 @@ public class WordComposer { public WordComposer() { mCurrentWord = new CharacterStore(); - mCommittedWordSavedForSuggestionResuming = null; mTrailingSingleQuotesCount = 0; } @@ -93,7 +90,6 @@ public class WordComposer { public void init(WordComposer source) { mCurrentWord = new CharacterStore(source.mCurrentWord); - mCommittedWordSavedForSuggestionResuming = source.mCommittedWordSavedForSuggestionResuming; mCapsCount = source.mCapsCount; mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; @@ -105,7 +101,6 @@ public class WordComposer { */ public void reset() { mCurrentWord.reset(); - mCommittedWordSavedForSuggestionResuming = null; mCapsCount = 0; mIsFirstCharCapitalized = false; mTrailingSingleQuotesCount = 0; @@ -201,7 +196,6 @@ public class WordComposer { int codePoint = word.charAt(i); addKeyInfo(codePoint, keyboard, keyDetector); } - mCommittedWordSavedForSuggestionResuming = null; } /** @@ -331,7 +325,6 @@ public class WordComposer { // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. public LastComposedWord commitWord(final int type) { - mCommittedWordSavedForSuggestionResuming = mCurrentWord; // Note: currently, we come here whenever we commit a word. If it's any *other* kind than // DECIDED_WORD, we should reset mAutoCorrection so that we don't attempt to cancel later. // If it's a DECIDED_WORD, it may be an actual auto-correction by the IME, or what the user @@ -339,29 +332,26 @@ public class WordComposer { // Ideally we would also null it when it was a DECIDED_WORD that was not an auto-correct. // As it happens these two cases should behave differently, because the former can be // canceled while the latter can't. Currently, we figure this out in - // #didAutoCorrectToAnotherWord with #equals(). It would be marginally cleaner to do it - // here, but it would be slower (since we would #equals() for each commit, instead of - // only on cancel), and ultimately we want to figure it out even earlier anyway. - if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) { - // Only ever revert an auto-correct. - mCommittedWordSavedForSuggestionResuming.mAutoCorrection = null; - } + // LastComposedWord#didAutoCorrectToAnotherWord with #equals(). It would be marginally + // cleaner to do it here, but it would be slower (since we would #equals() for each commit, + // instead of only on cancel), and ultimately we want to figure it out even earlier anyway. final LastComposedWord lastComposedWord = new LastComposedWord(type, mCurrentWord.mCodes, mCurrentWord.mXCoordinates, mCurrentWord.mYCoordinates, mCurrentWord.mTypedWord.toString(), - null == mCurrentWord.mAutoCorrection - ? null : mCurrentWord.mAutoCorrection.toString()); + (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) + || (null == mCurrentWord.mAutoCorrection) + ? null : mCurrentWord.mAutoCorrection.toString()); // TODO: improve performance by swapping buffers instead of creating a new object. mCurrentWord = new CharacterStore(); return lastComposedWord; } - public boolean hasWordKeptForSuggestionResuming() { - return null != mCommittedWordSavedForSuggestionResuming; - } - - public void resumeSuggestionOnKeptWord() { - mCurrentWord = mCommittedWordSavedForSuggestionResuming; - mCommittedWordSavedForSuggestionResuming = null; + public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) { + mCurrentWord.mCodes = lastComposedWord.mCodes; + mCurrentWord.mXCoordinates = lastComposedWord.mXCoordinates; + mCurrentWord.mYCoordinates = lastComposedWord.mYCoordinates; + mCurrentWord.mTypedWord.setLength(0); + mCurrentWord.mTypedWord.append(lastComposedWord.mTypedWord); + mCurrentWord.mAutoCorrection = lastComposedWord.mAutoCorrection; } } -- cgit v1.2.3-83-g751a From b6b8729374dc68b153f00730c79828532acf1ee5 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 26 Jan 2012 17:16:40 +0900 Subject: Straighten out resuming suggestion on kept word (A5) This is cleanup. This also introduces a "deactivated" state to the last committed word, that can be used for Bug: 5875776 Change-Id: I1855adb8ac8123f6d2c5365b0ae899145e5c3ba1 --- .../android/inputmethod/latin/LastComposedWord.java | 11 +++++++++-- .../src/com/android/inputmethod/latin/LatinIME.java | 21 +++++++++++---------- .../com/android/inputmethod/latin/WordComposer.java | 7 ------- 3 files changed, 20 insertions(+), 19 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index accc6307a..767c3a7da 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -47,6 +47,8 @@ public class LastComposedWord { public final String mTypedWord; public final String mAutoCorrection; + private boolean mActive; + public static final LastComposedWord NOT_A_COMPOSED_WORD = new LastComposedWord(COMMIT_TYPE_USER_TYPED_WORD, null, null, null, "", ""); @@ -58,10 +60,15 @@ public class LastComposedWord { mYCoordinates = yCoordinates; mTypedWord = typedWord; mAutoCorrection = autoCorrection; + mActive = true; + } + + public void deactivate() { + mActive = false; } - public boolean didAutoCorrectToAnotherWord() { - return !TextUtils.isEmpty(mAutoCorrection) + public boolean canCancelAutoCorrect() { + return mActive && !TextUtils.isEmpty(mAutoCorrection) && !TextUtils.equals(mTypedWord, mAutoCorrection); } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 62b287e3c..94da0cfb2 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -977,8 +977,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar .setHasMinimalSuggestion(false); // When in fullscreen mode, show completions generated by the application setSuggestions(builder.build()); - mWordComposer.deleteAutoCorrection(); - mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; + // TODO: is this the right thing to do? What should we auto-correct to in + // this case? This says to keep whatever the user typed. + mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); setSuggestionStripShown(true); } } @@ -1393,7 +1394,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // resuming here. The behavior needs to be different according to text field types, // and it would be much clearer to test for them explicitly here rather than // relying on implicit values like "whether the suggestion strip is displayed". - if (mLastComposedWord.didAutoCorrectToAnotherWord()) { + if (mLastComposedWord.canCancelAutoCorrect()) { Utils.Stats.onAutoCorrectionCancellation(); cancelAutoCorrect(ic); return; @@ -1999,7 +2000,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } // TODO: figure out here if this is an auto-correct or if the best word is actually // what user typed. Note: currently this is done much later in - // WordComposer#didAutoCorrectToAnotherWord by string equality of the remembered + // LastComposedWord#canCancelAutoCorrect by string equality of the remembered // strings. mLastComposedWord = mWordComposer.commitWord(commitType); } @@ -2165,12 +2166,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // "ic" must not be null private void cancelAutoCorrect(final InputConnection ic) { - mWordComposer.resumeSuggestionOnLastComposedWord(mLastComposedWord); - final String originallyTypedWord = mWordComposer.getTypedWord(); - final CharSequence autoCorrectedTo = mWordComposer.getAutoCorrectionOrNull(); + final String originallyTypedWord = mLastComposedWord.mTypedWord; + final CharSequence autoCorrectedTo = mLastComposedWord.mAutoCorrection; final int cancelLength = autoCorrectedTo.length(); final CharSequence separator = ic.getTextBeforeCursor(1, 0); if (DEBUG) { + if (mWordComposer.isComposingWord()) { + throw new RuntimeException("cancelAutoCorrect, but we are composing a word"); + } final String wordBeforeCursor = ic.getTextBeforeCursor(cancelLength + 1, 0).subSequence(0, cancelLength) .toString(); @@ -2189,9 +2192,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar ic.commitText(originallyTypedWord, 1); // Re-insert the separator ic.commitText(separator, 1); - mWordComposer.deleteAutoCorrection(); - mLastComposedWord = - mWordComposer.commitWord(LastComposedWord.COMMIT_TYPE_CANCEL_AUTO_CORRECT); + mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; Utils.Stats.onSeparator(separator.charAt(0), WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); mHandler.cancelUpdateBigramPredictions(); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index f994d68e3..bf132ed8c 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -309,13 +309,6 @@ public class WordComposer { mCurrentWord.mAutoCorrection = correction; } - /** - * Remove any auto-correction that may have been set. - */ - public void deleteAutoCorrection() { - mCurrentWord.mAutoCorrection = null; - } - /** * @return the auto-correction for this word, or null if none. */ -- cgit v1.2.3-83-g751a From be79227dc99421ff7be62224c51c553b3fa73777 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 26 Jan 2012 17:29:57 +0900 Subject: Remove the CharacterStore class (A7) Remove the now useless WordComposer.CharacterStore class and merge back its members inside WordComposer. This should simplify the word composer a bit. Change-Id: I5fe32418c62a583cd558dce98758a4701559bdf5 --- .../android/inputmethod/latin/WordComposer.java | 120 +++++++++------------ 1 file changed, 50 insertions(+), 70 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index bf132ed8c..12b009662 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -33,45 +33,17 @@ public class WordComposer { public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE; public static final int NOT_A_COORDINATE = -1; - // Storage for all the info about the current input. - private static class CharacterStore { - /** - * The list of unicode values for each keystroke (including surrounding keys) - */ - ArrayList mCodes; - int[] mXCoordinates; - int[] mYCoordinates; - StringBuilder mTypedWord; - CharSequence mAutoCorrection; - CharacterStore() { - final int N = BinaryDictionary.MAX_WORD_LENGTH; - mCodes = new ArrayList(N); - mTypedWord = new StringBuilder(N); - mXCoordinates = new int[N]; - mYCoordinates = new int[N]; - mAutoCorrection = null; - } - CharacterStore(final CharacterStore that) { - mCodes = new ArrayList(that.mCodes); - mTypedWord = new StringBuilder(that.mTypedWord); - mXCoordinates = Arrays.copyOf(that.mXCoordinates, that.mXCoordinates.length); - mYCoordinates = Arrays.copyOf(that.mYCoordinates, that.mYCoordinates.length); - } - void reset() { - // For better performance than creating a new character store. - mCodes.clear(); - mTypedWord.setLength(0); - mAutoCorrection = null; - } - } + final int N = BinaryDictionary.MAX_WORD_LENGTH; - // The currently typing word. May not be null. - private CharacterStore mCurrentWord; + private ArrayList mCodes; + private int[] mXCoordinates; + private int[] mYCoordinates; + private StringBuilder mTypedWord; + private CharSequence mAutoCorrection; + // Cache these values for performance private int mCapsCount; - private boolean mAutoCapitalized; - // Cache this value for performance private int mTrailingSingleQuotesCount; /** @@ -80,7 +52,11 @@ public class WordComposer { private boolean mIsFirstCharCapitalized; public WordComposer() { - mCurrentWord = new CharacterStore(); + mCodes = new ArrayList(N); + mTypedWord = new StringBuilder(N); + mXCoordinates = new int[N]; + mYCoordinates = new int[N]; + mAutoCorrection = null; mTrailingSingleQuotesCount = 0; } @@ -89,7 +65,10 @@ public class WordComposer { } public void init(WordComposer source) { - mCurrentWord = new CharacterStore(source.mCurrentWord); + mCodes = new ArrayList(source.mCodes); + mTypedWord = new StringBuilder(source.mTypedWord); + mXCoordinates = Arrays.copyOf(source.mXCoordinates, source.mXCoordinates.length); + mYCoordinates = Arrays.copyOf(source.mYCoordinates, source.mYCoordinates.length); mCapsCount = source.mCapsCount; mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; @@ -100,7 +79,9 @@ public class WordComposer { * Clear out the keys registered so far. */ public void reset() { - mCurrentWord.reset(); + mCodes.clear(); + mTypedWord.setLength(0); + mAutoCorrection = null; mCapsCount = 0; mIsFirstCharCapitalized = false; mTrailingSingleQuotesCount = 0; @@ -111,7 +92,7 @@ public class WordComposer { * @return the number of keystrokes */ public final int size() { - return mCurrentWord.mTypedWord.length(); + return mTypedWord.length(); } public final boolean isComposingWord() { @@ -124,15 +105,15 @@ public class WordComposer { * @return the unicode for the pressed and surrounding keys */ public int[] getCodesAt(int index) { - return mCurrentWord.mCodes.get(index); + return mCodes.get(index); } public int[] getXCoordinates() { - return mCurrentWord.mXCoordinates; + return mXCoordinates; } public int[] getYCoordinates() { - return mCurrentWord.mYCoordinates; + return mYCoordinates; } private static boolean isFirstCharCapitalized(int index, int codePoint, boolean previous) { @@ -147,12 +128,12 @@ public class WordComposer { */ public void add(int primaryCode, int[] codes, int x, int y) { final int newIndex = size(); - mCurrentWord.mTypedWord.append((char) primaryCode); + mTypedWord.append((char) primaryCode); correctPrimaryJuxtapos(primaryCode, codes); - mCurrentWord.mCodes.add(codes); + mCodes.add(codes); if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { - mCurrentWord.mXCoordinates[newIndex] = x; - mCurrentWord.mYCoordinates[newIndex] = y; + mXCoordinates[newIndex] = x; + mYCoordinates[newIndex] = y; } mIsFirstCharCapitalized = isFirstCharCapitalized( newIndex, primaryCode, mIsFirstCharCapitalized); @@ -162,7 +143,7 @@ public class WordComposer { } else { mTrailingSingleQuotesCount = 0; } - mCurrentWord.mAutoCorrection = null; + mAutoCorrection = null; } /** @@ -231,9 +212,9 @@ public class WordComposer { final int size = size(); if (size > 0) { final int lastPos = size - 1; - char lastChar = mCurrentWord.mTypedWord.charAt(lastPos); - mCurrentWord.mCodes.remove(lastPos); - mCurrentWord.mTypedWord.deleteCharAt(lastPos); + char lastChar = mTypedWord.charAt(lastPos); + mCodes.remove(lastPos); + mTypedWord.deleteCharAt(lastPos); if (Character.isUpperCase(lastChar)) mCapsCount--; } if (size() == 0) { @@ -242,12 +223,12 @@ public class WordComposer { if (mTrailingSingleQuotesCount > 0) { --mTrailingSingleQuotesCount; } else { - for (int i = mCurrentWord.mTypedWord.length() - 1; i >= 0; --i) { - if (Keyboard.CODE_SINGLE_QUOTE != mCurrentWord.mTypedWord.codePointAt(i)) break; + for (int i = mTypedWord.length() - 1; i >= 0; --i) { + if (Keyboard.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break; ++mTrailingSingleQuotesCount; } } - mCurrentWord.mAutoCorrection = null; + mAutoCorrection = null; } /** @@ -255,7 +236,7 @@ public class WordComposer { * @return the word that was typed so far. Never returns null. */ public String getTypedWord() { - return mCurrentWord.mTypedWord.toString(); + return mTypedWord.toString(); } /** @@ -306,14 +287,14 @@ public class WordComposer { * Sets the auto-correction for this word. */ public void setAutoCorrection(final CharSequence correction) { - mCurrentWord.mAutoCorrection = correction; + mAutoCorrection = correction; } /** * @return the auto-correction for this word, or null if none. */ public CharSequence getAutoCorrectionOrNull() { - return mCurrentWord.mAutoCorrection; + return mAutoCorrection; } // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. @@ -328,23 +309,22 @@ public class WordComposer { // LastComposedWord#didAutoCorrectToAnotherWord with #equals(). It would be marginally // cleaner to do it here, but it would be slower (since we would #equals() for each commit, // instead of only on cancel), and ultimately we want to figure it out even earlier anyway. - final LastComposedWord lastComposedWord = new LastComposedWord(type, mCurrentWord.mCodes, - mCurrentWord.mXCoordinates, mCurrentWord.mYCoordinates, - mCurrentWord.mTypedWord.toString(), - (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) - || (null == mCurrentWord.mAutoCorrection) - ? null : mCurrentWord.mAutoCorrection.toString()); - // TODO: improve performance by swapping buffers instead of creating a new object. - mCurrentWord = new CharacterStore(); + final LastComposedWord lastComposedWord = new LastComposedWord(type, mCodes, + mXCoordinates, mYCoordinates, mTypedWord.toString(), + (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) || (null == mAutoCorrection) + ? null : mAutoCorrection.toString()); + mCodes.clear(); + mTypedWord.setLength(0); + mAutoCorrection = null; return lastComposedWord; } public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) { - mCurrentWord.mCodes = lastComposedWord.mCodes; - mCurrentWord.mXCoordinates = lastComposedWord.mXCoordinates; - mCurrentWord.mYCoordinates = lastComposedWord.mYCoordinates; - mCurrentWord.mTypedWord.setLength(0); - mCurrentWord.mTypedWord.append(lastComposedWord.mTypedWord); - mCurrentWord.mAutoCorrection = lastComposedWord.mAutoCorrection; + mCodes = lastComposedWord.mCodes; + mXCoordinates = lastComposedWord.mXCoordinates; + mYCoordinates = lastComposedWord.mYCoordinates; + mTypedWord.setLength(0); + mTypedWord.append(lastComposedWord.mTypedWord); + mAutoCorrection = lastComposedWord.mAutoCorrection; } } -- cgit v1.2.3-83-g751a From 5971a0a0bbbb671bb5b7d5cc7829ddf169c0cc7a Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 26 Jan 2012 17:43:10 +0900 Subject: Remove a useless member (A8) It turns out this can be removed entirely. Change-Id: I6f23703cef1666311989a825285317eef696487f --- java/src/com/android/inputmethod/latin/LastComposedWord.java | 6 ++---- java/src/com/android/inputmethod/latin/WordComposer.java | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index 767c3a7da..0c8c88f50 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -40,7 +40,6 @@ public class LastComposedWord { // an auto-correction. public static final int COMMIT_TYPE_CANCEL_AUTO_CORRECT = 3; - public final int mType; public final ArrayList mCodes; public final int[] mXCoordinates; public final int[] mYCoordinates; @@ -50,11 +49,10 @@ public class LastComposedWord { private boolean mActive; public static final LastComposedWord NOT_A_COMPOSED_WORD = - new LastComposedWord(COMMIT_TYPE_USER_TYPED_WORD, null, null, null, "", ""); + new LastComposedWord(null, null, null, "", ""); - public LastComposedWord(final int type, final ArrayList codes, final int[] xCoordinates, + public LastComposedWord(final ArrayList codes, final int[] xCoordinates, final int[] yCoordinates, final String typedWord, final String autoCorrection) { - mType = type; mCodes = codes; mXCoordinates = xCoordinates; mYCoordinates = yCoordinates; diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 12b009662..b96b0842a 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -309,7 +309,7 @@ public class WordComposer { // LastComposedWord#didAutoCorrectToAnotherWord with #equals(). It would be marginally // cleaner to do it here, but it would be slower (since we would #equals() for each commit, // instead of only on cancel), and ultimately we want to figure it out even earlier anyway. - final LastComposedWord lastComposedWord = new LastComposedWord(type, mCodes, + final LastComposedWord lastComposedWord = new LastComposedWord(mCodes, mXCoordinates, mYCoordinates, mTypedWord.toString(), (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) || (null == mAutoCorrection) ? null : mAutoCorrection.toString()); -- cgit v1.2.3-83-g751a From 449415c72f437f523a49a9ccfcde8a3c0f583a18 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 26 Jan 2012 19:05:59 +0900 Subject: Cleanup (A9) Deactivate the LastComposedWord when the commit was not the right type, instead of fooling it by passing it a null auto-correction. Change-Id: I032b477dc691bd151a644ca4b0c9f0a9b5512e45 --- java/src/com/android/inputmethod/latin/WordComposer.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index b96b0842a..230c2916b 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -311,8 +311,10 @@ public class WordComposer { // instead of only on cancel), and ultimately we want to figure it out even earlier anyway. final LastComposedWord lastComposedWord = new LastComposedWord(mCodes, mXCoordinates, mYCoordinates, mTypedWord.toString(), - (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) || (null == mAutoCorrection) - ? null : mAutoCorrection.toString()); + null == mAutoCorrection ? null : mAutoCorrection.toString()); + if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) { + lastComposedWord.deactivate(); + } mCodes.clear(); mTypedWord.setLength(0); mAutoCorrection = null; -- cgit v1.2.3-83-g751a From e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476c Mon Sep 17 00:00:00 2001 From: satok Date: Tue, 31 Jan 2012 17:15:43 +0900 Subject: Support additional proximity characters Change-Id: Ifbe0d7e4eafea1926bbce968eae4724dd5769689 --- java/res/values-en/additional-proximitychars.xml | 62 +++++++++ java/res/values/additional-proximitychars.xml | 23 ++++ .../android/inputmethod/keyboard/KeyDetector.java | 41 +++++- .../com/android/inputmethod/keyboard/Keyboard.java | 36 ++++- .../inputmethod/keyboard/ProximityInfo.java | 50 +++++-- .../android/inputmethod/latin/WordComposer.java | 4 +- native/src/correction.cpp | 146 ++++++++++++++------- native/src/correction.h | 2 +- native/src/defines.h | 9 ++ native/src/proximity_info.cpp | 18 ++- native/src/proximity_info.h | 4 +- 11 files changed, 327 insertions(+), 68 deletions(-) create mode 100644 java/res/values-en/additional-proximitychars.xml create mode 100644 java/res/values/additional-proximitychars.xml (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/res/values-en/additional-proximitychars.xml b/java/res/values-en/additional-proximitychars.xml new file mode 100644 index 000000000..0e1276796 --- /dev/null +++ b/java/res/values-en/additional-proximitychars.xml @@ -0,0 +1,62 @@ + + + + + + + + + a + e + i + o + u + + + e + a + i + o + u + + + i + a + e + o + u + + + o + a + e + i + u + + + u + a + e + i + o + + + + \ No newline at end of file diff --git a/java/res/values/additional-proximitychars.xml b/java/res/values/additional-proximitychars.xml new file mode 100644 index 000000000..03d10d5d8 --- /dev/null +++ b/java/res/values/additional-proximitychars.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index 0d271625b..bff491ffd 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -19,12 +19,14 @@ package com.android.inputmethod.keyboard; import android.util.Log; import java.util.Arrays; +import java.util.List; public class KeyDetector { private static final String TAG = KeyDetector.class.getSimpleName(); private static final boolean DEBUG = false; public static final int NOT_A_CODE = -1; + private static final int ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE = 2; private final int mKeyHysteresisDistanceSquared; @@ -154,8 +156,9 @@ public class KeyDetector { return distances.length; } - private void getNearbyKeyCodes(final int[] allCodes) { + private void getNearbyKeyCodes(final int primaryCode, final int[] allCodes) { final Key[] neighborKeys = mNeighborKeys; + final int maxCodesSize = allCodes.length; // allCodes[0] should always have the key code even if it is a non-letter key. if (neighborKeys[0] == null) { @@ -164,7 +167,7 @@ public class KeyDetector { } int numCodes = 0; - for (int j = 0; j < neighborKeys.length && numCodes < allCodes.length; j++) { + for (int j = 0; j < neighborKeys.length && numCodes < maxCodesSize; j++) { final Key key = neighborKeys[j]; if (key == null) break; @@ -174,6 +177,38 @@ public class KeyDetector { continue; allCodes[numCodes++] = code; } + if (maxCodesSize <= numCodes) { + return; + } + if (primaryCode != NOT_A_CODE) { + final List additionalChars = + mKeyboard.getAdditionalProximityChars().get(primaryCode); + if (additionalChars == null || additionalChars.size() == 0) { + return; + } + int currentCodesSize = numCodes; + allCodes[numCodes++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE; + if (maxCodesSize <= numCodes) { + return; + } + // TODO: This is O(N^2). Assuming additionalChars.size() is up to 4 or 5. + for (int i = 0; i < additionalChars.size(); ++i) { + final int additionalChar = additionalChars.get(i); + boolean contains = false; + for (int j = 0; j < currentCodesSize; ++j) { + if (additionalChar == allCodes[j]) { + contains = true; + break; + } + } + if (!contains) { + allCodes[numCodes++] = additionalChar; + if (maxCodesSize <= numCodes) { + return; + } + } + } + } } /** @@ -205,7 +240,7 @@ public class KeyDetector { } if (allCodes != null && allCodes.length > 0) { - getNearbyKeyCodes(allCodes); + getNearbyKeyCodes(primaryKey != null ? primaryKey.mCode : NOT_A_CODE, allCodes); if (DEBUG) { Log.d(TAG, "x=" + x + " y=" + y + " primary=" + printableCode(primaryKey) diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 6653dec4b..10e0a5b01 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; @@ -38,10 +39,12 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -130,6 +133,8 @@ public class Keyboard { private final ProximityInfo mProximityInfo; + public final Map> mAdditionalProximityChars; + public Keyboard(Params params) { mId = params.mId; mThemeId = params.mThemeId; @@ -146,10 +151,12 @@ public class Keyboard { mKeys = Collections.unmodifiableSet(params.mKeys); mShiftKeys = Collections.unmodifiableSet(params.mShiftKeys); mIconsSet = params.mIconsSet; + mAdditionalProximityChars = params.mAdditionalProximityChars; mProximityInfo = new ProximityInfo( params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, - mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection); + mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection, + params.mAdditionalProximityChars); } public ProximityInfo getProximityInfo() { @@ -227,6 +234,9 @@ public class Keyboard { public final Set mKeys = new HashSet(); public final Set mShiftKeys = new HashSet(); public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); + // TODO: Should be in Key instead of Keyboard.Params? + public final Map> mAdditionalProximityChars = + new HashMap>(); public KeyboardSet.KeysCache mKeysCache; @@ -358,6 +368,10 @@ public class Keyboard { return mProximityInfo.getNearestKeys(adjustedX, adjustedY); } + public Map> getAdditionalProximityChars() { + return mAdditionalProximityChars; + } + public static String printableCode(int code) { switch (code) { case CODE_SHIFT: return "shift"; @@ -614,6 +628,7 @@ public class Keyboard { mParams = params; setTouchPositionCorrectionData(context, params); + setAdditionalProximityChars(context, params); params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width); params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height); @@ -636,6 +651,25 @@ public class Keyboard { params.mTouchPositionCorrection.load(data); } + private static void setAdditionalProximityChars(Context context, Params params) { + final String[] additionalChars = + context.getResources().getStringArray(R.array.additional_proximitychars); + int currentPrimaryIndex = 0; + for (int i = 0; i < additionalChars.length; ++i) { + final String additionalChar = additionalChars[i]; + if (TextUtils.isEmpty(additionalChar)) { + currentPrimaryIndex = 0; + } else if (currentPrimaryIndex == 0) { + currentPrimaryIndex = additionalChar.charAt(0); + params.mAdditionalProximityChars.put( + currentPrimaryIndex, new ArrayList()); + } else if (currentPrimaryIndex != 0) { + final int c = additionalChar.charAt(0); + params.mAdditionalProximityChars.get(currentPrimaryIndex).add(c); + } + } + } + public void setAutoGenerate(KeyboardSet.KeysCache keysCache) { mParams.mKeysCache = keysCache; } diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index c1dae0601..2d1a0083d 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -24,6 +24,9 @@ import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Set; public class ProximityInfo { @@ -44,7 +47,8 @@ public class ProximityInfo { private final Key[][] mGridNeighbors; ProximityInfo(int gridWidth, int gridHeight, int minWidth, int height, int keyWidth, - int keyHeight, Set keys, TouchPositionCorrection touchPositionCorrection) { + int keyHeight, Set keys, TouchPositionCorrection touchPositionCorrection, + Map> additionalProximityChars) { mGridWidth = gridWidth; mGridHeight = gridHeight; mGridSize = mGridWidth * mGridHeight; @@ -58,20 +62,20 @@ public class ProximityInfo { // No proximity required. Keyboard might be mini keyboard. return; } - computeNearestNeighbors(keyWidth, keys, touchPositionCorrection); + computeNearestNeighbors(keyWidth, keys, touchPositionCorrection, additionalProximityChars); } public static ProximityInfo createDummyProximityInfo() { - return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.emptySet(), null); + return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections. emptySet(), + null, Collections.> emptyMap()); } public static ProximityInfo createSpellCheckerProximityInfo(final int[] proximity) { final ProximityInfo spellCheckerProximityInfo = createDummyProximityInfo(); spellCheckerProximityInfo.mNativeProximityInfo = spellCheckerProximityInfo.setProximityInfoNative( - SpellCheckerProximityInfo.ROW_SIZE, - 480, 300, 11, 3, proximity, - 0, null, null, null, null, null, null, null, null); + SpellCheckerProximityInfo.ROW_SIZE, 480, 300, 11, 3, proximity, 0, + null, null, null, null, null, null, null, null); return spellCheckerProximityInfo; } @@ -79,11 +83,13 @@ public class ProximityInfo { static { Utils.loadNativeLibrary(); } + private native long 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, float[] sweetSpotCenterX, float[] sweetSpotCenterY, float[] sweetSpotRadii); + private native void releaseProximityInfoNative(long nativeProximityInfo); private final void setProximityInfo(Key[][] gridNeighborKeys, int keyboardWidth, @@ -138,7 +144,7 @@ public class ProximityInfo { final float radius = touchPositionCorrection.mRadii[row]; sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth; sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight; - sweetSpotRadii[i] = radius * (float)Math.sqrt( + sweetSpotRadii[i] = radius * (float) Math.sqrt( hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight); } } @@ -168,7 +174,12 @@ public class ProximityInfo { } private void computeNearestNeighbors(int defaultWidth, Set keys, - TouchPositionCorrection touchPositionCorrection) { + TouchPositionCorrection touchPositionCorrection, + Map> additionalProximityChars) { + final Map keyCodeMap = new HashMap(); + for (final Key key : keys) { + keyCodeMap.put(key.mCode, key); + } final int thresholdBase = (int) (defaultWidth * SEARCH_DISTANCE); final int threshold = thresholdBase * thresholdBase; // Round-up so we don't have any pixels outside the grid @@ -186,6 +197,27 @@ public class ProximityInfo { neighborKeys[count++] = key; } } + int currentCodesSize = count; + for (int i = 0; i < currentCodesSize; ++i) { + final int c = neighborKeys[i].mCode; + final List additionalChars = additionalProximityChars.get(c); + if (additionalChars == null || additionalChars.size() == 0) { + continue; + } + for (int j = 0; j < additionalChars.size(); ++j) { + final int additionalChar = additionalChars.get(j); + boolean contains = false; + for (int k = 0; k < count; ++k) { + if(additionalChar == neighborKeys[k].mCode) { + contains = true; + break; + } + } + if (!contains) { + neighborKeys[count++] = keyCodeMap.get(additionalChar); + } + } + } mGridNeighbors[(y / mCellHeight) * mGridWidth + (x / mCellWidth)] = Arrays.copyOfRange(neighborKeys, 0, count); } @@ -199,7 +231,7 @@ public class ProximityInfo { return EMPTY_KEY_ARRAY; } if (x >= 0 && x < mKeyboardMinWidth && y >= 0 && y < mKeyboardHeight) { - int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth); + int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth); if (index < mGridSize) { return mGridNeighbors[index]; } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 230c2916b..bd244b913 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -16,8 +16,6 @@ package com.android.inputmethod.latin; -import android.text.TextUtils; - import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; @@ -33,7 +31,7 @@ public class WordComposer { public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE; public static final int NOT_A_COORDINATE = -1; - final int N = BinaryDictionary.MAX_WORD_LENGTH; + final static int N = BinaryDictionary.MAX_WORD_LENGTH; private ArrayList mCodes; private int[] mXCoordinates; diff --git a/native/src/correction.cpp b/native/src/correction.cpp index 7323747d7..dafc0fd7f 100644 --- a/native/src/correction.cpp +++ b/native/src/correction.cpp @@ -383,7 +383,10 @@ Correction::CorrectionType Correction::processCharAndCalcState( incrementInputIndex(); } else { --mTransposedCount; - if (DEBUG_CORRECTION) { + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 + || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { DUMP_WORD(mWord, mOutputIndex); AKLOGI("UNRELATED(0): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, mTransposedCount, mExcessiveCount, c); @@ -404,13 +407,17 @@ Correction::CorrectionType Correction::processCharAndCalcState( : mProximityInfo->getMatchedProximityId( mInputIndex, c, checkProximityChars, &proximityIndex); - if (ProximityInfo::UNRELATED_CHAR == matchedProximityCharId) { + if (ProximityInfo::UNRELATED_CHAR == matchedProximityCharId + || ProximityInfo::ADDITIONAL_PROXIMITY_CHAR == matchedProximityCharId) { if (canTryCorrection && mOutputIndex > 0 && mCorrectionStates[mOutputIndex].mProximityMatching && mCorrectionStates[mOutputIndex].mExceeding && isEquivalentChar(mProximityInfo->getMatchedProximityId( mInputIndex, mWord[mOutputIndex - 1], false))) { - if (DEBUG_CORRECTION) { + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 + || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { AKLOGI("CONVERSION p->e %c", mWord[mOutputIndex - 1]); } // Conversion p->e @@ -429,7 +436,8 @@ Correction::CorrectionType Correction::processCharAndCalcState( } } - if (ProximityInfo::UNRELATED_CHAR == matchedProximityCharId) { + if (ProximityInfo::UNRELATED_CHAR == matchedProximityCharId + || ProximityInfo::ADDITIONAL_PROXIMITY_CHAR == matchedProximityCharId) { // TODO: Optimize // As the current char turned out to be an unrelated char, // we will try other correction-types. Please note that mCorrectionStates[mOutputIndex] @@ -481,12 +489,47 @@ Correction::CorrectionType Correction::processCharAndCalcState( ++mExcessiveCount; incrementInputIndex(); } + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 + || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { + DUMP_WORD(mWord, mOutputIndex); + if (mTransposing) { + AKLOGI("TRANSPOSE: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, + mTransposedCount, mExcessiveCount, c); + } else { + AKLOGI("EXCEED: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, + mTransposedCount, mExcessiveCount, c); + } + } } else if (mSkipping) { // 3. Skip correction ++mSkippedCount; + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 + || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { + AKLOGI("SKIP: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, + mTransposedCount, mExcessiveCount, c); + } return processSkipChar(c, isTerminal, false); + } else if (ProximityInfo::ADDITIONAL_PROXIMITY_CHAR == matchedProximityCharId) { + // As a last resort, use additional proximity characters + mProximityMatching = true; + ++mProximityCount; + mDistances[mOutputIndex] = ADDITIONAL_PROXIMITY_CHAR_DISTANCE_INFO; + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 + || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { + AKLOGI("ADDITIONALPROX: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, + mTransposedCount, mExcessiveCount, c); + } } else { - if (DEBUG_CORRECTION) { + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 + || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { DUMP_WORD(mWord, mOutputIndex); AKLOGI("UNRELATED(1): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, mTransposedCount, mExcessiveCount, c); @@ -506,6 +549,13 @@ Correction::CorrectionType Correction::processCharAndCalcState( ++mProximityCount; mDistances[mOutputIndex] = mProximityInfo->getNormalizedSquaredDistance(mInputIndex, proximityIndex); + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 + || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { + AKLOGI("PROX: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, + mTransposedCount, mExcessiveCount, c); + } } addCharToCurrentWord(c); @@ -539,7 +589,9 @@ Correction::CorrectionType Correction::processCharAndCalcState( || isSameAsUserTypedLength) && isTerminal) { mTerminalInputIndex = mInputIndex - 1; mTerminalOutputIndex = mOutputIndex - 1; - if (DEBUG_CORRECTION) { + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { DUMP_WORD(mWord, mOutputIndex); AKLOGI("ONTERMINAL(1): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, mTransposedCount, mExcessiveCount, c); @@ -678,7 +730,7 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const if (excessiveCount > 0) { multiplyRate(WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE, &finalFreq); if (!lastCharExceeded && !proximityInfo->existsAdjacentProximityChars(excessivePos)) { - if (DEBUG_CORRECTION_FREQ) { + if (DEBUG_DICT_FULL) { AKLOGI("Double excessive demotion"); } // If an excessive character is not adjacent to the left char or the right char, @@ -687,51 +739,46 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const } } + const bool performTouchPositionCorrection = + CALIBRATE_SCORE_BY_TOUCH_COORDINATES && proximityInfo->touchPositionCorrectionEnabled() + && skippedCount == 0 && excessiveCount == 0 && transposedCount == 0; // Score calibration by touch coordinates is being done only for pure-fat finger typing error // cases. // TODO: Remove this constraint. - if (CALIBRATE_SCORE_BY_TOUCH_COORDINATES && proximityInfo->touchPositionCorrectionEnabled() - && skippedCount == 0 && excessiveCount == 0 && transposedCount == 0) { - for (int i = 0; i < outputLength; ++i) { - const int squaredDistance = correction->mDistances[i]; - if (i < adjustedProximityMatchedCount) { - multiplyIntCapped(typedLetterMultiplier, &finalFreq); - } - if (squaredDistance >= 0) { - // Promote or demote the score according to the distance from the sweet spot - static const float A = ZERO_DISTANCE_PROMOTION_RATE / 100.0f; - static const float B = 1.0f; - static const float C = 0.5f; - static const float R1 = NEUTRAL_SCORE_SQUARED_RADIUS; - static const float R2 = HALF_SCORE_SQUARED_RADIUS; - const float x = (float)squaredDistance - / ProximityInfo::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR; - const float factor = (x < R1) - ? (A * (R1 - x) + B * x) / R1 - : (B * (R2 - x) + C * (x - R1)) / (R2 - R1); - // factor is piecewise linear function like: - // A -_ . - // ^-_ . - // B \ . - // \ . - // C \ . - // 0 R1 R2 - if (factor <= 0) { - return -1; - } - multiplyRate((int)(factor * 100), &finalFreq); - } else if (squaredDistance == PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO) { - multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq); - } - } - } else { - // Promotion for a word with proximity characters - for (int i = 0; i < adjustedProximityMatchedCount; ++i) { - // A word with proximity corrections - if (DEBUG_DICT_FULL) { - AKLOGI("Found a proximity correction."); - } + for (int i = 0; i < outputLength; ++i) { + const int squaredDistance = correction->mDistances[i]; + if (i < adjustedProximityMatchedCount) { multiplyIntCapped(typedLetterMultiplier, &finalFreq); + } + + if (performTouchPositionCorrection && squaredDistance >= 0) { + // Promote or demote the score according to the distance from the sweet spot + static const float A = ZERO_DISTANCE_PROMOTION_RATE / 100.0f; + static const float B = 1.0f; + static const float C = 0.5f; + static const float MIN = 0.3f; + static const float R1 = NEUTRAL_SCORE_SQUARED_RADIUS; + static const float R2 = HALF_SCORE_SQUARED_RADIUS; + const float x = (float)squaredDistance + / ProximityInfo::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR; + const float factor = max((x < R1) + ? (A * (R1 - x) + B * x) / R1 + : (B * (R2 - x) + C * (x - R1)) / (R2 - R1), MIN); + // factor is piecewise linear function like: + // A -_ . + // ^-_ . + // B \ . + // \_ . + // C ------------. + // . + // 0 R1 R2 . + multiplyRate((int)(factor * 100), &finalFreq); + } else if (performTouchPositionCorrection + && squaredDistance == PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO) { + multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq); + } else if (squaredDistance == ADDITIONAL_PROXIMITY_CHAR_DISTANCE_INFO) { + multiplyRate(WORDS_WITH_ADDITIONAL_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq); + } else if (i < adjustedProximityMatchedCount) { multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq); } } @@ -794,7 +841,8 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const AKLOGI("calc: %d, %d", outputLength, sameLength); } - if (DEBUG_CORRECTION_FREQ) { + if (DEBUG_CORRECTION_FREQ + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == inputLength)) { DUMP_WORD(correction->mWord, outputLength); AKLOGI("FinalFreq: [P%d, S%d, T%d, E%d] %d, %d, %d, %d, %d, %d", proximityMatchedCount, skippedCount, transposedCount, excessiveCount, outputLength, lastCharExceeded, diff --git a/native/src/correction.h b/native/src/correction.h index b246070fe..a711c994d 100644 --- a/native/src/correction.h +++ b/native/src/correction.h @@ -85,7 +85,7 @@ class Correction { } } - Correction(const int typedLetterMultiplier, const int fullWordMultiplier); + Correction(const int typedLetterMultiplier, const int fullWordMultiplier); void initCorrection( const ProximityInfo *pi, const int inputLength, const int maxWordLength); void initCorrectionState(const int rootPos, const int childCount, const bool traverseAll); diff --git a/native/src/defines.h b/native/src/defines.h index 3f3f5ba5c..02c1fe0a2 100644 --- a/native/src/defines.h +++ b/native/src/defines.h @@ -172,6 +172,7 @@ static void prof_out(void) { #define NOT_A_COORDINATE -1 #define EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO -2 #define PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO -3 +#define ADDITIONAL_PROXIMITY_CHAR_DISTANCE_INFO -4 #define NOT_A_INDEX -1 #define NOT_A_FREQUENCY -1 @@ -194,6 +195,7 @@ static void prof_out(void) { #define WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE 70 #define FULL_MATCHED_WORDS_PROMOTION_RATE 120 #define WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE 90 +#define WORDS_WITH_ADDITIONAL_PROXIMITY_CHARACTER_DEMOTION_RATE 30 #define WORDS_WITH_MATCH_SKIP_PROMOTION_RATE 105 #define WORDS_WITH_JUST_ONE_CORRECTION_PROMOTION_RATE 160 #define CORRECTION_COUNT_RATE_DEMOTION_RATE_BASE 45 @@ -210,6 +212,9 @@ static void prof_out(void) { // This is only used for the size of array. Not to be used in c functions. #define MAX_WORD_LENGTH_INTERNAL 48 +// This must be equal to ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE in KeyDetector.java +#define ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE 2 + // Word limit for sub queues used in WordsPriorityQueuePool. Sub queues are temporary queues used // for better performance. // Holds up to 1 candidate for each word @@ -241,4 +246,8 @@ static void prof_out(void) { // The ratio of neutral area radius to sweet spot radius. #define NEUTRAL_AREA_RADIUS_RATIO 1.3f +// DEBUG +#define INPUTLENGTH_FOR_DEBUG -1 +#define MIN_OUTPUT_INDEX_FOR_DEBUG -1 + #endif // LATINIME_DEFINES_H diff --git a/native/src/proximity_info.cpp b/native/src/proximity_info.cpp index e0e938099..b6bab2274 100644 --- a/native/src/proximity_info.cpp +++ b/native/src/proximity_info.cpp @@ -261,7 +261,8 @@ ProximityInfo::ProximityType ProximityInfo::getMatchedProximityId(const int inde // Not an exact nor an accent-alike match: search the list of close keys int j = 1; - while (j < MAX_PROXIMITY_CHARS_SIZE && currentChars[j] > 0) { + while (j < MAX_PROXIMITY_CHARS_SIZE + && currentChars[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) { const bool matched = (currentChars[j] == baseLowerC || currentChars[j] == c); if (matched) { if (proximityIndex) { @@ -271,6 +272,21 @@ ProximityInfo::ProximityType ProximityInfo::getMatchedProximityId(const int inde } ++j; } + if (j < MAX_PROXIMITY_CHARS_SIZE + && currentChars[j] == ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) { + ++j; + while (j < MAX_PROXIMITY_CHARS_SIZE + && currentChars[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) { + const bool matched = (currentChars[j] == baseLowerC || currentChars[j] == c); + if (matched) { + if (proximityIndex) { + *proximityIndex = j; + } + return ADDITIONAL_PROXIMITY_CHAR; + } + ++j; + } + } // Was not included, signal this as an unrelated character. return UNRELATED_CHAR; diff --git a/native/src/proximity_info.h b/native/src/proximity_info.h index 9ca5505a7..b77c1bb0a 100644 --- a/native/src/proximity_info.h +++ b/native/src/proximity_info.h @@ -38,7 +38,9 @@ class ProximityInfo { // It is a char located nearby on the keyboard NEAR_PROXIMITY_CHAR, // It is an unrelated char - UNRELATED_CHAR + UNRELATED_CHAR, + // Additional proximity char which can differ by language. + ADDITIONAL_PROXIMITY_CHAR } ProximityType; ProximityInfo(const int maxProximityCharsSize, const int keyboardWidth, -- cgit v1.2.3-83-g751a From 9242a2bcf8a6b07bb045a8356711bed1493c251e Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 3 Feb 2012 10:51:34 +0900 Subject: Fix string iterations in a couple places. Seems I didn't get how to iterate on a String correctly >.> Talk about a big bug. Anyway, I think it's working now. Bug: 5955228 Change-Id: I988c900cf2a16c44b9505cfd4f77c7cda7e592f0 --- .../com/android/inputmethod/latin/BinaryDictionaryGetter.java | 6 ++++-- java/src/com/android/inputmethod/latin/SettingsValues.java | 5 ++++- java/src/com/android/inputmethod/latin/WordComposer.java | 3 ++- .../latin/spellcheck/AndroidSpellCheckerService.java | 11 +++++------ tests/src/com/android/inputmethod/latin/InputLogicTests.java | 2 +- .../src/com/android/inputmethod/latin/FusionDictionary.java | 2 +- 6 files changed, 17 insertions(+), 12 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java index b333e4873..79441c557 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java @@ -75,7 +75,8 @@ class BinaryDictionaryGetter { // This assumes '%' is fully available as a non-separator, normal // character in a file name. This is probably true for all file systems. final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < name.length(); ++i) { + final int nameLength = name.length(); + for (int i = 0; i < nameLength; i = name.offsetByCodePoints(i, 1)) { final int codePoint = name.codePointAt(i); if (isFileNameCharacter(codePoint)) { sb.appendCodePoint(codePoint); @@ -92,7 +93,8 @@ class BinaryDictionaryGetter { */ private static String getWordListIdFromFileName(final String fname) { final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < fname.length(); ++i) { + final int fnameLength = fname.length(); + for (int i = 0; i < fnameLength; i = fname.offsetByCodePoints(i, 1)) { final int codePoint = fname.codePointAt(i); if ('%' != codePoint) { sb.appendCodePoint(codePoint); diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 8e2f605c4..589cb6f86 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -93,7 +93,8 @@ public class SettingsValues { mMagicSpaceStrippers = res.getString(R.string.magic_space_stripping_symbols); mMagicSpaceSwappers = res.getString(R.string.magic_space_swapping_symbols); if (LatinImeLogger.sDBG) { - for (int i = 0; i < mMagicSpaceStrippers.length(); ++i) { + final int length = mMagicSpaceStrippers.length(); + for (int i = 0; i < length; i = mMagicSpaceStrippers.offsetByCodePoints(i, 1)) { if (isMagicSpaceSwapper(mMagicSpaceStrippers.codePointAt(i))) { throw new RuntimeException("Char code " + mMagicSpaceStrippers.codePointAt(i) + " is both a magic space swapper and stripper."); @@ -234,10 +235,12 @@ public class SettingsValues { } public boolean isMagicSpaceStripper(int code) { + // TODO: this does not work if the code does not fit in a char return mMagicSpaceStrippers.contains(String.valueOf((char)code)); } public boolean isMagicSpaceSwapper(int code) { + // TODO: this does not work if the code does not fit in a char return mMagicSpaceSwappers.contains(String.valueOf((char)code)); } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index bd244b913..fa1b5ef6c 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -221,7 +221,8 @@ public class WordComposer { if (mTrailingSingleQuotesCount > 0) { --mTrailingSingleQuotesCount; } else { - for (int i = mTypedWord.length() - 1; i >= 0; --i) { + for (int i = mTypedWord.offsetByCodePoints(mTypedWord.length(), -1); + i >= 0; i = mTypedWord.offsetByCodePoints(i, -1)) { if (Keyboard.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break; ++mTrailingSingleQuotesCount; } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 88ac043ed..8ac82ee5b 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -431,9 +431,9 @@ public class AndroidSpellCheckerService extends SpellCheckerService // If the first char is not uppercase, then the word is either all lower case, // and in either case we return CAPITALIZE_NONE. if (!Character.isUpperCase(text.codePointAt(0))) return CAPITALIZE_NONE; - final int len = text.codePointCount(0, text.length()); + final int len = text.length(); int capsCount = 1; - for (int i = 1; i < len; ++i) { + for (int i = 1; i < len; i = text.offsetByCodePoints(i, 1)) { if (1 != capsCount && i != capsCount) break; if (Character.isUpperCase(text.codePointAt(i))) ++capsCount; } @@ -522,13 +522,12 @@ public class AndroidSpellCheckerService extends SpellCheckerService // Filter contents final int length = text.length(); int letterCount = 0; - for (int i = 0; i < length; ++i) { + for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { final int codePoint = text.codePointAt(i); // Any word containing a '@' is probably an e-mail address // Any word containing a '/' is probably either an ad-hoc combination of two // words or a URI - in either case we don't want to spell check that - if ('@' == codePoint - || '/' == codePoint) return true; + if ('@' == codePoint || '/' == codePoint) return true; if (isLetterCheckableByLanguage(codePoint, script)) ++letterCount; } // Guestimate heuristic: perform spell checking if at least 3/4 of the characters @@ -570,7 +569,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService suggestionsLimit); final WordComposer composer = new WordComposer(); final int length = text.length(); - for (int i = 0; i < length; ++i) { + for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { final int character = text.codePointAt(i); final int proximityIndex = SpellCheckerProximityInfo.getIndexOfCodeForScript(character, mScript); diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java index 8c0ccd40b..af647b8ce 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java @@ -133,7 +133,7 @@ public class InputLogicTests extends ServiceTestCase { } private void type(final String stringToType) { - for (int i = 0; i < stringToType.length(); ++i) { + for (int i = 0; i < stringToType.length(); i = stringToType.offsetByCodePoints(i, 1)) { type(stringToType.codePointAt(i)); } } diff --git a/tools/makedict/src/com/android/inputmethod/latin/FusionDictionary.java b/tools/makedict/src/com/android/inputmethod/latin/FusionDictionary.java index 918b1ca4b..08143d3ea 100644 --- a/tools/makedict/src/com/android/inputmethod/latin/FusionDictionary.java +++ b/tools/makedict/src/com/android/inputmethod/latin/FusionDictionary.java @@ -164,7 +164,7 @@ public class FusionDictionary implements Iterable { static private int[] getCodePoints(String word) { final int wordLength = word.length(); int[] array = new int[word.codePointCount(0, wordLength)]; - for (int i = 0; i < wordLength; ++i) { + for (int i = 0; i < wordLength; i = word.offsetByCodePoints(i, 1)) { array[i] = word.codePointAt(i); } return array; -- cgit v1.2.3-83-g751a From 825e2bbd910cce3055a4ca808d3744bc0b2cedda Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 3 Feb 2012 12:22:02 +0900 Subject: Fix a bug when deleting the last char And unit test Change-Id: Ic4fc3626f8b86e10156d770d41cd6deab5d31f39 --- java/src/com/android/inputmethod/latin/WordComposer.java | 6 ++++-- tests/src/com/android/inputmethod/latin/InputLogicTests.java | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index fa1b5ef6c..dd24432f7 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -212,6 +212,7 @@ public class WordComposer { final int lastPos = size - 1; char lastChar = mTypedWord.charAt(lastPos); mCodes.remove(lastPos); + // TODO: This crashes and catches fire if the code point doesn't fit a char mTypedWord.deleteCharAt(lastPos); if (Character.isUpperCase(lastChar)) mCapsCount--; } @@ -221,8 +222,9 @@ public class WordComposer { if (mTrailingSingleQuotesCount > 0) { --mTrailingSingleQuotesCount; } else { - for (int i = mTypedWord.offsetByCodePoints(mTypedWord.length(), -1); - i >= 0; i = mTypedWord.offsetByCodePoints(i, -1)) { + int i = mTypedWord.length(); + while (i > 0) { + i = mTypedWord.offsetByCodePoints(i, -1); if (Keyboard.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break; ++mTrailingSingleQuotesCount; } diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java index af647b8ce..ee3a97fab 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java @@ -291,4 +291,13 @@ public class InputLogicTests extends ServiceTestCase { assertEquals("manual pick then space then type", WORD1_TO_TYPE + WORD2_TO_TYPE, mTextView.getText().toString()); } + + public void testDeleteWholeComposingWord() { + final String WORD_TO_TYPE = "this"; + type(WORD_TO_TYPE); + for (int i = 0; i < WORD_TO_TYPE.length(); ++i) { + type(Keyboard.CODE_DELETE); + } + assertEquals("delete whole composing word", "", mTextView.getText().toString()); + } } -- cgit v1.2.3-83-g751a From a7f2500001c53dc5a6de9c2525a75229cc7c6645 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Mon, 6 Feb 2012 18:06:20 +0900 Subject: Fix a bug with common objects. Bug: 5961179 Change-Id: I452efc552c6ab390931f25557d7aee5a64bf054e --- java/src/com/android/inputmethod/latin/LastComposedWord.java | 2 ++ java/src/com/android/inputmethod/latin/LatinIME.java | 7 ++----- java/src/com/android/inputmethod/latin/WordComposer.java | 11 ++++++++--- 3 files changed, 12 insertions(+), 8 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index 0c8c88f50..f34cb5ff9 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -51,6 +51,8 @@ public class LastComposedWord { public static final LastComposedWord NOT_A_COMPOSED_WORD = new LastComposedWord(null, null, null, "", ""); + // Warning: this is using the passed objects as is and fully expects them to be + // immutable. Do not fiddle with their contents after you passed them to this constructor. public LastComposedWord(final ArrayList codes, final int[] xCoordinates, final int[] yCoordinates, final String typedWord, final String autoCorrection) { mCodes = codes; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 24007f95a..e4339318b 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -2201,9 +2201,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // new composing text. final int restartLength = mWordComposer.size(); if (DEBUG) { - final String wordBeforeCursor = - ic.getTextBeforeCursor(restartLength + 1, 0).subSequence(0, restartLength) - .toString(); + final String wordBeforeCursor = ic.getTextBeforeCursor(restartLength, 0).toString(); if (!TextUtils.equals(mWordComposer.getTypedWord(), wordBeforeCursor)) { throw new RuntimeException("restartSuggestionsOnManuallyPickedTypedWord " + "check failed: we thought we were reverting \"" @@ -2212,8 +2210,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar + wordBeforeCursor + "\""); } } - // Warning: this +1 takes into account the extra space added by the manual pick process. - ic.deleteSurroundingText(restartLength + 1, 0); + ic.deleteSurroundingText(restartLength, 0); ic.setComposingText(mWordComposer.getTypedWord(), 1); mHandler.cancelUpdateBigramPredictions(); mHandler.postUpdateSuggestions(); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index dd24432f7..f418968b5 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -310,13 +310,18 @@ public class WordComposer { // LastComposedWord#didAutoCorrectToAnotherWord with #equals(). It would be marginally // cleaner to do it here, but it would be slower (since we would #equals() for each commit, // instead of only on cancel), and ultimately we want to figure it out even earlier anyway. - final LastComposedWord lastComposedWord = new LastComposedWord(mCodes, - mXCoordinates, mYCoordinates, mTypedWord.toString(), + final ArrayList codes = mCodes; + final int[] xCoordinates = mXCoordinates; + final int[] yCoordinates = mYCoordinates; + mCodes = new ArrayList(N); + mXCoordinates = new int[N]; + mYCoordinates = new int[N]; + final LastComposedWord lastComposedWord = new LastComposedWord(codes, + xCoordinates, yCoordinates, mTypedWord.toString(), null == mAutoCorrection ? null : mAutoCorrection.toString()); if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) { lastComposedWord.deactivate(); } - mCodes.clear(); mTypedWord.setLength(0); mAutoCorrection = null; return lastComposedWord; -- cgit v1.2.3-83-g751a From 9159b9953d857de83ae2f90a121fcd259f5ee01d Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 3 Feb 2012 16:05:48 +0900 Subject: Fix the auto-composer to support supplementary chars Change-Id: I61ff218ae2ca4eb443a370e581b677755258670a --- .../android/inputmethod/latin/WordComposer.java | 35 ++++++++++++++-------- .../android/inputmethod/latin/InputLogicTests.java | 21 +++++++++++-- 2 files changed, 41 insertions(+), 15 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index f418968b5..a1a329a8d 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -90,11 +90,11 @@ public class WordComposer { * @return the number of keystrokes */ public final int size() { - return mTypedWord.length(); + return mCodes.size(); } public final boolean isComposingWord() { - return size() > 0; + return mCodes.size() > 0; } /** @@ -125,8 +125,8 @@ public class WordComposer { * @param codes the array of unicode values */ public void add(int primaryCode, int[] codes, int x, int y) { - final int newIndex = size(); - mTypedWord.append((char) primaryCode); + final int newIndex = mCodes.size(); + mTypedWord.appendCodePoint(primaryCode); correctPrimaryJuxtapos(primaryCode, codes); mCodes.add(codes); if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { @@ -171,8 +171,8 @@ public class WordComposer { final KeyDetector keyDetector) { reset(); final int length = word.length(); - for (int i = 0; i < length; ++i) { - int codePoint = word.charAt(i); + for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) { + int codePoint = Character.codePointAt(word, i); addKeyInfo(codePoint, keyboard, keyDetector); } } @@ -207,16 +207,25 @@ public class WordComposer { * Delete the last keystroke as a result of hitting backspace. */ public void deleteLast() { - final int size = size(); + final int size = mCodes.size(); if (size > 0) { - final int lastPos = size - 1; - char lastChar = mTypedWord.charAt(lastPos); - mCodes.remove(lastPos); - // TODO: This crashes and catches fire if the code point doesn't fit a char - mTypedWord.deleteCharAt(lastPos); + mCodes.remove(size - 1); + // Note: mTypedWord.length() and mCodes.length differ when there are surrogate pairs + final int stringBuilderLength = mTypedWord.length(); + if (stringBuilderLength < size) { + throw new RuntimeException( + "In WordComposer: mCodes and mTypedWords have non-matching lengths"); + } + final int lastChar = mTypedWord.codePointBefore(stringBuilderLength); + if (Character.isSupplementaryCodePoint(lastChar)) { + mTypedWord.delete(stringBuilderLength - 2, stringBuilderLength); + } else { + mTypedWord.deleteCharAt(stringBuilderLength - 1); + } if (Character.isUpperCase(lastChar)) mCapsCount--; } - if (size() == 0) { + // We may have deleted the last one. + if (0 == mCodes.size()) { mIsFirstCharCapitalized = false; } if (mTrailingSingleQuotesCount > 0) { diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java index 2cecc9d8d..9d886da3b 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java @@ -159,11 +159,26 @@ public class InputLogicTests extends ServiceTestCase { } public void testPickSuggestionThenBackspace() { - final String WORD_TO_TYPE = "tgis"; + final String WORD_TO_TYPE = "this"; + final String EXPECTED_RESULT = "this"; type(WORD_TO_TYPE); mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); + mLatinIME.onUpdateSelection(0, 0, WORD_TO_TYPE.length(), WORD_TO_TYPE.length(), -1, -1); type(Keyboard.CODE_DELETE); - assertEquals("press suggestion then backspace", WORD_TO_TYPE, + assertEquals("press suggestion then backspace", EXPECTED_RESULT, + mTextView.getText().toString()); + } + + public void testPickTypedWordOverAutoCorrectionThenBackspace() { + final String WORD_TO_TYPE = "tgis"; + final String EXPECTED_RESULT = "tgis"; + type(WORD_TO_TYPE); + // Choose the typed word, which should be in position 1 (because position 0 should + // be occupied by the "this" auto-correction, as checked by testAutoCorrect()) + mLatinIME.pickSuggestionManually(1, WORD_TO_TYPE); + mLatinIME.onUpdateSelection(0, 0, WORD_TO_TYPE.length(), WORD_TO_TYPE.length(), -1, -1); + type(Keyboard.CODE_DELETE); + assertEquals("pick typed word over auto-correction then backspace", EXPECTED_RESULT, mTextView.getText().toString()); } @@ -379,4 +394,6 @@ public class InputLogicTests extends ServiceTestCase { assertEquals("type word type dot then press the .com key", EXPECTED_RESULT, mTextView.getText().toString()); } + + // TODO: Add some tests for non-BMP characters } -- cgit v1.2.3-83-g751a From cf9d92629cae88273805eaf7984fcfdd8afd11f5 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 21 Feb 2012 23:11:07 -0800 Subject: Give LastComposedWord knowledge of the committed word (A1) There is no point storing the prospective autocorrect - we are recomputing it anyway. The committed word however will be necessary to implement feature request #5968922. Change-Id: I588c18e1a5a1050a791d601de465f421ccbe36cd --- .../src/com/android/inputmethod/latin/LastComposedWord.java | 10 +++++----- java/src/com/android/inputmethod/latin/LatinIME.java | 13 +++++++------ java/src/com/android/inputmethod/latin/WordComposer.java | 10 +++++----- 3 files changed, 17 insertions(+), 16 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index f34cb5ff9..37be03c3e 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -44,7 +44,7 @@ public class LastComposedWord { public final int[] mXCoordinates; public final int[] mYCoordinates; public final String mTypedWord; - public final String mAutoCorrection; + public final String mCommittedWord; private boolean mActive; @@ -54,12 +54,12 @@ public class LastComposedWord { // Warning: this is using the passed objects as is and fully expects them to be // immutable. Do not fiddle with their contents after you passed them to this constructor. public LastComposedWord(final ArrayList codes, final int[] xCoordinates, - final int[] yCoordinates, final String typedWord, final String autoCorrection) { + final int[] yCoordinates, final String typedWord, final String committedWord) { mCodes = codes; mXCoordinates = xCoordinates; mYCoordinates = yCoordinates; mTypedWord = typedWord; - mAutoCorrection = autoCorrection; + mCommittedWord = committedWord; mActive = true; } @@ -68,7 +68,7 @@ public class LastComposedWord { } public boolean canCancelAutoCorrect() { - return mActive && !TextUtils.isEmpty(mAutoCorrection) - && !TextUtils.equals(mTypedWord, mAutoCorrection); + return mActive && !TextUtils.isEmpty(mCommittedWord) + && !TextUtils.equals(mTypedWord, mCommittedWord); } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index da268451b..a40bcdfe2 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1129,8 +1129,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public void commitTyped(final InputConnection ic) { if (!mWordComposer.isComposingWord()) return; final CharSequence typedWord = mWordComposer.getTypedWord(); - mLastComposedWord = mWordComposer.commitWord(LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD); if (typedWord.length() > 0) { + mLastComposedWord = mWordComposer.commitWord( + LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, typedWord.toString()); if (ic != null) { ic.commitText(typedWord, 1); } @@ -2034,7 +2035,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // what user typed. Note: currently this is done much later in // LastComposedWord#canCancelAutoCorrect by string equality of the remembered // strings. - mLastComposedWord = mWordComposer.commitWord(commitType); + mLastComposedWord = mWordComposer.commitWord(commitType, bestWord.toString()); } private static final WordComposer sEmptyWordComposer = new WordComposer(); @@ -2198,8 +2199,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // "ic" must not be null private void cancelAutoCorrect(final InputConnection ic) { final String originallyTypedWord = mLastComposedWord.mTypedWord; - final CharSequence autoCorrectedTo = mLastComposedWord.mAutoCorrection; - final int cancelLength = autoCorrectedTo.length(); + final CharSequence committedWord = mLastComposedWord.mCommittedWord; + final int cancelLength = committedWord.length(); final CharSequence separator = ic.getTextBeforeCursor(1, 0); if (DEBUG) { if (mWordComposer.isComposingWord()) { @@ -2208,9 +2209,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final String wordBeforeCursor = ic.getTextBeforeCursor(cancelLength + 1, 0).subSequence(0, cancelLength) .toString(); - if (!TextUtils.equals(autoCorrectedTo, wordBeforeCursor)) { + if (!TextUtils.equals(committedWord, wordBeforeCursor)) { throw new RuntimeException("cancelAutoCorrect check failed: we thought we were " - + "reverting \"" + autoCorrectedTo + + "reverting \"" + committedWord + "\", but before the cursor we found \"" + wordBeforeCursor + "\""); } if (TextUtils.equals(originallyTypedWord, wordBeforeCursor)) { diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index a1a329a8d..1f9371538 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -308,9 +308,10 @@ public class WordComposer { } // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. - public LastComposedWord commitWord(final int type) { + public LastComposedWord commitWord(final int type, final String committedWord) { // Note: currently, we come here whenever we commit a word. If it's any *other* kind than - // DECIDED_WORD, we should reset mAutoCorrection so that we don't attempt to cancel later. + // DECIDED_WORD, we should deactivate the last composed word so that we don't attempt to + // cancel later. // If it's a DECIDED_WORD, it may be an actual auto-correction by the IME, or what the user // typed because the IME decided *not* to auto-correct for whatever reason. // Ideally we would also null it when it was a DECIDED_WORD that was not an auto-correct. @@ -326,8 +327,7 @@ public class WordComposer { mXCoordinates = new int[N]; mYCoordinates = new int[N]; final LastComposedWord lastComposedWord = new LastComposedWord(codes, - xCoordinates, yCoordinates, mTypedWord.toString(), - null == mAutoCorrection ? null : mAutoCorrection.toString()); + xCoordinates, yCoordinates, mTypedWord.toString(), committedWord); if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) { lastComposedWord.deactivate(); } @@ -342,6 +342,6 @@ public class WordComposer { mYCoordinates = lastComposedWord.mYCoordinates; mTypedWord.setLength(0); mTypedWord.append(lastComposedWord.mTypedWord); - mAutoCorrection = lastComposedWord.mAutoCorrection; + mAutoCorrection = null; // This will be filled by the next call to updateSuggestion. } } -- cgit v1.2.3-83-g751a From 66bb563535dbe3672f99f75bd71763a551444867 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 21 Feb 2012 23:17:54 -0800 Subject: Give LastComposedWord knowledge of the separator (A2) This stores the separator that was used to commit the word in the LastComposedWord. It may be NOT_A_SEPARATOR if there was no separator (for example, the cursor moved causing a commit, or there was a manual pick). This is necessary to implement feature request #5968922. Change-Id: I5fcf19a78ec66d68d4df89418eaef13952588207 --- .../android/inputmethod/deprecated/VoiceProxy.java | 3 ++- .../inputmethod/latin/LastComposedWord.java | 9 ++++++-- .../com/android/inputmethod/latin/LatinIME.java | 25 +++++++++++++--------- java/src/com/android/inputmethod/latin/Utils.java | 6 ++++-- .../android/inputmethod/latin/WordComposer.java | 5 +++-- 5 files changed, 31 insertions(+), 17 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java index f632b0e02..5c4e9af68 100644 --- a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java +++ b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java @@ -56,6 +56,7 @@ import com.android.inputmethod.deprecated.voice.VoiceInput; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.LatinKeyboardView; import com.android.inputmethod.latin.EditingUtils; +import com.android.inputmethod.latin.LastComposedWord; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinIME.UIHandler; import com.android.inputmethod.latin.LatinImeLogger; @@ -553,7 +554,7 @@ public class VoiceProxy implements VoiceInput.UiListener { mHints.registerVoiceResult(bestResult); if (ic != null) ic.beginBatchEdit(); // To avoid extra updates on committing older text - mService.commitTyped(ic); + mService.commitTyped(ic, LastComposedWord.NOT_A_SEPARATOR); EditingUtils.appendText(ic, bestResult); if (ic != null) ic.endBatchEdit(); diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index 37be03c3e..f0b91b104 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -40,26 +40,31 @@ public class LastComposedWord { // an auto-correction. public static final int COMMIT_TYPE_CANCEL_AUTO_CORRECT = 3; + public static final int NOT_A_SEPARATOR = -1; + public final ArrayList mCodes; public final int[] mXCoordinates; public final int[] mYCoordinates; public final String mTypedWord; public final String mCommittedWord; + public final int mSeparatorCode; private boolean mActive; public static final LastComposedWord NOT_A_COMPOSED_WORD = - new LastComposedWord(null, null, null, "", ""); + new LastComposedWord(null, null, null, "", "", NOT_A_SEPARATOR); // Warning: this is using the passed objects as is and fully expects them to be // immutable. Do not fiddle with their contents after you passed them to this constructor. public LastComposedWord(final ArrayList codes, final int[] xCoordinates, - final int[] yCoordinates, final String typedWord, final String committedWord) { + final int[] yCoordinates, final String typedWord, final String committedWord, + final int separatorCode) { mCodes = codes; mXCoordinates = xCoordinates; mYCoordinates = yCoordinates; mTypedWord = typedWord; mCommittedWord = committedWord; + mSeparatorCode = separatorCode; mActive = true; } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index a40bcdfe2..b7c8b70e1 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -658,7 +658,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mDisplayOrientation = conf.orientation; mHandler.startOrientationChanging(); final InputConnection ic = getCurrentInputConnection(); - commitTyped(ic); + commitTyped(ic, LastComposedWord.NOT_A_SEPARATOR); if (ic != null) ic.finishComposingText(); // For voice input if (isShowingOptionDialog()) mOptionsDialog.dismiss(); @@ -1126,12 +1126,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; } - public void commitTyped(final InputConnection ic) { + public void commitTyped(final InputConnection ic, final int separatorCode) { if (!mWordComposer.isComposingWord()) return; final CharSequence typedWord = mWordComposer.getTypedWord(); if (typedWord.length() > 0) { mLastComposedWord = mWordComposer.commitWord( - LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, typedWord.toString()); + LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, typedWord.toString(), + separatorCode); if (ic != null) { ic.commitText(typedWord, 1); } @@ -1353,7 +1354,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final InputConnection ic = getCurrentInputConnection(); if (ic == null) return; ic.beginBatchEdit(); - commitTyped(ic); + commitTyped(ic, LastComposedWord.NOT_A_SEPARATOR); text = specificTldProcessingOnTextInput(ic, text); if (SPACE_STATE_PHANTOM == mSpaceState) { sendKeyCodePoint(Keyboard.CODE_SPACE); @@ -1646,7 +1647,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar commitCurrentAutoCorrection(primaryCode, ic); didAutoCorrect = true; } else { - commitTyped(ic); + commitTyped(ic, primaryCode); } } @@ -1703,7 +1704,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } private void handleClose() { - commitTyped(getCurrentInputConnection()); + commitTyped(getCurrentInputConnection(), LastComposedWord.NOT_A_SEPARATOR); mVoiceProxy.handleClose(); requestHideSelf(0); LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); @@ -1914,7 +1915,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint); mExpectingUpdateSelection = true; - commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD); + commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, + separatorCodePoint); // Add the word to the user unigram dictionary if it's not a known word addToUserUnigramAndBigramDictionaries(autoCorrection, UserUnigramDictionary.FREQUENCY_FOR_TYPED); @@ -1969,7 +1971,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(), suggestion.toString(), index, suggestions.mWords); mExpectingUpdateSelection = true; - commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK); + commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, + LastComposedWord.NOT_A_SEPARATOR); // Add the word to the auto dictionary if it's not a known word if (index == 0) { addToUserUnigramAndBigramDictionaries(suggestion, @@ -2019,7 +2022,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar /** * Commits the chosen word to the text field and saves it for later retrieval. */ - private void commitChosenWord(final CharSequence bestWord, final int commitType) { + private void commitChosenWord(final CharSequence bestWord, final int commitType, + final int separatorCode) { final InputConnection ic = getCurrentInputConnection(); if (ic != null) { mVoiceProxy.rememberReplacedWord(bestWord, mSettingsValues.mWordSeparators); @@ -2035,7 +2039,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // what user typed. Note: currently this is done much later in // LastComposedWord#canCancelAutoCorrect by string equality of the remembered // strings. - mLastComposedWord = mWordComposer.commitWord(commitType, bestWord.toString()); + mLastComposedWord = mWordComposer.commitWord(commitType, bestWord.toString(), + separatorCode); } private static final WordComposer sEmptyWordComposer = new WordComposer(); diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 3975dddeb..6d63e95f6 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -264,6 +264,7 @@ public class Utils { int ret = in % BUFSIZE; return ret < 0 ? ret + BUFSIZE : ret; } + // TODO: accept code points public void push(char c, int x, int y) { if (!mEnabled) return; if (mUsabilityStudy) { @@ -777,9 +778,10 @@ public class Utils { LatinImeLogger.logOnInputChar(); } - public static void onSeparator(final char code, final int x, + public static void onSeparator(final int code, final int x, final int y) { - RingCharBuffer.getInstance().push(code, x, y); + // TODO: accept code points + RingCharBuffer.getInstance().push((char)code, x, y); LatinImeLogger.logOnInputSeparator(); } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 1f9371538..0fa28e49e 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -308,7 +308,8 @@ public class WordComposer { } // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. - public LastComposedWord commitWord(final int type, final String committedWord) { + public LastComposedWord commitWord(final int type, final String committedWord, + final int separatorCode) { // Note: currently, we come here whenever we commit a word. If it's any *other* kind than // DECIDED_WORD, we should deactivate the last composed word so that we don't attempt to // cancel later. @@ -327,7 +328,7 @@ public class WordComposer { mXCoordinates = new int[N]; mYCoordinates = new int[N]; final LastComposedWord lastComposedWord = new LastComposedWord(codes, - xCoordinates, yCoordinates, mTypedWord.toString(), committedWord); + xCoordinates, yCoordinates, mTypedWord.toString(), committedWord, separatorCode); if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) { lastComposedWord.deactivate(); } -- cgit v1.2.3-83-g751a From 9271b770e81350e232c351f76f9f7a2ec23dff5f Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 22 Feb 2012 00:05:19 -0800 Subject: Activate the code to cancel a manual pick (A5) This finally makes active the behavior described in Bug: 5968922 Change-Id: I363ed23270c3dea75411ea806011225097b5d07c --- .../com/android/inputmethod/latin/LastComposedWord.java | 3 +-- java/src/com/android/inputmethod/latin/LatinIME.java | 7 ++----- .../src/com/android/inputmethod/latin/WordComposer.java | 17 +++++------------ 3 files changed, 8 insertions(+), 19 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index d32b22d4f..cc1221bcb 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -73,8 +73,7 @@ public class LastComposedWord { } public boolean canCancelAutoCorrect() { - return mActive && !TextUtils.isEmpty(mCommittedWord) - && !TextUtils.equals(mTypedWord, mCommittedWord); + return mActive && !TextUtils.isEmpty(mCommittedWord); } public boolean didCommitTypedWord() { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index ad85cc077..741f7f2a1 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1466,11 +1466,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) { // Go back to the suggestion mode if the user canceled the // "Touch again to save". - // NOTE: In general, we don't revert the word when backspacing - // from a manual suggestion pick. We deliberately chose a - // different behavior only in the case of picking the first - // suggestion (typed word). It's intentional to have made this - // inconsistent with backspacing after selecting other suggestions. + // TODO: this code path is not used any more. Verify & delete. restartSuggestionsOnManuallyPickedTypedWord(ic); } else { // Here we must check whether there is a selection. If so we should remove the @@ -2202,6 +2198,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } // "ic" must not be null + // TODO: rename this method to cancelCommit. private void cancelAutoCorrect(final InputConnection ic) { final String originallyTypedWord = mLastComposedWord.mTypedWord; final CharSequence committedWord = mLastComposedWord.mCommittedWord; diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 0fa28e49e..8121ada7f 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -310,17 +310,9 @@ public class WordComposer { // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. public LastComposedWord commitWord(final int type, final String committedWord, final int separatorCode) { - // Note: currently, we come here whenever we commit a word. If it's any *other* kind than - // DECIDED_WORD, we should deactivate the last composed word so that we don't attempt to - // cancel later. - // If it's a DECIDED_WORD, it may be an actual auto-correction by the IME, or what the user - // typed because the IME decided *not* to auto-correct for whatever reason. - // Ideally we would also null it when it was a DECIDED_WORD that was not an auto-correct. - // As it happens these two cases should behave differently, because the former can be - // canceled while the latter can't. Currently, we figure this out in - // LastComposedWord#didAutoCorrectToAnotherWord with #equals(). It would be marginally - // cleaner to do it here, but it would be slower (since we would #equals() for each commit, - // instead of only on cancel), and ultimately we want to figure it out even earlier anyway. + // Note: currently, we come here whenever we commit a word. If it's a MANUAL_PICK + // or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate + // the last composed word to ensure this does not happen. final ArrayList codes = mCodes; final int[] xCoordinates = mXCoordinates; final int[] yCoordinates = mYCoordinates; @@ -329,7 +321,8 @@ public class WordComposer { mYCoordinates = new int[N]; final LastComposedWord lastComposedWord = new LastComposedWord(codes, xCoordinates, yCoordinates, mTypedWord.toString(), committedWord, separatorCode); - if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) { + if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD + && type != LastComposedWord.COMMIT_TYPE_MANUAL_PICK) { lastComposedWord.deactivate(); } mTypedWord.setLength(0); -- cgit v1.2.3-83-g751a From ca7ec2097ca6af1505c1e6aa8b81b6068ba46dae Mon Sep 17 00:00:00 2001 From: satok Date: Tue, 6 Mar 2012 14:56:46 +0900 Subject: Integrate the logic to calculate the proximities Bug: 4343280 Change-Id: I0f6a7e6912ed4abea07c10d266da4c7ccb0dae76 --- .../keyboard/KeyboardActionListener.java | 10 ++--- .../inputmethod/keyboard/LatinKeyboardView.java | 3 +- .../inputmethod/keyboard/MoreKeysKeyboardView.java | 4 +- .../inputmethod/keyboard/PointerTracker.java | 13 ++---- .../com/android/inputmethod/latin/LatinIME.java | 38 ++++++++-------- .../src/com/android/inputmethod/latin/Suggest.java | 1 - .../android/inputmethod/latin/WordComposer.java | 50 ++++++++++++++++++++-- .../spellcheck/AndroidSpellCheckerService.java | 18 +------- .../latin/suggestions/MoreSuggestionsView.java | 2 +- .../android/inputmethod/latin/InputLogicTests.java | 30 ++----------- 10 files changed, 83 insertions(+), 86 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java index 6e13b95b5..16b4eafc9 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java @@ -41,11 +41,6 @@ public interface KeyboardActionListener { * Send a key code to the listener. * * @param primaryCode this is the code of the key that was pressed - * @param keyCodes the codes for all the possible alternative keys with the primary code being - * the first. If the primary key code is a single character such as an alphabet or - * number or symbol, the alternatives will include other characters that may be on - * the same key or adjacent keys. These codes are useful to correct for accidental - * presses of a key adjacent to the intended key. * @param x x-coordinate pixel of touched event. If {@link #onCodeInput} is not called by * {@link PointerTracker#onTouchEvent} or so, the value should be * {@link #NOT_A_TOUCH_COORDINATE}. If it's called on insertion from the suggestion @@ -55,10 +50,11 @@ public interface KeyboardActionListener { * {@link #NOT_A_TOUCH_COORDINATE}. If it's called on insertion from the suggestion * strip, it should be {@link #SUGGESTION_STRIP_COORDINATE}. */ - public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y); + public void onCodeInput(int primaryCode, int x, int y); public static final int NOT_A_TOUCH_COORDINATE = -1; public static final int SUGGESTION_STRIP_COORDINATE = -2; + public static final int SPELL_CHECKER_COORDINATE = -3; /** * Sends a sequence of characters to the listener. @@ -84,7 +80,7 @@ public interface KeyboardActionListener { @Override public void onReleaseKey(int primaryCode, boolean withSliding) {} @Override - public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {} + public void onCodeInput(int primaryCode, int x, int y) {} @Override public void onTextInput(CharSequence text) {} @Override diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 8a2f89257..78c371ff0 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -505,7 +505,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } private void invokeCodeInput(int primaryCode) { - mKeyboardActionListener.onCodeInput(primaryCode, null, + mKeyboardActionListener.onCodeInput(primaryCode, KeyboardActionListener.NOT_A_TOUCH_COORDINATE, KeyboardActionListener.NOT_A_TOUCH_COORDINATE); } @@ -740,6 +740,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke * @return {@code true} if the event was handled by the view, {@code false} * otherwise */ + //Should not annotate @override public boolean dispatchHoverEvent(MotionEvent event) { if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java index b030dd95a..9970d1d0b 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java @@ -46,8 +46,8 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel private final KeyboardActionListener mMoreKeysKeyboardListener = new KeyboardActionListener.Adapter() { @Override - public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { - mListener.onCodeInput(primaryCode, keyCodes, x, y); + public void onCodeInput(int primaryCode, int x, int y) { + mListener.onCodeInput(primaryCode, x, y); } @Override diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index f8f17bdd9..7a9915be0 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -105,7 +105,6 @@ public class PointerTracker { } } - private static KeyboardSwitcher sKeyboardSwitcher; // Parameters for pointer handling. private static LatinKeyboardView.PointerTrackerParams sParams; private static int sTouchNoiseThresholdDistanceSquared; @@ -172,7 +171,6 @@ public class PointerTracker { } setParameters(LatinKeyboardView.PointerTrackerParams.DEFAULT); - sKeyboardSwitcher = KeyboardSwitcher.getInstance(); } public static void setParameters(LatinKeyboardView.PointerTrackerParams params) { @@ -254,13 +252,13 @@ public class PointerTracker { // Note that we need primaryCode argument because the keyboard may in shifted state and the // primaryCode is different from {@link Key#mCode}. - private void callListenerOnCodeInput(Key key, int primaryCode, int[] keyCodes, int x, int y) { + private void callListenerOnCodeInput(Key key, int primaryCode, int x, int y) { final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); final boolean alterCode = key.altCodeWhileTyping() && mTimerProxy.isTyping(); final int code = alterCode ? key.mAltCode : primaryCode; if (DEBUG_LISTENER) { Log.d(TAG, "onCodeInput: " + Keyboard.printableCode(code) + " text=" + key.mOutputText - + " codes="+ KeyDetector.printableCodes(keyCodes) + " x=" + x + " y=" + y + + " x=" + x + " y=" + y + " ignoreModifier=" + ignoreModifierKey + " alterCode=" + alterCode + " enabled=" + key.isEnabled()); } @@ -271,7 +269,7 @@ public class PointerTracker { if (code == Keyboard.CODE_OUTPUT_TEXT) { mListener.onTextInput(key.mOutputText); } else if (code != Keyboard.CODE_UNSPECIFIED) { - mListener.onCodeInput(code, keyCodes, x, y); + mListener.onCodeInput(code, x, y); } if (!key.altCodeWhileTyping() && !key.isModifier()) { mTimerProxy.startKeyTypedTimer(); @@ -719,10 +717,7 @@ public class PointerTracker { } int code = key.mCode; - final int[] codes = mKeyDetector.newCodeArray(); - mKeyDetector.getKeyAndNearbyCodes(x, y, codes); - - callListenerOnCodeInput(key, code, codes, x, y); + callListenerOnCodeInput(key, code, x, y); callListenerOnRelease(key, code, false); } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 64b9f3364..044f05014 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -728,10 +728,17 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final KeyboardSwitcher switcher = mKeyboardSwitcher; LatinKeyboardView inputView = switcher.getKeyboardView(); + if (editorInfo == null) { + Log.e(TAG, "Null EditorInfo in onStartInputView()"); + if (LatinImeLogger.sDBG) { + throw new NullPointerException("Null EditorInfo in onStartInputView()"); + } + return; + } if (DEBUG) { - Log.d(TAG, "onStartInputView: editorInfo:" + ((editorInfo == null) ? "none" - : String.format("inputType=0x%08x imeOptions=0x%08x", - editorInfo.inputType, editorInfo.imeOptions))); + Log.d(TAG, "onStartInputView: editorInfo:" + + String.format("inputType=0x%08x imeOptions=0x%08x", + editorInfo.inputType, editorInfo.imeOptions)); } if (Utils.inPrivateImeOptions(null, IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)) { Log.w(TAG, "Deprecated private IME option specified: " @@ -761,7 +768,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to // know now whether this is a password text field, because we need to know now whether we // want to enable the voice button. - final int inputType = (editorInfo != null) ? editorInfo.inputType : 0; + final int inputType = editorInfo.inputType; mVoiceProxy.resetVoiceStates(InputTypeCompatUtils.isPasswordInputType(inputType) || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)); @@ -1245,12 +1252,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return mOptionsDialog != null && mOptionsDialog.isShowing(); } - private void insertPunctuationFromSuggestionStrip(final int code) { - onCodeInput(code, new int[] { code }, - KeyboardActionListener.SUGGESTION_STRIP_COORDINATE, - KeyboardActionListener.SUGGESTION_STRIP_COORDINATE); - } - private static int getActionId(Keyboard keyboard) { return keyboard != null ? keyboard.mId.imeActionId() : EditorInfo.IME_ACTION_NONE; } @@ -1279,7 +1280,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Implementation of {@link KeyboardActionListener}. @Override - public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { + public void onCodeInput(int primaryCode, int x, int y) { final long when = SystemClock.uptimeMillis(); if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) { mDeleteCount = 0; @@ -1331,7 +1332,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (mSettingsValues.isWordSeparator(primaryCode)) { didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState); } else { - handleCharacter(primaryCode, keyCodes, x, y, spaceState); + handleCharacter(primaryCode, x, y, spaceState); } mExpectingUpdateSelection = true; break; @@ -1498,18 +1499,18 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } - private void handleCharacter(final int primaryCode, final int[] keyCodes, final int x, + private void handleCharacter(final int primaryCode, final int x, final int y, final int spaceState) { mVoiceProxy.handleCharacter(); final InputConnection ic = getCurrentInputConnection(); if (null != ic) ic.beginBatchEdit(); // TODO: if ic is null, does it make any sense to call this? - handleCharacterWhileInBatchEdit(primaryCode, keyCodes, x, y, spaceState, ic); + handleCharacterWhileInBatchEdit(primaryCode, x, y, spaceState, ic); if (null != ic) ic.endBatchEdit(); } // "ic" may be null without this crashing, but the behavior will be really strange - private void handleCharacterWhileInBatchEdit(final int primaryCode, final int[] keyCodes, + private void handleCharacterWhileInBatchEdit(final int primaryCode, final int x, final int y, final int spaceState, final InputConnection ic) { boolean isComposingWord = mWordComposer.isComposingWord(); @@ -1541,7 +1542,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } if (isComposingWord) { - mWordComposer.add(primaryCode, keyCodes, x, y); + mWordComposer.add( + primaryCode, x, y, mKeyboardSwitcher.getKeyboardView().getKeyDetector()); if (ic != null) { // If it's the first letter, make note of auto-caps state if (mWordComposer.size() == 1) { @@ -1912,7 +1914,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar LatinImeLogger.logOnManualSuggestion("", suggestion.toString(), index, suggestedWords); // Rely on onCodeInput to do the complicated swapping/stripping logic consistently. final int primaryCode = suggestion.charAt(0); - onCodeInput(primaryCode, new int[] { primaryCode }, + onCodeInput(primaryCode, KeyboardActionListener.SUGGESTION_STRIP_COORDINATE, KeyboardActionListener.SUGGESTION_STRIP_COORDINATE); return; @@ -2158,7 +2160,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final String originallyTypedWord = mLastComposedWord.mTypedWord; final CharSequence committedWord = mLastComposedWord.mCommittedWord; final int cancelLength = committedWord.length(); - final int separatorLength = mLastComposedWord.getSeparatorLength( + final int separatorLength = LastComposedWord.getSeparatorLength( mLastComposedWord.mSeparatorCode); // TODO: should we check our saved separator against the actual contents of the text view? if (DEBUG) { diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index f6e177aaf..298ead665 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -323,7 +323,6 @@ public class Suggest implements Dictionary.WordCallback { } } else { // Word entered: return only bigrams that match the first char of the typed word - @SuppressWarnings("null") final char currentChar = consideredWord.charAt(0); // TODO: Must pay attention to locale when changing case. final char currentCharUpper = Character.toUpperCase(currentChar); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 8121ada7f..2a597b86d 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -19,6 +19,9 @@ package com.android.inputmethod.latin; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardActionListener; +import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService; +import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo; import java.util.ArrayList; import java.util.Arrays; @@ -119,19 +122,60 @@ public class WordComposer { return previous && !Character.isUpperCase(codePoint); } + // TODO: remove input keyDetector + public void add(int primaryCode, int keyX, int keyY, KeyDetector keyDetector) { + final int[] codes; + if (keyX == KeyboardActionListener.SPELL_CHECKER_COORDINATE + || keyY == KeyboardActionListener.SPELL_CHECKER_COORDINATE) { + // only used for tests in InputLogicTests + addKeyForSpellChecker(primaryCode, AndroidSpellCheckerService.SCRIPT_LATIN); + return; + } else if (keyX == KeyboardActionListener.SUGGESTION_STRIP_COORDINATE + || keyY == KeyboardActionListener.SUGGESTION_STRIP_COORDINATE + || keyX == KeyboardActionListener.NOT_A_TOUCH_COORDINATE + || keyY == KeyboardActionListener.NOT_A_TOUCH_COORDINATE) { + codes = new int[] { primaryCode }; + } else { + codes = keyDetector.newCodeArray(); + keyDetector.getKeyAndNearbyCodes(keyX, keyY, codes); + } + add(primaryCode, codes, keyX, keyY); + } + + // TODO: remove this function + public void addKeyForSpellChecker(int primaryCode, int script) { + final int[] proximities; + final int proximityIndex = + SpellCheckerProximityInfo.getIndexOfCodeForScript(primaryCode, script); + if (-1 == proximityIndex) { + proximities = new int[] { primaryCode }; + } else { + // TODO: an initial examination seems to reveal this is actually used + // read-only. It should be possible to compute the arrays statically once + // and skip doing a copy each time here. + proximities = Arrays.copyOfRange( + SpellCheckerProximityInfo.getProximityForScript(script), + proximityIndex, + proximityIndex + SpellCheckerProximityInfo.ROW_SIZE); + } + add(primaryCode, proximities, + KeyboardActionListener.NOT_A_TOUCH_COORDINATE, + KeyboardActionListener.NOT_A_TOUCH_COORDINATE); + } + /** * Add a new keystroke, with codes[0] containing the pressed key's unicode and the rest of * the array containing unicode for adjacent keys, sorted by reducing probability/proximity. * @param codes the array of unicode values */ - public void add(int primaryCode, int[] codes, int x, int y) { + private void add(int primaryCode, int[] codes, int keyX, int keyY) { final int newIndex = mCodes.size(); mTypedWord.appendCodePoint(primaryCode); correctPrimaryJuxtapos(primaryCode, codes); mCodes.add(codes); if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { - mXCoordinates[newIndex] = x; - mYCoordinates[newIndex] = y; + mXCoordinates[newIndex] = keyX; + mYCoordinates[newIndex] = keyY; } mIsFirstCharCapitalized = isFirstCharCapitalized( newIndex, primaryCode, mIsFirstCharCapitalized); diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 8ac82ee5b..755c75b2e 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -570,23 +570,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService final WordComposer composer = new WordComposer(); final int length = text.length(); for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { - final int character = text.codePointAt(i); - final int proximityIndex = - SpellCheckerProximityInfo.getIndexOfCodeForScript(character, mScript); - final int[] proximities; - if (-1 == proximityIndex) { - proximities = new int[] { character }; - } else { - // TODO: an initial examination seems to reveal this is actually used - // read-only. It should be possible to compute the arrays statically once - // and skip doing a copy each time here. - proximities = Arrays.copyOfRange( - SpellCheckerProximityInfo.getProximityForScript(mScript), - proximityIndex, - proximityIndex + SpellCheckerProximityInfo.ROW_SIZE); - } - composer.add(character, proximities, - WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); + composer.addKeyForSpellChecker(text.codePointAt(i), mScript); } final int capitalizeType = getCapitalizationType(text); diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java index cd83c3e21..1f7214777 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java @@ -66,7 +66,7 @@ public class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel { } @Override - public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { + public void onCodeInput(int primaryCode, int x, int y) { final int index = primaryCode - MoreSuggestions.SUGGESTION_CODE_BASE; if (index >= 0 && index < SuggestionsView.MAX_SUGGESTIONS) { mListener.onCustomRequest(index); diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java index 9d53b63f1..1ea70a98f 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java @@ -51,29 +51,9 @@ public class InputLogicTests extends ServiceTestCase { private LatinIME mLatinIME; private TextView mTextView; private InputConnection mInputConnection; - private HashMap mProximity; public InputLogicTests() { super(LatinIME.class); - mProximity = createProximity(); - } - - private static HashMap createProximity() { - final HashMap proximity = new HashMap(); - final int[] testProximity = SpellCheckerProximityInfo.getProximityForScript( - AndroidSpellCheckerService.SCRIPT_LATIN); - final int ROW_SIZE = SpellCheckerProximityInfo.ROW_SIZE; - final int NUL = SpellCheckerProximityInfo.NUL; - for (int row = 0; row * ROW_SIZE < testProximity.length; ++row) { - final int rowBase = row * ROW_SIZE; - int column; - for (column = 1; NUL != testProximity[rowBase + column]; ++column) { - // Do nothing, just search for a NUL element - } - proximity.put(testProximity[row * ROW_SIZE], - Arrays.copyOfRange(testProximity, rowBase, rowBase + column)); - } - return proximity; } // returns the previous setting value @@ -185,13 +165,9 @@ public class InputLogicTests extends ServiceTestCase { // to keep these tests as pinpoint as possible and avoid bringing it too many dependencies, // but keep them in mind if something breaks. Commenting them out as is should work. //mLatinIME.onPressKey(codePoint); - int[] proximityKeys = mProximity.get(codePoint); - if (null == proximityKeys) { - proximityKeys = new int[] { codePoint }; - } - mLatinIME.onCodeInput(codePoint, proximityKeys, - KeyboardActionListener.NOT_A_TOUCH_COORDINATE, - KeyboardActionListener.NOT_A_TOUCH_COORDINATE); + mLatinIME.onCodeInput(codePoint, + KeyboardActionListener.SPELL_CHECKER_COORDINATE, + KeyboardActionListener.SPELL_CHECKER_COORDINATE); //mLatinIME.onReleaseKey(codePoint, false); } -- cgit v1.2.3-83-g751a From 691f1c174b660f3bcfe1823d16e55990b4c829da Mon Sep 17 00:00:00 2001 From: satok Date: Tue, 6 Mar 2012 16:38:00 +0900 Subject: Fix coordinates sent to native code Change-Id: I2c8b093b59ad36ffe860c3c4d360d87251d101c4 --- .../android/inputmethod/keyboard/KeyDetector.java | 4 ++-- .../android/inputmethod/latin/WordComposer.java | 22 ++++++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index 10cf1d1f4..3638eae8d 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -65,11 +65,11 @@ public class KeyDetector { return mKeyHysteresisDistanceSquared; } - protected int getTouchX(int x) { + public int getTouchX(int x) { return x + mCorrectionX; } - protected int getTouchY(int y) { + public int getTouchY(int y) { return y + mCorrectionY; } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 2a597b86d..3324a3793 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -123,21 +123,27 @@ public class WordComposer { } // TODO: remove input keyDetector - public void add(int primaryCode, int keyX, int keyY, KeyDetector keyDetector) { + public void add(int primaryCode, int x, int y, KeyDetector keyDetector) { final int[] codes; - if (keyX == KeyboardActionListener.SPELL_CHECKER_COORDINATE - || keyY == KeyboardActionListener.SPELL_CHECKER_COORDINATE) { + final int keyX; + final int keyY; + if (x == KeyboardActionListener.SPELL_CHECKER_COORDINATE + || y == KeyboardActionListener.SPELL_CHECKER_COORDINATE) { // only used for tests in InputLogicTests addKeyForSpellChecker(primaryCode, AndroidSpellCheckerService.SCRIPT_LATIN); return; - } else if (keyX == KeyboardActionListener.SUGGESTION_STRIP_COORDINATE - || keyY == KeyboardActionListener.SUGGESTION_STRIP_COORDINATE - || keyX == KeyboardActionListener.NOT_A_TOUCH_COORDINATE - || keyY == KeyboardActionListener.NOT_A_TOUCH_COORDINATE) { + } else if (x == KeyboardActionListener.SUGGESTION_STRIP_COORDINATE + || y == KeyboardActionListener.SUGGESTION_STRIP_COORDINATE + || x == KeyboardActionListener.NOT_A_TOUCH_COORDINATE + || y == KeyboardActionListener.NOT_A_TOUCH_COORDINATE) { codes = new int[] { primaryCode }; + keyX = x; + keyY = y; } else { codes = keyDetector.newCodeArray(); - keyDetector.getKeyAndNearbyCodes(keyX, keyY, codes); + keyDetector.getKeyAndNearbyCodes(x, y, codes); + keyX = keyDetector.getTouchX(x); + keyY = keyDetector.getTouchX(y); } add(primaryCode, codes, keyX, keyY); } -- cgit v1.2.3-83-g751a From 853d9020edb058e39c46a6af1215dfcfeb865ad8 Mon Sep 17 00:00:00 2001 From: satok Date: Wed, 14 Mar 2012 21:39:31 +0900 Subject: Really pass the y - touch correction to the native code Bug: 4343280 Test: I11f8518d9ee Change-Id: I4b90bdffffed9736af223ac83c1a54019add70bb --- java/src/com/android/inputmethod/latin/WordComposer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 3324a3793..5f6be6867 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -143,7 +143,7 @@ public class WordComposer { codes = keyDetector.newCodeArray(); keyDetector.getKeyAndNearbyCodes(x, y, codes); keyX = keyDetector.getTouchX(x); - keyY = keyDetector.getTouchX(y); + keyY = keyDetector.getTouchY(y); } add(primaryCode, codes, keyX, keyY); } -- cgit v1.2.3-83-g751a From 723aaa2eebcfea0d285f11fc265941057332664d Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Thu, 15 Mar 2012 19:44:43 +0900 Subject: Remove touch dead zone KeyDetector should use the distance from the hit box to detect the key. Bug: 6174250 Change-Id: Id1745d90222d1d1a10467f194b45307c12449944 --- .../android/inputmethod/keyboard/KeyDetector.java | 45 ++++++++++++++-------- .../inputmethod/keyboard/MoreKeysDetector.java | 22 ++++++++++- .../inputmethod/keyboard/PointerTracker.java | 6 +-- .../android/inputmethod/latin/WordComposer.java | 4 +- 4 files changed, 55 insertions(+), 22 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index 3638eae8d..ea3f6236a 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -97,21 +97,21 @@ public class KeyDetector { /** * Computes maximum size of the array that can contain all nearby key codes returned by - * {@link #getKeyAndNearbyCodes}. + * {@link #getNearbyCodes}. * * @return Returns maximum size of the array that can contain all nearby key codes returned - * by {@link #getKeyAndNearbyCodes}. + * by {@link #getNearbyCodes}. */ protected int getMaxNearbyKeys() { return MAX_NEARBY_KEYS; } /** - * Allocates array that can hold all key codes returned by {@link #getKeyAndNearbyCodes} + * Allocates array that can hold all key codes returned by {@link #getNearbyCodes} * method. The maximum size of the array should be computed by {@link #getMaxNearbyKeys}. * * @return Allocates and returns an array that can hold all key codes returned by - * {@link #getKeyAndNearbyCodes} method. All elements in the returned array are + * {@link #getNearbyCodes} method. All elements in the returned array are * initialized by {@link #NOT_A_CODE} value. */ public int[] newCodeArray() { @@ -222,15 +222,15 @@ public class KeyDetector { * @param x The x-coordinate of a touch point * @param y The y-coordinate of a touch point * @param allCodes All nearby key codes except functional key are returned in this array - * @return The nearest key */ - public Key getKeyAndNearbyCodes(int x, int y, final int[] allCodes) { + // TODO: Move this method to native code. + public void getNearbyCodes(int x, int y, final int[] allCodes) { final int touchX = getTouchX(x); final int touchY = getTouchY(y); initializeNearbyKeys(); Key primaryKey = null; - for (final Key key: mKeyboard.getNearestKeys(touchX, touchY)) { + for (final Key key : mKeyboard.getNearestKeys(touchX, touchY)) { final boolean isOnKey = key.isOnKey(touchX, touchY); final int distance = key.squaredDistanceToEdge(touchX, touchY); if (isOnKey || (mProximityCorrectOn && distance < mProximityThresholdSquare)) { @@ -241,16 +241,31 @@ public class KeyDetector { } } - if (allCodes != null && allCodes.length > 0) { - getNearbyKeyCodes(primaryKey != null ? primaryKey.mCode : NOT_A_CODE, allCodes); - if (DEBUG) { - Log.d(TAG, "x=" + x + " y=" + y - + " primary=" + printableCode(primaryKey) - + " codes=" + printableCodes(allCodes)); - } + getNearbyKeyCodes(primaryKey != null ? primaryKey.mCode : NOT_A_CODE, allCodes); + if (DEBUG) { + Log.d(TAG, "x=" + x + " y=" + y + + " primary=" + printableCode(primaryKey) + + " codes=" + printableCodes(allCodes)); } + } + + /** + * Detect the key whose hitbox the touch point is in. + * + * @param x The x-coordinate of a touch point + * @param y The y-coordinate of a touch point + * @return the key that the touch point hits. + */ + public Key detectHitKey(int x, int y) { + final int touchX = getTouchX(x); + final int touchY = getTouchY(y); - return primaryKey; + for (final Key key : mKeyboard.getNearestKeys(touchX, touchY)) { + if (key.isOnKey(touchX, touchY)) { + return key; + } + } + return null; } public static String printableCode(Key key) { diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java index 742ee98d7..6c8d02016 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java @@ -39,7 +39,7 @@ public class MoreKeysDetector extends KeyDetector { } @Override - public Key getKeyAndNearbyCodes(int x, int y, final int[] allCodes) { + public void getNearbyCodes(int x, int y, final int[] allCodes) { final int touchX = getTouchX(x); final int touchY = getTouchY(y); @@ -53,8 +53,26 @@ public class MoreKeysDetector extends KeyDetector { } } - if (allCodes != null && nearestKey != null) { + if (nearestKey != null) { allCodes[0] = nearestKey.mCode; + } else { + allCodes[0] = NOT_A_CODE; + } + } + + @Override + public Key detectHitKey(int x, int y) { + final int touchX = getTouchX(x); + final int touchY = getTouchY(y); + + Key nearestKey = null; + int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare; + for (final Key key : getKeyboard().mKeys) { + final int dist = key.squaredDistanceToEdge(touchX, touchY); + if (dist < nearestDist) { + nearestKey = key; + nearestDist = dist; + } } return nearestKey; } diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index ed889712a..ec9081681 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -318,7 +318,7 @@ public class PointerTracker { } public Key getKeyOn(int x, int y) { - return mKeyDetector.getKeyAndNearbyCodes(x, y, null); + return mKeyDetector.detectHitKey(x, y); } private void setReleasedKeyGraphics(Key key) { @@ -421,7 +421,7 @@ public class PointerTracker { private Key onMoveKeyInternal(int x, int y) { mLastX = x; mLastY = y; - return mKeyDetector.getKeyAndNearbyCodes(x, y, null); + return mKeyDetector.detectHitKey(x, y); } private Key onMoveKey(int x, int y) { @@ -748,7 +748,7 @@ public class PointerTracker { private long mPreviousEventTime; private void printTouchEvent(String title, int x, int y, long eventTime) { - final Key key = mKeyDetector.getKeyAndNearbyCodes(x, y, null); + final Key key = mKeyDetector.detectHitKey(x, y); final String code = KeyDetector.printableCode(key); final long delta = eventTime - mPreviousEventTime; Log.d(TAG, String.format("%s%s[%d] %4d %4d %5d %s", title, diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 5f6be6867..126ac47e7 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -141,7 +141,7 @@ public class WordComposer { keyY = y; } else { codes = keyDetector.newCodeArray(); - keyDetector.getKeyAndNearbyCodes(x, y, codes); + keyDetector.getNearbyCodes(x, y, codes); keyX = keyDetector.getTouchX(x); keyY = keyDetector.getTouchY(y); } @@ -204,7 +204,7 @@ public class WordComposer { final int x = key.mX + key.mWidth / 2; final int y = key.mY + key.mHeight / 2; final int[] codes = keyDetector.newCodeArray(); - keyDetector.getKeyAndNearbyCodes(x, y, codes); + keyDetector.getNearbyCodes(x, y, codes); add(codePoint, codes, x, y); return; } -- cgit v1.2.3-83-g751a From ef08daddead8f189a4c38abdb1930f9c39c473ae Mon Sep 17 00:00:00 2001 From: satok Date: Fri, 16 Mar 2012 12:54:17 +0900 Subject: Do not change the proximity orders Bug: 4343280 Change-Id: I4e2dfb00d9c843a8a285d409ac5ab8fca5fb1694 --- java/src/com/android/inputmethod/latin/WordComposer.java | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 126ac47e7..a9609310c 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -177,7 +177,6 @@ public class WordComposer { private void add(int primaryCode, int[] codes, int keyX, int keyY) { final int newIndex = mCodes.size(); mTypedWord.appendCodePoint(primaryCode); - correctPrimaryJuxtapos(primaryCode, codes); mCodes.add(codes); if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { mXCoordinates[newIndex] = keyX; @@ -238,21 +237,6 @@ public class WordComposer { setComposingWord(word, keyboard, keyDetector); } - /** - * Swaps the first and second values in the codes array if the primary code is not the first - * value in the array but the second. This happens when the preferred key is not the key that - * the user released the finger on. - * @param primaryCode the preferred character - * @param codes array of codes based on distance from touch point - */ - private static void correctPrimaryJuxtapos(int primaryCode, int[] codes) { - if (codes.length < 2) return; - if (codes[0] > 0 && codes[1] > 0 && codes[0] != primaryCode && codes[1] == primaryCode) { - codes[1] = codes[0]; - codes[0] = primaryCode; - } - } - /** * Delete the last keystroke as a result of hitting backspace. */ -- cgit v1.2.3-83-g751a From 1caff47ecdfcf413df709371a919cf9377e26bf7 Mon Sep 17 00:00:00 2001 From: satok Date: Wed, 14 Mar 2012 23:17:12 +0900 Subject: Calculate proximity characters in the native code Bug: 4343280 Change-Id: I6adaf560f7a4f1f96dcb6ec2f61f20ee3001167e --- .../android/inputmethod/keyboard/KeyDetector.java | 15 +++-- .../android/inputmethod/latin/WordComposer.java | 4 +- native/src/proximity_info.cpp | 75 ++++++++++++++++------ native/src/proximity_info.h | 9 ++- 4 files changed, 77 insertions(+), 26 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index ea3f6236a..d342c6df0 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -260,12 +260,19 @@ public class KeyDetector { final int touchX = getTouchX(x); final int touchY = getTouchY(y); - for (final Key key : mKeyboard.getNearestKeys(touchX, touchY)) { - if (key.isOnKey(touchX, touchY)) { - return key; + int minDistance = Integer.MAX_VALUE; + Key primaryKey = null; + for (final Key key: mKeyboard.getNearestKeys(touchX, touchY)) { + final boolean isOnKey = key.isOnKey(touchX, touchY); + final int distance = key.squaredDistanceToEdge(touchX, touchY); + // TODO: need to take care of hitbox overlaps + if (primaryKey == null || distance < minDistance + || (distance == minDistance && isOnKey)) { + minDistance = distance; + primaryKey = key; } } - return null; + return primaryKey; } public static String printableCode(Key key) { diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index a9609310c..251063ec4 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -140,8 +140,8 @@ public class WordComposer { keyX = x; keyY = y; } else { - codes = keyDetector.newCodeArray(); - keyDetector.getNearbyCodes(x, y, codes); + final Key key = keyDetector.detectHitKey(x, y); + codes = new int[] { key != null ? key.mCode : NOT_A_CODE }; keyX = keyDetector.getTouchX(x); keyY = keyDetector.getTouchY(y); } diff --git a/native/src/proximity_info.cpp b/native/src/proximity_info.cpp index dd60ed62c..4d03f3274 100644 --- a/native/src/proximity_info.cpp +++ b/native/src/proximity_info.cpp @@ -55,6 +55,7 @@ ProximityInfo::ProximityInfo(const std::string localeStr, const int maxProximity mTouchPositionCorrectionEnabled(false) { const int proximityGridLength = GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE; mProximityCharsArray = new int32_t[proximityGridLength]; + mInputCodes = new int32_t[MAX_PROXIMITY_CHARS_SIZE * MAX_WORD_LENGTH_INTERNAL]; if (DEBUG_PROXIMITY_INFO) { AKLOGI("Create proximity info array %d", proximityGridLength); } @@ -96,6 +97,7 @@ void ProximityInfo::initializeCodeToKeyIndex() { ProximityInfo::~ProximityInfo() { delete[] mNormalizedSquaredDistances; delete[] mProximityCharsArray; + delete[] mInputCodes; } inline int ProximityInfo::getStartIndexFromCoordinates(const int x, const int y) const { @@ -138,7 +140,7 @@ bool ProximityInfo::isOnKey(const int keyId, const int x, const int y) { int ProximityInfo::squaredDistanceToEdge(const int keyId, const int x, const int y) { const int left = mKeyXCoordinates[keyId]; const int top = mKeyYCoordinates[keyId]; - const int right = left + mKeyWidths[keyId] + 1; + const int right = left + mKeyWidths[keyId]; const int bottom = top + mKeyHeights[keyId]; const int edgeX = x < left ? left : (x > right ? right : x); const int edgeY = y < top ? top : (y > bottom ? bottom : y); @@ -157,10 +159,10 @@ void ProximityInfo::calculateNearbyKeyCodes( if (c < KEYCODE_SPACE || c == primaryKey) { continue; } - int keyIndex = getKeyIndex(c); + const int keyIndex = getKeyIndex(c); const bool onKey = isOnKey(keyIndex, x, y); const int distance = squaredDistanceToEdge(keyIndex, x, y); - if (onKey || distance < MOST_COMMON_KEY_WIDTH_SQUARE) { + if (c >= KEYCODE_SPACE && (onKey || distance < MOST_COMMON_KEY_WIDTH_SQUARE)) { inputCodes[insertPos++] = c; if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) { if (DEBUG_DICT) { @@ -170,17 +172,17 @@ void ProximityInfo::calculateNearbyKeyCodes( } } } - inputCodes[insertPos++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE; - if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) { - if (DEBUG_DICT) { - assert(false); - } - return; - } - const int additionalProximitySize = AdditionalProximityChars::getAdditionalCharsSize(&mLocaleStr, primaryKey); if (additionalProximitySize > 0) { + inputCodes[insertPos++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE; + if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) { + if (DEBUG_DICT) { + assert(false); + } + return; + } + const int32_t* additionalProximityChars = AdditionalProximityChars::getAdditionalChars(&mLocaleStr, primaryKey); for (int j = 0; j < additionalProximitySize; ++j) { @@ -204,13 +206,46 @@ void ProximityInfo::calculateNearbyKeyCodes( } } // Add a delimiter for the proximity characters - inputCodes[insertPos] = 0; + for (int i = insertPos; i < MAX_PROXIMITY_CHARS_SIZE; ++i) { + inputCodes[i] = NOT_A_CODE; + } } // TODO: Calculate nearby codes here. -void ProximityInfo::setInputParams(const int* inputCodes, const int inputLength, +void ProximityInfo::setInputParams(const int32_t* inputCodes, const int inputLength, const int* xCoordinates, const int* yCoordinates) { - mInputCodes = inputCodes; + memset(mInputCodes, 0, + MAX_WORD_LENGTH_INTERNAL * MAX_PROXIMITY_CHARS_SIZE * sizeof(mInputCodes[0])); + + for (int i = 0; i < inputLength; ++i) { + const int32_t primaryKey = inputCodes[i * MAX_PROXIMITY_CHARS_SIZE]; + const int x = xCoordinates[i]; + const int y = yCoordinates[i]; + int *proximities = &mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE]; + calculateNearbyKeyCodes(x, y, primaryKey, proximities); + } + + if (DEBUG_PROXIMITY_CHARS) { + for (int i = 0; i < inputLength; ++i) { + AKLOGI("---"); + for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE; ++j) { + int icc = mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE + j]; + int icfjc = inputCodes[i * MAX_PROXIMITY_CHARS_SIZE + j]; + icc+= 0; + icfjc += 0; + AKLOGI("--- (%d)%c,%c", i, icc, icfjc); + AKLOGI("--- A<%d>,B<%d>", icc, icfjc); + } + } + } + //Keep for debug, sorry + //for (int i = 0; i < MAX_WORD_LENGTH_INTERNAL * MAX_PROXIMITY_CHARS_SIZE; ++i) { + //if (i < inputLength * MAX_PROXIMITY_CHARS_SIZE) { + //mInputCodes[i] = mInputCodesFromJava[i]; + //} else { + // mInputCodes[i] = 0; + // } + //} mInputXCoordinates = xCoordinates; mInputYCoordinates = yCoordinates; mTouchPositionCorrectionEnabled = @@ -246,8 +281,9 @@ void ProximityInfo::setInputParams(const int* inputCodes, const int inputLength, } for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE && proximityChars[j] > 0; ++j) { const int currentChar = proximityChars[j]; - const int keyIndex = getKeyIndex(currentChar); - const float squaredDistance = calculateNormalizedSquaredDistance(keyIndex, i); + const float squaredDistance = hasInputCoordinates() + ? calculateNormalizedSquaredDistance(getKeyIndex(currentChar), i) + : NOT_A_DISTANCE_FLOAT; if (squaredDistance >= 0.0f) { mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE + j] = (int)(squaredDistance * NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR); @@ -267,7 +303,6 @@ inline float square(const float x) { return x * x; } float ProximityInfo::calculateNormalizedSquaredDistance( const int keyIndex, const int inputIndex) const { - static const float NOT_A_DISTANCE_FLOAT = -1.0f; if (keyIndex == NOT_A_INDEX) { return NOT_A_DISTANCE_FLOAT; } @@ -282,8 +317,12 @@ float ProximityInfo::calculateNormalizedSquaredDistance( return squaredDistance / squaredRadius; } +bool ProximityInfo::hasInputCoordinates() const { + return mInputXCoordinates && mInputYCoordinates; +} + int ProximityInfo::getKeyIndex(const int c) const { - if (KEY_COUNT == 0 || !mInputXCoordinates || !mInputYCoordinates) { + if (KEY_COUNT == 0) { // We do not have the coordinate data return NOT_A_INDEX; } diff --git a/native/src/proximity_info.h b/native/src/proximity_info.h index 1a47aff84..cdc5a3d43 100644 --- a/native/src/proximity_info.h +++ b/native/src/proximity_info.h @@ -53,7 +53,7 @@ class ProximityInfo { const float *sweetSpotCenterYs, const float *sweetSpotRadii); ~ProximityInfo(); bool hasSpaceProximity(const int x, const int y) const; - void setInputParams(const int *inputCodes, const int inputLength, + void setInputParams(const int32_t *inputCodes, const int inputLength, const int *xCoordinates, const int *yCoordinates); const int* getProximityCharsAt(const int index) const; unsigned short getPrimaryCharAt(const int index) const; @@ -77,12 +77,15 @@ class ProximityInfo { static const int MAX_KEY_COUNT_IN_A_KEYBOARD = 64; // The upper limit of the char code in mCodeToKeyIndex static const int MAX_CHAR_CODE = 127; + static const float NOT_A_DISTANCE_FLOAT = -1.0f; + static const int NOT_A_CODE = -1; int getStartIndexFromCoordinates(const int x, const int y) const; void initializeCodeToKeyIndex(); float calculateNormalizedSquaredDistance(const int keyIndex, const int inputIndex) const; float calculateSquaredDistanceFromSweetSpotCenter( const int keyIndex, const int inputIndex) const; + bool hasInputCoordinates() const; int getKeyIndex(const int c) const; bool hasSweetSpotData(const int keyIndex) const { // When there are no calibration data for a key, @@ -105,7 +108,9 @@ class ProximityInfo { const int KEY_COUNT; const bool HAS_TOUCH_POSITION_CORRECTION_DATA; const std::string mLocaleStr; - const int *mInputCodes; + // TODO: remove this + const int *mInputCodesFromJava; + int32_t *mInputCodes; const int *mInputXCoordinates; const int *mInputYCoordinates; bool mTouchPositionCorrectionEnabled; -- cgit v1.2.3-83-g751a From 728d1c884e99e1fd25aa253b5ad30dbdb046ad5f Mon Sep 17 00:00:00 2001 From: satok Date: Mon, 19 Mar 2012 14:47:38 +0900 Subject: Cleanup proximity related code Bug: 4343280 Change-Id: I57c0f9e20d9d8911009ea97057251a7f7a81512f --- java/res/values-en/additional-proximitychars.xml | 62 ------- java/res/values/additional-proximitychars.xml | 23 --- .../android/inputmethod/keyboard/KeyDetector.java | 185 +-------------------- .../com/android/inputmethod/keyboard/Keyboard.java | 36 +--- .../inputmethod/keyboard/LatinKeyboardView.java | 1 - .../inputmethod/keyboard/MoreKeysDetector.java | 28 ---- .../inputmethod/keyboard/ProximityInfo.java | 35 +--- .../android/inputmethod/latin/InputAttributes.java | 1 + .../android/inputmethod/latin/SettingsValues.java | 1 - .../android/inputmethod/latin/WordComposer.java | 9 +- .../latin/suggestions/MoreSuggestions.java | 3 - .../latin/suggestions/SuggestionsView.java | 1 - 12 files changed, 13 insertions(+), 372 deletions(-) delete mode 100644 java/res/values-en/additional-proximitychars.xml delete mode 100644 java/res/values/additional-proximitychars.xml (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/res/values-en/additional-proximitychars.xml b/java/res/values-en/additional-proximitychars.xml deleted file mode 100644 index a5ff4a979..000000000 --- a/java/res/values-en/additional-proximitychars.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - a - e - i - o - u - - - e - a - i - o - u - - - i - a - e - o - u - - - o - a - e - i - u - - - u - a - e - i - o - - - - diff --git a/java/res/values/additional-proximitychars.xml b/java/res/values/additional-proximitychars.xml deleted file mode 100644 index 03d10d5d8..000000000 --- a/java/res/values/additional-proximitychars.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index c2ad56d9f..13e909c7e 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -16,17 +16,9 @@ package com.android.inputmethod.keyboard; -import android.util.Log; - -import java.util.Arrays; -import java.util.List; public class KeyDetector { - private static final String TAG = KeyDetector.class.getSimpleName(); - private static final boolean DEBUG = false; - public static final int NOT_A_CODE = -1; - private static final int ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE = 2; private final int mKeyHysteresisDistanceSquared; @@ -34,12 +26,6 @@ public class KeyDetector { private int mCorrectionX; private int mCorrectionY; private boolean mProximityCorrectOn; - private int mProximityThresholdSquare; - - // working area - private static final int MAX_NEARBY_KEYS = 12; - private final int[] mDistances = new int[MAX_NEARBY_KEYS]; - private final Key[] mNeighborKeys = new Key[MAX_NEARBY_KEYS]; /** * This class handles key detection. @@ -57,8 +43,6 @@ public class KeyDetector { mCorrectionX = (int)correctionX; mCorrectionY = (int)correctionY; mKeyboard = keyboard; - final int threshold = keyboard.mMostCommonKeyWidth; - mProximityThresholdSquare = threshold * threshold; } public int getKeyHysteresisDistanceSquared() { @@ -87,168 +71,10 @@ public class KeyDetector { return mProximityCorrectOn; } - public void setProximityThreshold(int threshold) { - mProximityThresholdSquare = threshold * threshold; - } - public boolean alwaysAllowsSlidingInput() { return false; } - /** - * Computes maximum size of the array that can contain all nearby key codes returned by - * {@link #getNearbyCodes}. - * - * @return Returns maximum size of the array that can contain all nearby key codes returned - * by {@link #getNearbyCodes}. - */ - protected int getMaxNearbyKeys() { - return MAX_NEARBY_KEYS; - } - - /** - * Allocates array that can hold all key codes returned by {@link #getNearbyCodes} - * method. The maximum size of the array should be computed by {@link #getMaxNearbyKeys}. - * - * @return Allocates and returns an array that can hold all key codes returned by - * {@link #getNearbyCodes} method. All elements in the returned array are - * initialized by {@link #NOT_A_CODE} value. - */ - public int[] newCodeArray() { - int[] codes = new int[getMaxNearbyKeys()]; - Arrays.fill(codes, NOT_A_CODE); - return codes; - } - - private void initializeNearbyKeys() { - Arrays.fill(mDistances, Integer.MAX_VALUE); - Arrays.fill(mNeighborKeys, null); - } - - /** - * Insert the key into nearby keys buffer and sort nearby keys by ascending order of distance. - * If the distance of two keys are the same, the key which the point is on should be considered - * as a closer one. - * - * @param key the key to be inserted into the nearby keys buffer. - * @param distance distance between the key's edge and user touched point. - * @param isOnKey true if the point is on the key. - * @return order of the key in the nearby buffer, 0 if it is the nearest key. - */ - private int sortNearbyKeys(Key key, int distance, boolean isOnKey) { - final int[] distances = mDistances; - final Key[] neighborKeys = mNeighborKeys; - for (int insertPos = 0; insertPos < distances.length; insertPos++) { - final int comparingDistance = distances[insertPos]; - if (distance < comparingDistance || (distance == comparingDistance && isOnKey)) { - final int nextPos = insertPos + 1; - if (nextPos < distances.length) { - System.arraycopy(distances, insertPos, distances, nextPos, - distances.length - nextPos); - System.arraycopy(neighborKeys, insertPos, neighborKeys, nextPos, - neighborKeys.length - nextPos); - } - distances[insertPos] = distance; - neighborKeys[insertPos] = key; - return insertPos; - } - } - return distances.length; - } - - private void getNearbyKeyCodes(final int primaryCode, final int[] allCodes) { - final Key[] neighborKeys = mNeighborKeys; - final int maxCodesSize = allCodes.length; - - // allCodes[0] should always have the key code even if it is a non-letter key. - if (neighborKeys[0] == null) { - allCodes[0] = NOT_A_CODE; - return; - } - - int numCodes = 0; - for (int j = 0; j < neighborKeys.length && numCodes < maxCodesSize; j++) { - final Key key = neighborKeys[j]; - if (key == null) - break; - final int code = key.mCode; - // filter out a non-letter key from nearby keys - if (code < Keyboard.CODE_SPACE) - continue; - allCodes[numCodes++] = code; - } - if (maxCodesSize <= numCodes) { - return; - } - - final int code = (primaryCode == NOT_A_CODE) ? allCodes[0] : primaryCode; - if (code == NOT_A_CODE) { - return; - } - final List additionalChars = mKeyboard.getAdditionalProximityChars().get(code); - if (additionalChars == null || additionalChars.size() == 0) { - return; - } - int currentCodesSize = numCodes; - allCodes[numCodes++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE; - if (maxCodesSize <= numCodes) { - return; - } - // TODO: This is O(N^2). Assuming additionalChars.size() is up to 4 or 5. - for (int i = 0; i < additionalChars.size(); ++i) { - final int additionalChar = additionalChars.get(i); - boolean contains = false; - for (int j = 0; j < currentCodesSize; ++j) { - if (additionalChar == allCodes[j]) { - contains = true; - break; - } - } - if (!contains) { - allCodes[numCodes++] = additionalChar; - if (maxCodesSize <= numCodes) { - return; - } - } - } - } - - /** - * Finds all possible nearby key codes around a touch event point and returns the nearest key. - * The algorithm to determine the nearby keys depends on the threshold set by - * {@link #setProximityThreshold(int)} and the mode set by - * {@link #setProximityCorrectionEnabled(boolean)}. - * - * @param x The x-coordinate of a touch point - * @param y The y-coordinate of a touch point - * @param allCodes All nearby key codes except functional key are returned in this array - */ - // TODO: Move this method to native code. - public void getNearbyCodes(int x, int y, final int[] allCodes) { - final int touchX = getTouchX(x); - final int touchY = getTouchY(y); - - initializeNearbyKeys(); - Key primaryKey = null; - for (final Key key : mKeyboard.getNearestKeys(touchX, touchY)) { - final boolean isOnKey = key.isOnKey(touchX, touchY); - final int distance = key.squaredDistanceToEdge(touchX, touchY); - if (isOnKey || (mProximityCorrectOn && distance < mProximityThresholdSquare)) { - final int insertedPosition = sortNearbyKeys(key, distance, isOnKey); - if (insertedPosition == 0 && isOnKey) { - primaryKey = key; - } - } - } - - getNearbyKeyCodes(primaryKey != null ? primaryKey.mCode : NOT_A_CODE, allCodes); - if (DEBUG) { - Log.d(TAG, "x=" + x + " y=" + y - + " primary=" + printableCode(primaryKey) - + " codes=" + printableCodes(allCodes)); - } - } - /** * Detect the key whose hitbox the touch point is in. * @@ -284,14 +110,9 @@ public class KeyDetector { boolean addDelimiter = false; for (final int code : codes) { if (code == NOT_A_CODE) break; - if (code == ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) { - sb.append(" | "); - addDelimiter = false; - } else { - if (addDelimiter) sb.append(", "); - sb.append(Keyboard.printableCode(code)); - addDelimiter = true; - } + if (addDelimiter) sb.append(", "); + sb.append(Keyboard.printableCode(code)); + addDelimiter = true; } return "[" + sb + "]"; } diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 973f64b4d..2b1cc43cd 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -20,7 +20,6 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; -import android.text.TextUtils; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; @@ -42,8 +41,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; -import java.util.List; -import java.util.Map; /** * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard @@ -133,8 +130,6 @@ public class Keyboard { private final ProximityInfo mProximityInfo; - private final Map> mAdditionalProximityChars; - public Keyboard(Params params) { mId = params.mId; mThemeId = params.mThemeId; @@ -153,12 +148,10 @@ public class Keyboard { mAltCodeKeysWhileTyping = params.mAltCodeKeysWhileTyping.toArray( new Key[params.mAltCodeKeysWhileTyping.size()]); mIconsSet = params.mIconsSet; - mAdditionalProximityChars = params.mAdditionalProximityChars; mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(), params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, - mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection, - params.mAdditionalProximityChars); + mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection); } public ProximityInfo getProximityInfo() { @@ -230,9 +223,6 @@ public class Keyboard { public final ArrayList mShiftKeys = new ArrayList(); public final ArrayList mAltCodeKeysWhileTyping = new ArrayList(); public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); - // TODO: Should be in Key instead of Keyboard.Params? - public final Map> mAdditionalProximityChars = - new HashMap>(); public KeyboardSet.KeysCache mKeysCache; @@ -368,10 +358,6 @@ public class Keyboard { return mProximityInfo.getNearestKeys(adjustedX, adjustedY); } - public Map> getAdditionalProximityChars() { - return mAdditionalProximityChars; - } - public static String printableCode(int code) { switch (code) { case CODE_SHIFT: return "shift"; @@ -630,7 +616,6 @@ public class Keyboard { mParams = params; setTouchPositionCorrectionData(context, params); - setAdditionalProximityChars(context, params); params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width); params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height); @@ -653,25 +638,6 @@ public class Keyboard { params.mTouchPositionCorrection.load(data); } - private static void setAdditionalProximityChars(Context context, Params params) { - final String[] additionalChars = - context.getResources().getStringArray(R.array.additional_proximitychars); - int currentPrimaryIndex = 0; - for (int i = 0; i < additionalChars.length; ++i) { - final String additionalChar = additionalChars[i]; - if (TextUtils.isEmpty(additionalChar)) { - currentPrimaryIndex = 0; - } else if (currentPrimaryIndex == 0) { - currentPrimaryIndex = additionalChar.charAt(0); - params.mAdditionalProximityChars.put( - currentPrimaryIndex, new ArrayList()); - } else if (currentPrimaryIndex != 0) { - final int c = additionalChar.charAt(0); - params.mAdditionalProximityChars.get(currentPrimaryIndex).add(c); - } - } - } - public void setAutoGenerate(KeyboardSet.KeysCache keysCache) { mParams.mKeysCache = keysCache; } diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 343842552..b869059e4 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -480,7 +480,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke super.setKeyboard(keyboard); mKeyDetector.setKeyboard( keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection); - mKeyDetector.setProximityThreshold(keyboard.mMostCommonKeyWidth); PointerTracker.setKeyDetector(mKeyDetector); mTouchScreenRegulator.setKeyboard(keyboard); mMoreKeysPanelCache.clear(); diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java index 6c8d02016..cd4e3001e 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java @@ -32,34 +32,6 @@ public class MoreKeysDetector extends KeyDetector { return true; } - @Override - protected int getMaxNearbyKeys() { - // No nearby key will be returned. - return 1; - } - - @Override - public void getNearbyCodes(int x, int y, final int[] allCodes) { - final int touchX = getTouchX(x); - final int touchY = getTouchY(y); - - Key nearestKey = null; - int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare; - for (final Key key : getKeyboard().mKeys) { - final int dist = key.squaredDistanceToEdge(touchX, touchY); - if (dist < nearestDist) { - nearestKey = key; - nearestDist = dist; - } - } - - if (nearestKey != null) { - allCodes[0] = nearestKey.mCode; - } else { - allCodes[0] = NOT_A_CODE; - } - } - @Override public Key detectHitKey(int x, int y) { final int touchX = getTouchX(x); diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index 61d75e278..442413c0c 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -24,10 +24,7 @@ import com.android.inputmethod.latin.JniUtils; import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.List; -import java.util.Map; public class ProximityInfo { public static final int MAX_PROXIMITY_CHARS_SIZE = 16; @@ -50,8 +47,7 @@ public class ProximityInfo { ProximityInfo(String localeStr, int gridWidth, int gridHeight, int minWidth, int height, int mostCommonKeyWidth, int mostCommonKeyHeight, final Key[] keys, - TouchPositionCorrection touchPositionCorrection, - Map> additionalProximityChars) { + TouchPositionCorrection touchPositionCorrection) { if (TextUtils.isEmpty(localeStr)) { mLocaleStr = ""; } else { @@ -72,12 +68,11 @@ public class ProximityInfo { return; } computeNearestNeighbors( - mostCommonKeyWidth, keys, touchPositionCorrection, additionalProximityChars); + mostCommonKeyWidth, keys, touchPositionCorrection); } public static ProximityInfo createDummyProximityInfo() { - return new ProximityInfo("", 1, 1, 1, 1, 1, 1, EMPTY_KEY_ARRAY, null, - Collections.> emptyMap()); + return new ProximityInfo("", 1, 1, 1, 1, 1, 1, EMPTY_KEY_ARRAY, null); } public static ProximityInfo createSpellCheckerProximityInfo(final int[] proximity) { @@ -184,8 +179,7 @@ public class ProximityInfo { } private void computeNearestNeighbors(int defaultWidth, final Key[] keys, - TouchPositionCorrection touchPositionCorrection, - Map> additionalProximityChars) { + TouchPositionCorrection touchPositionCorrection) { final HashMap keyCodeMap = new HashMap(); for (final Key key : keys) { keyCodeMap.put(key.mCode, key); @@ -207,27 +201,6 @@ public class ProximityInfo { neighborKeys[count++] = key; } } - int currentCodesSize = count; - for (int i = 0; i < currentCodesSize; ++i) { - final int c = neighborKeys[i].mCode; - final List additionalChars = additionalProximityChars.get(c); - if (additionalChars == null || additionalChars.size() == 0) { - continue; - } - for (int j = 0; j < additionalChars.size(); ++j) { - final int additionalChar = additionalChars.get(j); - boolean contains = false; - for (int k = 0; k < count; ++k) { - if(additionalChar == neighborKeys[k].mCode) { - contains = true; - break; - } - } - if (!contains) { - neighborKeys[count++] = keyCodeMap.get(additionalChar); - } - } - } mGridNeighbors[(y / mCellHeight) * mGridWidth + (x / mCellWidth)] = Arrays.copyOfRange(neighborKeys, 0, count); } diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java index f7afed2a5..06c70c42c 100644 --- a/java/src/com/android/inputmethod/latin/InputAttributes.java +++ b/java/src/com/android/inputmethod/latin/InputAttributes.java @@ -95,6 +95,7 @@ public class InputAttributes { } } + @SuppressWarnings("unused") private void dumpFlags(final int inputType) { Log.i(TAG, "Input class:"); final int inputClass = inputType & InputType.TYPE_MASK_CLASS; diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 020b57caf..9fc047b75 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -23,7 +23,6 @@ import android.os.Build; import android.util.Log; import android.view.inputmethod.EditorInfo; -import com.android.inputmethod.compat.InputMethodInfoCompatWrapper; import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.compat.VibratorCompatWrapper; import com.android.inputmethod.keyboard.internal.KeySpecParser; diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 251063ec4..9f23f174f 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -141,6 +141,7 @@ public class WordComposer { keyY = y; } else { final Key key = keyDetector.detectHitKey(x, y); + // TODO: Pass an integer instead of an integer array codes = new int[] { key != null ? key.mCode : NOT_A_CODE }; keyX = keyDetector.getTouchX(x); keyY = keyDetector.getTouchY(y); @@ -202,9 +203,8 @@ public class WordComposer { if (key.mCode == codePoint) { final int x = key.mX + key.mWidth / 2; final int y = key.mY + key.mHeight / 2; - final int[] codes = keyDetector.newCodeArray(); - keyDetector.getNearbyCodes(x, y, codes); - add(codePoint, codes, x, y); + // TODO: Pass an integer instead of an integer array + add(codePoint, new int[] { key.mCode }, x, y); return; } } @@ -216,7 +216,7 @@ public class WordComposer { * Set the currently composing word to the one passed as an argument. * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. */ - public void setComposingWord(final CharSequence word, final Keyboard keyboard, + private void setComposingWord(final CharSequence word, final Keyboard keyboard, final KeyDetector keyDetector) { reset(); final int length = word.length(); @@ -233,7 +233,6 @@ public class WordComposer { final KeyDetector keyDetector = new KeyDetector(0); keyDetector.setKeyboard(keyboard, 0, 0); keyDetector.setProximityCorrectionEnabled(true); - keyDetector.setProximityThreshold(keyboard.mMostCommonKeyWidth); setComposingWord(word, keyboard, keyDetector); } diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java index c9c88fd23..3a17f1f64 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java @@ -25,7 +25,6 @@ import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; -import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.Utils; @@ -38,8 +37,6 @@ public class MoreSuggestions extends Keyboard { } public static class Builder extends Keyboard.Builder { - private static final boolean DBG = LatinImeLogger.sDBG; - private final MoreSuggestionsView mPaneView; private SuggestedWords mSuggestions; private int mFromPos; diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java index 286bf0aea..06fda44fa 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java @@ -62,7 +62,6 @@ import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; import com.android.inputmethod.latin.Suggest; import com.android.inputmethod.latin.SuggestedWords; -import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.Utils; import java.util.ArrayList; -- cgit v1.2.3-83-g751a From 081616cd2f472295449268cecb570771b969cba3 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 22 Mar 2012 17:39:27 +0900 Subject: Send correct coordinates for the spell checker This results in the computation being done in native code and the correct proximity being used. Bug: 6181080 Change-Id: I08fa05c781d607e4feca2caeda353ec19c133a3d --- .../inputmethod/keyboard/ProximityInfo.java | 6 +++-- .../android/inputmethod/latin/WordComposer.java | 29 ++-------------------- .../spellcheck/AndroidSpellCheckerService.java | 6 ++++- .../spellcheck/SpellCheckerProximityInfo.java | 24 +++++++++++++++--- native/src/proximity_info.cpp | 5 ++-- 5 files changed, 34 insertions(+), 36 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index aa499ed24..5c1808613 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -79,10 +79,12 @@ public class ProximityInfo { final ProximityInfo spellCheckerProximityInfo = createDummyProximityInfo(); spellCheckerProximityInfo.mNativeProximityInfo = spellCheckerProximityInfo.setProximityInfoNative("", - SpellCheckerProximityInfo.ROW_SIZE, 480, 300, + SpellCheckerProximityInfo.ROW_SIZE, SpellCheckerProximityInfo.PROXIMITY_GRID_WIDTH, SpellCheckerProximityInfo.PROXIMITY_GRID_HEIGHT, - (480 / 10), proximity, 0, null, null, null, null, null, null, null, null); + SpellCheckerProximityInfo.PROXIMITY_GRID_WIDTH, + SpellCheckerProximityInfo.PROXIMITY_GRID_HEIGHT, + 1, proximity, 0, null, null, null, null, null, null, null, null); return spellCheckerProximityInfo; } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 9f23f174f..231211d31 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -127,12 +127,8 @@ public class WordComposer { final int[] codes; final int keyX; final int keyY; - if (x == KeyboardActionListener.SPELL_CHECKER_COORDINATE - || y == KeyboardActionListener.SPELL_CHECKER_COORDINATE) { - // only used for tests in InputLogicTests - addKeyForSpellChecker(primaryCode, AndroidSpellCheckerService.SCRIPT_LATIN); - return; - } else if (x == KeyboardActionListener.SUGGESTION_STRIP_COORDINATE + if (null == keyDetector + || x == KeyboardActionListener.SUGGESTION_STRIP_COORDINATE || y == KeyboardActionListener.SUGGESTION_STRIP_COORDINATE || x == KeyboardActionListener.NOT_A_TOUCH_COORDINATE || y == KeyboardActionListener.NOT_A_TOUCH_COORDINATE) { @@ -149,27 +145,6 @@ public class WordComposer { add(primaryCode, codes, keyX, keyY); } - // TODO: remove this function - public void addKeyForSpellChecker(int primaryCode, int script) { - final int[] proximities; - final int proximityIndex = - SpellCheckerProximityInfo.getIndexOfCodeForScript(primaryCode, script); - if (-1 == proximityIndex) { - proximities = new int[] { primaryCode }; - } else { - // TODO: an initial examination seems to reveal this is actually used - // read-only. It should be possible to compute the arrays statically once - // and skip doing a copy each time here. - proximities = Arrays.copyOfRange( - SpellCheckerProximityInfo.getProximityForScript(script), - proximityIndex, - proximityIndex + SpellCheckerProximityInfo.ROW_SIZE); - } - add(primaryCode, proximities, - KeyboardActionListener.NOT_A_TOUCH_COORDINATE, - KeyboardActionListener.NOT_A_TOUCH_COORDINATE); - } - /** * Add a new keystroke, with codes[0] containing the pressed key's unicode and the rest of * the array containing unicode for adjacent keys, sorted by reducing probability/proximity. diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 35a5c0f52..973a448ee 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -570,7 +570,11 @@ public class AndroidSpellCheckerService extends SpellCheckerService final WordComposer composer = new WordComposer(); final int length = text.length(); for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { - composer.addKeyForSpellChecker(text.codePointAt(i), mScript); + final int codePoint = text.codePointAt(i); + // The getXYForCodePointAndScript method returns (Y << 16) + X + final int xy = SpellCheckerProximityInfo.getXYForCodePointAndScript( + codePoint, mScript); + composer.add(codePoint, xy & 0xFFFF, xy >> 16, null); } final int capitalizeType = getCapitalizationType(text); diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java index f4c66d04c..90c0aac1b 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java @@ -87,7 +87,7 @@ public class SpellCheckerProximityInfo { // Proximity for row 2. See comment above about size. 'a', 'z', 'x', 's', 'w', 'q', 'e', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL, 's', 'q', 'a', 'z', 'x', 'c', 'd', 'e', 'w', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'd', 'w', 's', 'x', 'c', 'v', 'f', 'r', 'e', 'w', NUL, NUL, NUL, NUL, NUL, NUL, + 'd', 'w', 's', 'x', 'c', 'v', 'f', 'r', 'e', NUL, NUL, NUL, NUL, NUL, NUL, NUL, 'f', 'e', 'd', 'c', 'v', 'b', 'g', 't', 'r', NUL, NUL, NUL, NUL, NUL, NUL, NUL, 'g', 'r', 'f', 'v', 'b', 'n', 'h', 'y', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL, 'h', 't', 'g', 'b', 'n', 'm', 'j', 'u', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL, @@ -181,14 +181,30 @@ public class SpellCheckerProximityInfo { throw new RuntimeException("Wrong script supplied: " + script); } } - public static int getIndexOfCodeForScript(final int characterCode, final int script) { + + private static int getIndexOfCodeForScript(final int codePoint, final int script) { switch (script) { case AndroidSpellCheckerService.SCRIPT_LATIN: - return Latin.getIndexOf(characterCode); + return Latin.getIndexOf(codePoint); case AndroidSpellCheckerService.SCRIPT_CYRILLIC: - return Cyrillic.getIndexOf(characterCode); + return Cyrillic.getIndexOf(codePoint); default: throw new RuntimeException("Wrong script supplied: " + script); } } + + // Returns (Y << 16) + X to avoid creating a temporary object. This is okay because + // X and Y are limited to PROXIMITY_GRID_WIDTH resp. PROXIMITY_GRID_HEIGHT which is very + // inferior to 1 << 16 + public static int getXYForCodePointAndScript(final int codePoint, final int script) { + final int index = getIndexOfCodeForScript(codePoint, script); + // TODO: precompute index / ROW_SIZE + final int y = index / (PROXIMITY_GRID_WIDTH * ROW_SIZE); + final int x = (index / ROW_SIZE) % PROXIMITY_GRID_WIDTH; + if (y > PROXIMITY_GRID_HEIGHT) { + // Safety check, should be entirely useless + throw new RuntimeException("Wrong y coordinate in spell checker proximity"); + } + return (y << 16) + x; + } } diff --git a/native/src/proximity_info.cpp b/native/src/proximity_info.cpp index 4d03f3274..47f137610 100644 --- a/native/src/proximity_info.cpp +++ b/native/src/proximity_info.cpp @@ -130,6 +130,7 @@ bool ProximityInfo::hasSpaceProximity(const int x, const int y) const { } bool ProximityInfo::isOnKey(const int keyId, const int x, const int y) { + if (keyId < 0) return true; // NOT_A_ID is -1, but return whenever < 0 just in case const int left = mKeyXCoordinates[keyId]; const int top = mKeyYCoordinates[keyId]; const int right = left + mKeyWidths[keyId] + 1; @@ -138,6 +139,7 @@ bool ProximityInfo::isOnKey(const int keyId, const int x, const int y) { } int ProximityInfo::squaredDistanceToEdge(const int keyId, const int x, const int y) { + if (keyId < 0) return true; // NOT_A_ID is -1, but return whenever < 0 just in case const int left = mKeyXCoordinates[keyId]; const int top = mKeyYCoordinates[keyId]; const int right = left + mKeyWidths[keyId]; @@ -162,7 +164,7 @@ void ProximityInfo::calculateNearbyKeyCodes( const int keyIndex = getKeyIndex(c); const bool onKey = isOnKey(keyIndex, x, y); const int distance = squaredDistanceToEdge(keyIndex, x, y); - if (c >= KEYCODE_SPACE && (onKey || distance < MOST_COMMON_KEY_WIDTH_SQUARE)) { + if (onKey || distance < MOST_COMMON_KEY_WIDTH_SQUARE) { inputCodes[insertPos++] = c; if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) { if (DEBUG_DICT) { @@ -211,7 +213,6 @@ void ProximityInfo::calculateNearbyKeyCodes( } } -// TODO: Calculate nearby codes here. void ProximityInfo::setInputParams(const int32_t* inputCodes, const int inputLength, const int* xCoordinates, const int* yCoordinates) { memset(mInputCodes, 0, -- cgit v1.2.3-83-g751a From a492790982c6d7df62f66344db30b31995800e1b Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 23 Mar 2012 17:55:11 +0900 Subject: Stop creating useless objects Man that was bad, it's heavy, it's called quite often, and it's totally useless Change-Id: Ia7e23e0e60ff4a929b226f3f4ccabedbc3ea2c06 --- .../com/android/inputmethod/latin/WordComposer.java | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 231211d31..ebd802fae 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -172,8 +172,7 @@ public class WordComposer { /** * Internal method to retrieve reasonable proximity info for a character. */ - private void addKeyInfo(final int codePoint, final Keyboard keyboard, - final KeyDetector keyDetector) { + private void addKeyInfo(final int codePoint, final Keyboard keyboard) { for (final Key key : keyboard.mKeys) { if (key.mCode == codePoint) { final int x = key.mX + key.mWidth / 2; @@ -191,26 +190,15 @@ public class WordComposer { * Set the currently composing word to the one passed as an argument. * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. */ - private void setComposingWord(final CharSequence word, final Keyboard keyboard, - final KeyDetector keyDetector) { + public void setComposingWord(final CharSequence word, final Keyboard keyboard) { reset(); final int length = word.length(); for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) { int codePoint = Character.codePointAt(word, i); - addKeyInfo(codePoint, keyboard, keyDetector); + addKeyInfo(codePoint, keyboard); } } - /** - * Shortcut for the above method, this will create a new KeyDetector for the passed keyboard. - */ - public void setComposingWord(final CharSequence word, final Keyboard keyboard) { - final KeyDetector keyDetector = new KeyDetector(0); - keyDetector.setKeyboard(keyboard, 0, 0); - keyDetector.setProximityCorrectionEnabled(true); - setComposingWord(word, keyboard, keyDetector); - } - /** * Delete the last keystroke as a result of hitting backspace. */ -- cgit v1.2.3-83-g751a From 9df4a4527a9bc2e671f644d6e2ec0121385740ec Mon Sep 17 00:00:00 2001 From: satok Date: Fri, 23 Mar 2012 16:05:18 +0900 Subject: Cleanup jni 1 Change-Id: Ieb6af8385356e259720b50f1fe46a694a098b30f --- .../inputmethod/latin/BinaryDictionary.java | 8 +++-- .../android/inputmethod/latin/WordComposer.java | 2 -- native/src/proximity_info.cpp | 8 ++--- native/src/proximity_info.h | 6 ++-- native/src/unigram_dictionary.cpp | 34 +++++++++------------- native/src/unigram_dictionary.h | 1 - 6 files changed, 26 insertions(+), 33 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index dfc8c8e9d..3aa0376e5 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -202,9 +202,11 @@ public class BinaryDictionary extends Dictionary { 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_PROXIMITY_CHARS_SIZE, - Math.min(alternatives.length, MAX_PROXIMITY_CHARS_SIZE)); + final int[] alternatives = codes.getCodesAt(i); + if (alternatives == null || alternatives.length < 1) { + continue; + } + mInputCodes[i] = alternatives[0]; } Arrays.fill(outputChars, (char) 0); Arrays.fill(scores, 0); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 231211d31..ef8ca47c2 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -20,8 +20,6 @@ import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardActionListener; -import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService; -import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo; import java.util.ArrayList; import java.util.Arrays; diff --git a/native/src/proximity_info.cpp b/native/src/proximity_info.cpp index 47f137610..679b3c273 100644 --- a/native/src/proximity_info.cpp +++ b/native/src/proximity_info.cpp @@ -129,7 +129,7 @@ bool ProximityInfo::hasSpaceProximity(const int x, const int y) const { return false; } -bool ProximityInfo::isOnKey(const int keyId, const int x, const int y) { +bool ProximityInfo::isOnKey(const int keyId, const int x, const int y) const { if (keyId < 0) return true; // NOT_A_ID is -1, but return whenever < 0 just in case const int left = mKeyXCoordinates[keyId]; const int top = mKeyYCoordinates[keyId]; @@ -138,7 +138,7 @@ bool ProximityInfo::isOnKey(const int keyId, const int x, const int y) { return left < right && top < bottom && x >= left && x < right && y >= top && y < bottom; } -int ProximityInfo::squaredDistanceToEdge(const int keyId, const int x, const int y) { +int ProximityInfo::squaredDistanceToEdge(const int keyId, const int x, const int y) const { if (keyId < 0) return true; // NOT_A_ID is -1, but return whenever < 0 just in case const int left = mKeyXCoordinates[keyId]; const int top = mKeyYCoordinates[keyId]; @@ -152,7 +152,7 @@ int ProximityInfo::squaredDistanceToEdge(const int keyId, const int x, const int } void ProximityInfo::calculateNearbyKeyCodes( - const int x, const int y, const int32_t primaryKey, int *inputCodes) { + const int x, const int y, const int32_t primaryKey, int *inputCodes) const { int insertPos = 0; inputCodes[insertPos++] = primaryKey; const int startIndex = getStartIndexFromCoordinates(x, y); @@ -219,7 +219,7 @@ void ProximityInfo::setInputParams(const int32_t* inputCodes, const int inputLen MAX_WORD_LENGTH_INTERNAL * MAX_PROXIMITY_CHARS_SIZE * sizeof(mInputCodes[0])); for (int i = 0; i < inputLength; ++i) { - const int32_t primaryKey = inputCodes[i * MAX_PROXIMITY_CHARS_SIZE]; + const int32_t primaryKey = inputCodes[i]; const int x = xCoordinates[i]; const int y = yCoordinates[i]; int *proximities = &mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE]; diff --git a/native/src/proximity_info.h b/native/src/proximity_info.h index cdc5a3d43..c1eefeacc 100644 --- a/native/src/proximity_info.h +++ b/native/src/proximity_info.h @@ -92,10 +92,10 @@ class ProximityInfo { // the radius of the key is assigned to zero. return mSweetSpotRadii[keyIndex] > 0.0; } - bool isOnKey(const int keyId, const int x, const int y); - int squaredDistanceToEdge(const int keyId, const int x, const int y); + bool isOnKey(const int keyId, const int x, const int y) const; + int squaredDistanceToEdge(const int keyId, const int x, const int y) const; void calculateNearbyKeyCodes( - const int x, const int y, const int32_t primaryKey, int *inputCodes); + const int x, const int y, const int32_t primaryKey, int *inputCodes) const; const int MAX_PROXIMITY_CHARS_SIZE; const int KEYBOARD_WIDTH; diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp index 563541dce..b170fcd00 100644 --- a/native/src/unigram_dictionary.cpp +++ b/native/src/unigram_dictionary.cpp @@ -39,11 +39,11 @@ UnigramDictionary::UnigramDictionary(const uint8_t* const streamStart, int typed int fullWordMultiplier, int maxWordLength, int maxWords, int maxProximityChars, const bool isLatestDictVersion) : DICT_ROOT(streamStart), MAX_WORD_LENGTH(maxWordLength), MAX_WORDS(maxWords), - MAX_PROXIMITY_CHARS(maxProximityChars), IS_LATEST_DICT_VERSION(isLatestDictVersion), + IS_LATEST_DICT_VERSION(isLatestDictVersion), TYPED_LETTER_MULTIPLIER(typedLetterMultiplier), FULL_WORD_MULTIPLIER(fullWordMultiplier), // TODO : remove this variable. ROOT_POS(0), - BYTES_IN_ONE_CHAR(MAX_PROXIMITY_CHARS * sizeof(int)), + BYTES_IN_ONE_CHAR(sizeof(int)), MAX_DIGRAPH_SEARCH_DEPTH(DEFAULT_MAX_DIGRAPH_SEARCH_DEPTH) { if (DEBUG_DICT) { AKLOGI("UnigramDictionary - constructor"); @@ -53,9 +53,8 @@ UnigramDictionary::UnigramDictionary(const uint8_t* const streamStart, int typed UnigramDictionary::~UnigramDictionary() { } -static inline unsigned int getCodesBufferSize(const int *codes, const int codesSize, - const int MAX_PROXIMITY_CHARS) { - return sizeof(*codes) * MAX_PROXIMITY_CHARS * codesSize; +static inline unsigned int getCodesBufferSize(const int *codes, const int codesSize) { + return sizeof(*codes) * codesSize; } // TODO: This needs to take a const unsigned short* and not tinker with its contents @@ -73,7 +72,7 @@ int UnigramDictionary::getDigraphReplacement(const int *codes, const int i, cons // Search for the first char of some digraph int lastDigraphIndex = -1; - const int thisChar = codes[i * MAX_PROXIMITY_CHARS]; + const int thisChar = codes[i]; for (lastDigraphIndex = digraphsSize - 1; lastDigraphIndex >= 0; --lastDigraphIndex) { if (thisChar == digraphs[lastDigraphIndex].first) break; } @@ -81,7 +80,7 @@ int UnigramDictionary::getDigraphReplacement(const int *codes, const int i, cons if (lastDigraphIndex < 0) return 0; // It's an interesting digraph if the second char matches too. - if (digraphs[lastDigraphIndex].second == codes[(i + 1) * MAX_PROXIMITY_CHARS]) { + if (digraphs[lastDigraphIndex].second == codes[i + 1]) { return digraphs[lastDigraphIndex].replacement; } else { return 0; @@ -102,7 +101,7 @@ void UnigramDictionary::getWordWithDigraphSuggestionsRec(ProximityInfo *proximit WordsPriorityQueuePool *queuePool, const digraph_t* const digraphs, const unsigned int digraphsSize) { - const int startIndex = (codesDest - codesBuffer) / MAX_PROXIMITY_CHARS; + const int startIndex = codesDest - codesBuffer; if (currentDepth < MAX_DIGRAPH_SEARCH_DEPTH) { for (int i = 0; i < codesRemain; ++i) { xCoordinatesBuffer[startIndex + i] = xcoordinates[codesBufferSize - codesRemain + i]; @@ -126,19 +125,18 @@ void UnigramDictionary::getWordWithDigraphSuggestionsRec(ProximityInfo *proximit replacementCodePoint; getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer, xCoordinatesBuffer, yCoordinatesBuffer, codesBufferSize, flags, - codesSrc + (i + 1) * MAX_PROXIMITY_CHARS, codesRemain - i - 1, - currentDepth + 1, codesDest + i * MAX_PROXIMITY_CHARS, correction, + codesSrc + i + 1, codesRemain - i - 1, + currentDepth + 1, codesDest + i, correction, queuePool, digraphs, digraphsSize); // Copy the second char of the digraph in place, then continue processing on // the remaining part of the word. // In our example, after "pru" in the buffer copy the "e", and continue on "fen" - memcpy(codesDest + i * MAX_PROXIMITY_CHARS, codesSrc + i * MAX_PROXIMITY_CHARS, - BYTES_IN_ONE_CHAR); + memcpy(codesDest + i, codesSrc + i, BYTES_IN_ONE_CHAR); getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer, xCoordinatesBuffer, yCoordinatesBuffer, codesBufferSize, flags, - codesSrc + i * MAX_PROXIMITY_CHARS, codesRemain - i, currentDepth + 1, - codesDest + i * MAX_PROXIMITY_CHARS, correction, queuePool, + codesSrc + i, codesRemain - i, currentDepth + 1, + codesDest + i, correction, queuePool, digraphs, digraphsSize); return; } @@ -173,7 +171,7 @@ int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, Correction* masterCorrection = correction; if (REQUIRES_GERMAN_UMLAUT_PROCESSING & flags) { // Incrementally tune the word and try all possibilities - int codesBuffer[getCodesBufferSize(codes, codesSize, MAX_PROXIMITY_CHARS)]; + int codesBuffer[getCodesBufferSize(codes, codesSize)]; int xCoordinatesBuffer[codesSize]; int yCoordinatesBuffer[codesSize]; getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer, @@ -414,7 +412,7 @@ bool UnigramDictionary::getSubStringSuggestion( if (inputWordStartPos > 0) { const int offset = inputWordStartPos; initSuggestions(proximityInfo, &xcoordinates[offset], &ycoordinates[offset], - codes + offset * MAX_PROXIMITY_CHARS, inputWordLength, correction); + codes + offset, inputWordLength, correction); queuePool->clearSubQueue(currentWordIndex); getSuggestionCandidates(useFullEditDistance, inputWordLength, correction, queuePool, false, MAX_ERRORS_FOR_TWO_WORDS, currentWordIndex); @@ -572,10 +570,6 @@ void UnigramDictionary::getSplitMultipleWordsSuggestions(ProximityInfo *proximit Correction *correction, WordsPriorityQueuePool* queuePool, const bool hasAutoCorrectionCandidate) { if (inputLength >= MAX_WORD_LENGTH) return; - if (DEBUG_DICT) { - // MAX_PROXIMITY_CHARS_SIZE in ProximityInfo.java should be 16 - assert(MAX_PROXIMITY_CHARS == 16); - } if (DEBUG_DICT) { AKLOGI("--- Suggest multiple words"); } diff --git a/native/src/unigram_dictionary.h b/native/src/unigram_dictionary.h index b85913ffb..94ca626b0 100644 --- a/native/src/unigram_dictionary.h +++ b/native/src/unigram_dictionary.h @@ -143,7 +143,6 @@ class UnigramDictionary { const uint8_t* const DICT_ROOT; const int MAX_WORD_LENGTH; const int MAX_WORDS; - const int MAX_PROXIMITY_CHARS; const bool IS_LATEST_DICT_VERSION; const int TYPED_LETTER_MULTIPLIER; const int FULL_WORD_MULTIPLIER; -- cgit v1.2.3-83-g751a From 01ab7c8b59a7f12862fbd95fb252e56719f1757f Mon Sep 17 00:00:00 2001 From: satok Date: Tue, 27 Mar 2012 15:21:54 +0900 Subject: ongoing cleanup 2 Change-Id: I66b61cbe491cf8375144e834390beae3209a777d --- .../inputmethod/latin/BinaryDictionary.java | 10 +---- .../inputmethod/latin/ExpandableDictionary.java | 8 +++- .../inputmethod/latin/LastComposedWord.java | 8 ++-- .../android/inputmethod/latin/WordComposer.java | 52 ++++++++++++---------- 4 files changed, 39 insertions(+), 39 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index a9df1ce12..9909638d4 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -144,9 +144,7 @@ public class BinaryDictionary extends Dictionary { int codesSize = codes.size(); Arrays.fill(mInputCodes, -1); if (codesSize > 0) { - int[] alternatives = codes.getCodesAt(0); - System.arraycopy(alternatives, 0, mInputCodes, 0, - Math.min(alternatives.length, MAX_PROXIMITY_CHARS_SIZE)); + mInputCodes[0] = codes.getCodeAt(0); } int count = getBigramsNative(mNativeDict, chars, chars.length, mInputCodes, codesSize, @@ -205,11 +203,7 @@ public class BinaryDictionary extends Dictionary { Arrays.fill(mInputCodes, WordComposer.NOT_A_CODE); for (int i = 0; i < codesSize; i++) { - final int[] alternatives = codes.getCodesAt(i); - if (alternatives == null || alternatives.length < 1) { - continue; - } - mInputCodes[i] = alternatives[0]; + mInputCodes[i] = codes.getCodeAt(i); } Arrays.fill(outputChars, (char) 0); Arrays.fill(scores, 0); diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 8e8adc1c2..f8de029bd 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -210,7 +210,11 @@ public class ExpandableDictionary extends Dictionary { 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++) { - mCodes[i] = codes.getCodesAt(i); + // TODO: Calculate proximity info here. + if (mCodes[i] == null || mCodes[i].length < 1) { + mCodes[i] = new int[1]; + } + mCodes[i][0] = codes.getCodeAt(i); } mMaxDepth = mInputLength * 3; getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, -1, callback); @@ -319,7 +323,7 @@ public class ExpandableDictionary extends Dictionary { } } else { // Don't use alternatives if we're looking for missing characters - final int alternativesSize = skipPos >= 0? 1 : currentChars.length; + final int alternativesSize = skipPos >= 0 ? 1 : currentChars.length; for (int j = 0; j < alternativesSize; j++) { final int addedAttenuation = (j > 0 ? 1 : 2); final int currentChar = currentChars[j]; diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index bc0792434..af0ef4b37 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -18,8 +18,6 @@ package com.android.inputmethod.latin; import android.text.TextUtils; -import java.util.ArrayList; - /** * This class encapsulates data about a word previously composed, but that has been * committed already. This is used for resuming suggestion, and cancel auto-correction. @@ -42,7 +40,7 @@ public class LastComposedWord { public static final int NOT_A_SEPARATOR = -1; - public final ArrayList mCodes; + public final int[] mPrimaryKeyCodes; public final int[] mXCoordinates; public final int[] mYCoordinates; public final String mTypedWord; @@ -56,10 +54,10 @@ public class LastComposedWord { // Warning: this is using the passed objects as is and fully expects them to be // immutable. Do not fiddle with their contents after you passed them to this constructor. - public LastComposedWord(final ArrayList codes, final int[] xCoordinates, + public LastComposedWord(final int[] primaryKeyCodes, final int[] xCoordinates, final int[] yCoordinates, final String typedWord, final String committedWord, final int separatorCode) { - mCodes = codes; + mPrimaryKeyCodes = primaryKeyCodes; mXCoordinates = xCoordinates; mYCoordinates = yCoordinates; mTypedWord = typedWord; diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index cabf68099..29a7e4816 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -21,7 +21,6 @@ import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardActionListener; -import java.util.ArrayList; import java.util.Arrays; /** @@ -32,9 +31,9 @@ public class WordComposer { public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE; public static final int NOT_A_COORDINATE = -1; - final static int N = BinaryDictionary.MAX_WORD_LENGTH; + private static final int N = BinaryDictionary.MAX_WORD_LENGTH; - private ArrayList mCodes; + private int[] mPrimaryKeyCodes; private int[] mXCoordinates; private int[] mYCoordinates; private StringBuilder mTypedWord; @@ -44,6 +43,7 @@ public class WordComposer { private int mCapsCount; private boolean mAutoCapitalized; private int mTrailingSingleQuotesCount; + private int mCodePointSize; /** * Whether the user chose to capitalize the first char of the word. @@ -51,12 +51,13 @@ public class WordComposer { private boolean mIsFirstCharCapitalized; public WordComposer() { - mCodes = new ArrayList(N); + mPrimaryKeyCodes = new int[N]; mTypedWord = new StringBuilder(N); mXCoordinates = new int[N]; mYCoordinates = new int[N]; mAutoCorrection = null; mTrailingSingleQuotesCount = 0; + refreshSize(); } public WordComposer(WordComposer source) { @@ -64,7 +65,7 @@ public class WordComposer { } public void init(WordComposer source) { - mCodes = new ArrayList(source.mCodes); + mPrimaryKeyCodes = Arrays.copyOf(source.mPrimaryKeyCodes, source.mPrimaryKeyCodes.length); mTypedWord = new StringBuilder(source.mTypedWord); mXCoordinates = Arrays.copyOf(source.mXCoordinates, source.mXCoordinates.length); mYCoordinates = Arrays.copyOf(source.mYCoordinates, source.mYCoordinates.length); @@ -72,18 +73,23 @@ public class WordComposer { mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount; + refreshSize(); } /** * Clear out the keys registered so far. */ public void reset() { - mCodes.clear(); mTypedWord.setLength(0); mAutoCorrection = null; mCapsCount = 0; mIsFirstCharCapitalized = false; mTrailingSingleQuotesCount = 0; + refreshSize(); + } + + public final void refreshSize() { + mCodePointSize = mTypedWord.codePointCount(0, mTypedWord.length()); } /** @@ -91,20 +97,15 @@ public class WordComposer { * @return the number of keystrokes */ public final int size() { - return mCodes.size(); + return mCodePointSize; } public final boolean isComposingWord() { - return mCodes.size() > 0; + return size() > 0; } - /** - * Returns the codes at a particular position in the word. - * @param index the position in the word - * @return the unicode for the pressed and surrounding keys - */ - public int[] getCodesAt(int index) { - return mCodes.get(index); + public int getCodeAt(int index) { + return mPrimaryKeyCodes[index]; } public int[] getXCoordinates() { @@ -149,9 +150,10 @@ public class WordComposer { * @param codes the array of unicode values */ private void add(int primaryCode, int[] codes, int keyX, int keyY) { - final int newIndex = mCodes.size(); + final int newIndex = size(); mTypedWord.appendCodePoint(primaryCode); - mCodes.add(codes); + refreshSize(); + mPrimaryKeyCodes[newIndex] = codes[0]; if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { mXCoordinates[newIndex] = keyX; mYCoordinates[newIndex] = keyY; @@ -201,9 +203,8 @@ public class WordComposer { * Delete the last keystroke as a result of hitting backspace. */ public void deleteLast() { - final int size = mCodes.size(); + final int size = size(); if (size > 0) { - mCodes.remove(size - 1); // Note: mTypedWord.length() and mCodes.length differ when there are surrogate pairs final int stringBuilderLength = mTypedWord.length(); if (stringBuilderLength < size) { @@ -217,9 +218,10 @@ public class WordComposer { mTypedWord.deleteCharAt(stringBuilderLength - 1); } if (Character.isUpperCase(lastChar)) mCapsCount--; + refreshSize(); } // We may have deleted the last one. - if (0 == mCodes.size()) { + if (0 == size()) { mIsFirstCharCapitalized = false; } if (mTrailingSingleQuotesCount > 0) { @@ -307,29 +309,31 @@ public class WordComposer { // Note: currently, we come here whenever we commit a word. If it's a MANUAL_PICK // or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate // the last composed word to ensure this does not happen. - final ArrayList codes = mCodes; + final int[] primaryKeyCodes = mPrimaryKeyCodes; final int[] xCoordinates = mXCoordinates; final int[] yCoordinates = mYCoordinates; - mCodes = new ArrayList(N); + mPrimaryKeyCodes = new int[N]; mXCoordinates = new int[N]; mYCoordinates = new int[N]; - final LastComposedWord lastComposedWord = new LastComposedWord(codes, + final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes, xCoordinates, yCoordinates, mTypedWord.toString(), committedWord, separatorCode); if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD && type != LastComposedWord.COMMIT_TYPE_MANUAL_PICK) { lastComposedWord.deactivate(); } mTypedWord.setLength(0); + refreshSize(); mAutoCorrection = null; return lastComposedWord; } public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) { - mCodes = lastComposedWord.mCodes; + mPrimaryKeyCodes = lastComposedWord.mPrimaryKeyCodes; mXCoordinates = lastComposedWord.mXCoordinates; mYCoordinates = lastComposedWord.mYCoordinates; mTypedWord.setLength(0); mTypedWord.append(lastComposedWord.mTypedWord); + refreshSize(); mAutoCorrection = null; // This will be filled by the next call to updateSuggestion. } } -- cgit v1.2.3-83-g751a From 9611b281e18ac71d825ff5bc771a111423772cb3 Mon Sep 17 00:00:00 2001 From: satok Date: Wed, 28 Mar 2012 11:32:11 +0900 Subject: Fix AIOOBE Bug: 6236912 Change-Id: Ie09e5ef1c23eb48621ac3f2f2dc28dc2e46ca288 --- .../inputmethod/latin/ExpandableDictionary.java | 25 +++++++++++----------- .../inputmethod/latin/UserHistoryDictionary.java | 4 ++-- .../android/inputmethod/latin/WordComposer.java | 6 +++++- 3 files changed, 20 insertions(+), 15 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index f8de029bd..098913bef 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -28,17 +28,12 @@ import java.util.LinkedList; * be searched for suggestions and valid words. */ public class ExpandableDictionary extends Dictionary { - /** - * There is difference between what java and native code can handle. - * It uses 32 because Java stack overflows when greater value is used. - */ - protected static final int MAX_WORD_LENGTH = 32; // Bigram frequency is a fixed point number with 1 meaning 1.2 and 255 meaning 1.8. protected static final int BIGRAM_MAX_FREQUENCY = 255; private Context mContext; - private char[] mWordBuilder = new char[MAX_WORD_LENGTH]; + private char[] mWordBuilder = new char[BinaryDictionary.MAX_WORD_LENGTH]; private int mDicTypeId; private int mMaxDepth; private int mInputLength; @@ -113,7 +108,7 @@ public class ExpandableDictionary extends Dictionary { public ExpandableDictionary(Context context, int dicTypeId) { mContext = context; clearDictionary(); - mCodes = new int[MAX_WORD_LENGTH][]; + mCodes = new int[BinaryDictionary.MAX_WORD_LENGTH][]; mDicTypeId = dicTypeId; } @@ -151,10 +146,13 @@ public class ExpandableDictionary extends Dictionary { } public int getMaxWordLength() { - return MAX_WORD_LENGTH; + return BinaryDictionary.MAX_WORD_LENGTH; } public void addWord(String word, int frequency) { + if (word.length() >= BinaryDictionary.MAX_WORD_LENGTH) { + return; + } addWordRec(mRoots, word, 0, frequency, null); } @@ -201,6 +199,9 @@ public class ExpandableDictionary extends Dictionary { // Currently updating contacts, don't return any results. if (mUpdatingDictionary) return; } + if (codes.size() >= BinaryDictionary.MAX_WORD_LENGTH) { + return; + } getWordsInner(codes, callback, proximityInfo); } @@ -488,7 +489,7 @@ public class ExpandableDictionary extends Dictionary { } // Local to reverseLookUp, but do not allocate each time. - private final char[] mLookedUpString = new char[MAX_WORD_LENGTH]; + private final char[] mLookedUpString = new char[BinaryDictionary.MAX_WORD_LENGTH]; /** * reverseLookUp retrieves the full word given a list of terminal nodes and adds those words @@ -502,15 +503,15 @@ public class ExpandableDictionary extends Dictionary { for (NextWord nextWord : terminalNodes) { node = nextWord.mWord; freq = nextWord.getFrequency(); - int index = MAX_WORD_LENGTH; + int index = BinaryDictionary.MAX_WORD_LENGTH; do { --index; mLookedUpString[index] = node.mCode; node = node.mParent; } while (node != null); - callback.addWord(mLookedUpString, index, MAX_WORD_LENGTH - index, freq, mDicTypeId, - Dictionary.BIGRAM); + callback.addWord(mLookedUpString, index, BinaryDictionary.MAX_WORD_LENGTH - index, + freq, mDicTypeId, Dictionary.BIGRAM); } } diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java index db2cdf967..62525c205 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java @@ -247,8 +247,8 @@ public class UserHistoryDictionary extends ExpandableDictionary { // to recursive lookup if (null == word1) { super.addWord(word2, frequency); - } else if (word1.length() < MAX_WORD_LENGTH - && word2.length() < MAX_WORD_LENGTH) { + } else if (word1.length() < BinaryDictionary.MAX_WORD_LENGTH + && word2.length() < BinaryDictionary.MAX_WORD_LENGTH) { super.setBigram(word1, word2, frequency); } cursor.moveToNext(); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 29a7e4816..7c3d3c2a0 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -104,7 +104,11 @@ public class WordComposer { return size() > 0; } + // TODO: make sure that the index should not exceed MAX_WORD_LENGTH public int getCodeAt(int index) { + if (index >= BinaryDictionary.MAX_WORD_LENGTH) { + return -1; + } return mPrimaryKeyCodes[index]; } @@ -153,8 +157,8 @@ public class WordComposer { final int newIndex = size(); mTypedWord.appendCodePoint(primaryCode); refreshSize(); - mPrimaryKeyCodes[newIndex] = codes[0]; if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { + mPrimaryKeyCodes[newIndex] = codes[0]; mXCoordinates[newIndex] = keyX; mYCoordinates[newIndex] = keyY; } -- cgit v1.2.3-83-g751a From 67094f5bdece00994f70c6f1fa9a6ff7b8f3c3c1 Mon Sep 17 00:00:00 2001 From: satok Date: Wed, 28 Mar 2012 16:30:52 +0900 Subject: Do not re-calculate primary code in WordComposer Bug: 4343280 Test: Ib43c0f1d1a19d067ea0 Change-Id: I3393a6099cb7fb824994f4656ccfef884f9c6bc4 --- java/src/com/android/inputmethod/latin/WordComposer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 7c3d3c2a0..ac9304548 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -139,9 +139,8 @@ public class WordComposer { keyX = x; keyY = y; } else { - final Key key = keyDetector.detectHitKey(x, y); // TODO: Pass an integer instead of an integer array - codes = new int[] { key != null ? key.mCode : NOT_A_CODE }; + codes = new int[] { primaryCode }; keyX = keyDetector.getTouchX(x); keyY = keyDetector.getTouchY(y); } @@ -158,7 +157,8 @@ public class WordComposer { mTypedWord.appendCodePoint(primaryCode); refreshSize(); if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { - mPrimaryKeyCodes[newIndex] = codes[0]; + mPrimaryKeyCodes[newIndex] = primaryCode >= Keyboard.CODE_SPACE + ? Character.toLowerCase(primaryCode) : primaryCode; mXCoordinates[newIndex] = keyX; mYCoordinates[newIndex] = keyY; } -- cgit v1.2.3-83-g751a From 6ba8de2a608dfe4865b0b59a753f2d2abbedeeff Mon Sep 17 00:00:00 2001 From: satok Date: Wed, 28 Mar 2012 18:21:04 +0900 Subject: Good bye the proximity logic in Java code Bug: 4343280 Change-Id: I82f7d08703647a3492ce6e2d3b741146df58927e --- .../com/android/inputmethod/latin/BinaryDictionary.java | 14 +++++--------- java/src/com/android/inputmethod/latin/WordComposer.java | 14 ++++---------- .../com_android_inputmethod_latin_BinaryDictionary.cpp | 15 ++++++--------- native/src/bigram_dictionary.cpp | 7 +++---- native/src/bigram_dictionary.h | 8 ++++---- native/src/dictionary.cpp | 6 +++--- native/src/dictionary.h | 7 +++---- native/src/unigram_dictionary.cpp | 2 +- native/src/unigram_dictionary.h | 2 +- 9 files changed, 30 insertions(+), 45 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 9909638d4..c43683f2d 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -40,14 +40,13 @@ public class BinaryDictionary extends Dictionary { public static final int MAX_WORDS = 18; private static final String TAG = "BinaryDictionary"; - private static final int MAX_PROXIMITY_CHARS_SIZE = ProximityInfo.MAX_PROXIMITY_CHARS_SIZE; private static final int MAX_BIGRAMS = 60; private static final int TYPED_LETTER_MULTIPLIER = 2; private int mDicTypeId; private long mNativeDict; - private final int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_PROXIMITY_CHARS_SIZE]; + private final int[] mInputCodes = new int[MAX_WORD_LENGTH]; private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS]; private final char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS]; private final int[] mScores = new int[MAX_WORDS]; @@ -111,8 +110,7 @@ public class BinaryDictionary extends Dictionary { } private native long openNative(String sourceDir, long dictOffset, long dictSize, - int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength, - int maxWords, int maxAlternatives); + int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength, int maxWords); private native void closeNative(long dict); private native boolean isValidWordNative(long dict, char[] word, int wordLength); private native int getSuggestionsNative(long dict, long proximityInfo, int[] xCoordinates, @@ -120,7 +118,7 @@ public class BinaryDictionary extends Dictionary { int[] scores); private native int getBigramsNative(long dict, char[] prevWord, int prevWordLength, int[] inputCodes, int inputCodesLength, char[] outputChars, int[] scores, - int maxWordLength, int maxBigrams, int maxAlternatives); + int maxWordLength, int maxBigrams); private static native double calcNormalizedScoreNative( char[] before, int beforeLength, char[] after, int afterLength, int score); private static native int editDistanceNative( @@ -128,8 +126,7 @@ public class BinaryDictionary extends Dictionary { private final void loadDictionary(String path, long startOffset, long length) { mNativeDict = openNative(path, startOffset, length, - TYPED_LETTER_MULTIPLIER, FULL_WORD_SCORE_MULTIPLIER, - MAX_WORD_LENGTH, MAX_WORDS, MAX_PROXIMITY_CHARS_SIZE); + TYPED_LETTER_MULTIPLIER, FULL_WORD_SCORE_MULTIPLIER, MAX_WORD_LENGTH, MAX_WORDS); } @Override @@ -148,8 +145,7 @@ public class BinaryDictionary extends Dictionary { } int count = getBigramsNative(mNativeDict, chars, chars.length, mInputCodes, codesSize, - mOutputChars_bigrams, mBigramScores, MAX_WORD_LENGTH, MAX_BIGRAMS, - MAX_PROXIMITY_CHARS_SIZE); + mOutputChars_bigrams, mBigramScores, MAX_WORD_LENGTH, MAX_BIGRAMS); if (count > MAX_BIGRAMS) { count = MAX_BIGRAMS; } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index ac9304548..555a49ef4 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -127,7 +127,6 @@ public class WordComposer { // TODO: remove input keyDetector public void add(int primaryCode, int x, int y, KeyDetector keyDetector) { - final int[] codes; final int keyX; final int keyY; if (null == keyDetector @@ -135,16 +134,13 @@ public class WordComposer { || y == KeyboardActionListener.SUGGESTION_STRIP_COORDINATE || x == KeyboardActionListener.NOT_A_TOUCH_COORDINATE || y == KeyboardActionListener.NOT_A_TOUCH_COORDINATE) { - codes = new int[] { primaryCode }; keyX = x; keyY = y; } else { - // TODO: Pass an integer instead of an integer array - codes = new int[] { primaryCode }; keyX = keyDetector.getTouchX(x); keyY = keyDetector.getTouchY(y); } - add(primaryCode, codes, keyX, keyY); + add(primaryCode, keyX, keyY); } /** @@ -152,7 +148,7 @@ public class WordComposer { * the array containing unicode for adjacent keys, sorted by reducing probability/proximity. * @param codes the array of unicode values */ - private void add(int primaryCode, int[] codes, int keyX, int keyY) { + private void add(int primaryCode, int keyX, int keyY) { final int newIndex = size(); mTypedWord.appendCodePoint(primaryCode); refreshSize(); @@ -181,13 +177,11 @@ public class WordComposer { if (key.mCode == codePoint) { final int x = key.mX + key.mWidth / 2; final int y = key.mY + key.mHeight / 2; - // TODO: Pass an integer instead of an integer array - add(codePoint, new int[] { key.mCode }, x, y); + add(codePoint, x, y); return; } } - add(codePoint, new int[] { codePoint }, - WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); + add(codePoint, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); } /** diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index f2878eea5..20e44c2b0 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -45,8 +45,7 @@ void releaseDictBuf(void* dictBuf, const size_t length, int fd); static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, jstring sourceDir, jlong dictOffset, jlong dictSize, - jint typedLetterMultiplier, jint fullWordMultiplier, jint maxWordLength, jint maxWords, - jint maxAlternatives) { + jint typedLetterMultiplier, jint fullWordMultiplier, jint maxWordLength, jint maxWords) { PROF_OPEN; PROF_START(66); const char *sourceDirChars = env->GetStringUTFChars(sourceDir, 0); @@ -119,7 +118,7 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, #endif // USE_MMAP_FOR_DICTIONARY } else { dictionary = new Dictionary(dictBuf, dictSize, fd, adjust, typedLetterMultiplier, - fullWordMultiplier, maxWordLength, maxWords, maxAlternatives); + fullWordMultiplier, maxWordLength, maxWords); } PROF_END(66); PROF_CLOSE; @@ -155,8 +154,7 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, static int latinime_BinaryDictionary_getBigrams(JNIEnv *env, jobject object, jlong dict, jcharArray prevWordArray, jint prevWordLength, jintArray inputArray, jint inputArraySize, - jcharArray outputArray, jintArray frequencyArray, jint maxWordLength, jint maxBigrams, - jint maxAlternatives) { + jcharArray outputArray, jintArray frequencyArray, jint maxWordLength, jint maxBigrams) { Dictionary *dictionary = (Dictionary*)dict; if (!dictionary) return 0; @@ -166,8 +164,7 @@ static int latinime_BinaryDictionary_getBigrams(JNIEnv *env, jobject object, jlo int *frequencies = env->GetIntArrayElements(frequencyArray, 0); int count = dictionary->getBigrams((unsigned short*) prevWord, prevWordLength, inputCodes, - inputArraySize, (unsigned short*) outputChars, frequencies, maxWordLength, maxBigrams, - maxAlternatives); + inputArraySize, (unsigned short*) outputChars, frequencies, maxWordLength, maxBigrams); env->ReleaseCharArrayElements(prevWordArray, prevWord, JNI_ABORT); env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT); @@ -242,11 +239,11 @@ void releaseDictBuf(void* dictBuf, const size_t length, int fd) { } static JNINativeMethod sMethods[] = { - {"openNative", "(Ljava/lang/String;JJIIIII)J", (void*)latinime_BinaryDictionary_open}, + {"openNative", "(Ljava/lang/String;JJIIII)J", (void*)latinime_BinaryDictionary_open}, {"closeNative", "(J)V", (void*)latinime_BinaryDictionary_close}, {"getSuggestionsNative", "(JJ[I[I[III[C[I)I", (void*)latinime_BinaryDictionary_getSuggestions}, {"isValidWordNative", "(J[CI)Z", (void*)latinime_BinaryDictionary_isValidWord}, - {"getBigramsNative", "(J[CI[II[C[IIII)I", (void*)latinime_BinaryDictionary_getBigrams}, + {"getBigramsNative", "(J[CI[II[C[III)I", (void*)latinime_BinaryDictionary_getBigrams}, {"calcNormalizedScoreNative", "([CI[CII)D", (void*)latinime_BinaryDictionary_calcNormalizedScore}, {"editDistanceNative", "([CI[CI)I", (void*)latinime_BinaryDictionary_editDistance} diff --git a/native/src/bigram_dictionary.cpp b/native/src/bigram_dictionary.cpp index 3704c47e6..f7a3d3e60 100644 --- a/native/src/bigram_dictionary.cpp +++ b/native/src/bigram_dictionary.cpp @@ -26,10 +26,10 @@ namespace latinime { BigramDictionary::BigramDictionary(const unsigned char *dict, int maxWordLength, - int maxAlternatives, const bool isLatestDictVersion, const bool hasBigram, + const bool isLatestDictVersion, const bool hasBigram, Dictionary *parentDictionary) : DICT(dict), MAX_WORD_LENGTH(maxWordLength), - MAX_ALTERNATIVES(maxAlternatives), IS_LATEST_DICT_VERSION(isLatestDictVersion), + IS_LATEST_DICT_VERSION(isLatestDictVersion), HAS_BIGRAM(hasBigram), mParentDictionary(parentDictionary) { if (DEBUG_DICT) { AKLOGI("BigramDictionary - constructor"); @@ -92,7 +92,6 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ * bigramFreq: an array to output frequencies. * maxWordLength: the maximum size of a word. * maxBigrams: the maximum number of bigrams fitting in the bigramChars array. - * maxAlteratives: unused. * This method returns the number of bigrams this word has, for backward compatibility. * Note: this is not the number of bigrams output in the array, which is the number of * bigrams this word has WHOSE first letter also matches the letter the user typed. @@ -103,7 +102,7 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ */ int BigramDictionary::getBigrams(unsigned short *prevWord, int prevWordLength, int *codes, int codesSize, unsigned short *bigramChars, int *bigramFreq, int maxWordLength, - int maxBigrams, int maxAlternatives) { + int maxBigrams) { // TODO: remove unused arguments, and refrain from storing stuff in members of this class // TODO: have "in" arguments before "out" ones, and make out args explicit in the name mBigramFreq = bigramFreq; diff --git a/native/src/bigram_dictionary.h b/native/src/bigram_dictionary.h index 585a1866a..8132fbc59 100644 --- a/native/src/bigram_dictionary.h +++ b/native/src/bigram_dictionary.h @@ -22,11 +22,10 @@ namespace latinime { class Dictionary; class BigramDictionary { public: - BigramDictionary(const unsigned char *dict, int maxWordLength, int maxAlternatives, + BigramDictionary(const unsigned char *dict, int maxWordLength, const bool isLatestDictVersion, const bool hasBigram, Dictionary *parentDictionary); int getBigrams(unsigned short *word, int length, int *codes, int codesSize, - unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams, - int maxAlternatives); + unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams); ~BigramDictionary(); private: bool addWordBigram(unsigned short *word, int length, int frequency); @@ -39,7 +38,8 @@ class BigramDictionary { const unsigned char *DICT; const int MAX_WORD_LENGTH; - const int MAX_ALTERNATIVES; + // TODO: Re-implement proximity correction for bigram correction + static const int MAX_ALTERNATIVES = 1; const bool IS_LATEST_DICT_VERSION; const bool HAS_BIGRAM; diff --git a/native/src/dictionary.cpp b/native/src/dictionary.cpp index 8e252f730..981a983ee 100644 --- a/native/src/dictionary.cpp +++ b/native/src/dictionary.cpp @@ -27,7 +27,7 @@ namespace latinime { // TODO: Change the type of all keyCodes to uint32_t Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, int typedLetterMultiplier, int fullWordMultiplier, - int maxWordLength, int maxWords, int maxAlternatives) + int maxWordLength, int maxWords) : mDict((unsigned char*) dict), mDictSize(dictSize), mMmapFd(mmapFd), mDictBufAdjust(dictBufAdjust), // Checks whether it has the latest dictionary or the old dictionary @@ -44,8 +44,8 @@ Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, maxWords, SUB_QUEUE_MAX_WORDS, maxWordLength); const unsigned int headerSize = BinaryFormat::getHeaderSize(mDict); mUnigramDictionary = new UnigramDictionary(mDict + headerSize, typedLetterMultiplier, - fullWordMultiplier, maxWordLength, maxWords, maxAlternatives, IS_LATEST_DICT_VERSION); - mBigramDictionary = new BigramDictionary(mDict + headerSize, maxWordLength, maxAlternatives, + fullWordMultiplier, maxWordLength, maxWords, IS_LATEST_DICT_VERSION); + mBigramDictionary = new BigramDictionary(mDict + headerSize, maxWordLength, IS_LATEST_DICT_VERSION, true /* hasBigram */, this); } diff --git a/native/src/dictionary.h b/native/src/dictionary.h index 90d7148d5..139d3f0d7 100644 --- a/native/src/dictionary.h +++ b/native/src/dictionary.h @@ -30,7 +30,7 @@ namespace latinime { class Dictionary { public: Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, int typedLetterMultipler, - int fullWordMultiplier, int maxWordLength, int maxWords, int maxAlternatives); + int fullWordMultiplier, int maxWordLength, int maxWords); int getSuggestions(ProximityInfo *proximityInfo, int *xcoordinates, int *ycoordinates, int *codes, int codesSize, int flags, unsigned short *outWords, int *frequencies) { @@ -41,10 +41,9 @@ class Dictionary { // TODO: Call mBigramDictionary instead of mUnigramDictionary int getBigrams(unsigned short *word, int length, int *codes, int codesSize, - unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams, - int maxAlternatives) { + unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams) { return mBigramDictionary->getBigrams(word, length, codes, codesSize, outWords, frequencies, - maxWordLength, maxBigrams, maxAlternatives); + maxWordLength, maxBigrams); } bool isValidWord(unsigned short *word, int length); diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp index d21413d8b..ed4c066f3 100644 --- a/native/src/unigram_dictionary.cpp +++ b/native/src/unigram_dictionary.cpp @@ -40,7 +40,7 @@ const UnigramDictionary::digraph_t UnigramDictionary::FRENCH_LIGATURES_DIGRAPHS[ // TODO: check the header UnigramDictionary::UnigramDictionary(const uint8_t* const streamStart, int typedLetterMultiplier, - int fullWordMultiplier, int maxWordLength, int maxWords, int maxProximityChars, + int fullWordMultiplier, int maxWordLength, int maxWords, const bool isLatestDictVersion) : DICT_ROOT(streamStart), MAX_WORD_LENGTH(maxWordLength), MAX_WORDS(maxWords), IS_LATEST_DICT_VERSION(isLatestDictVersion), diff --git a/native/src/unigram_dictionary.h b/native/src/unigram_dictionary.h index 86bda77cb..c8f15566c 100644 --- a/native/src/unigram_dictionary.h +++ b/native/src/unigram_dictionary.h @@ -74,7 +74,7 @@ class UnigramDictionary { static const int MAX_ERRORS_FOR_TWO_WORDS = 1; UnigramDictionary(const uint8_t* const streamStart, int typedLetterMultipler, - int fullWordMultiplier, int maxWordLength, int maxWords, int maxProximityChars, + int fullWordMultiplier, int maxWordLength, int maxWords, const bool isLatestDictVersion); bool isValidWord(const uint16_t* const inWord, const int length) const; int getBigramPosition(int pos, unsigned short *word, int offset, int length) const; -- cgit v1.2.3-83-g751a From c61cd79229b1871d0f603a23389695d7f7751e66 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Thu, 29 Mar 2012 15:07:53 +0900 Subject: Fix some obvious compiler warnings Change-Id: I10a634f7492b45d5a72345f14d36cf341946387d --- .../inputmethod/compat/InputMethodManagerCompatWrapper.java | 9 +++++---- .../com/android/inputmethod/compat/SuggestionSpanUtils.java | 2 +- .../inputmethod/compat/SuggestionsInfoCompatUtils.java | 4 ++-- .../android/inputmethod/keyboard/KeyboardActionListener.java | 12 ++++++------ .../inputmethod/latin/BinaryDictionaryFileDumper.java | 2 +- java/src/com/android/inputmethod/latin/Dictionary.java | 2 +- java/src/com/android/inputmethod/latin/LatinIME.java | 1 - java/src/com/android/inputmethod/latin/LatinImeLogger.java | 1 - java/src/com/android/inputmethod/latin/ResearchLogger.java | 2 +- java/src/com/android/inputmethod/latin/WordComposer.java | 4 +--- 10 files changed, 18 insertions(+), 21 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java index bf5f20158..a4ff8238c 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java @@ -267,12 +267,13 @@ public class InputMethodManagerCompatWrapper { final InputMethodSubtypeCompatWrapper currentIms = getCurrentInputMethodSubtype(); final List imiList = getEnabledInputMethodList(); imiList.remove(myImi); + final PackageManager pm = mPackageManager; Collections.sort(imiList, new Comparator() { @Override public int compare(InputMethodInfoCompatWrapper imi1, InputMethodInfoCompatWrapper imi2) { - final CharSequence imiId1 = imi1.loadLabel(mPackageManager) + "/" + imi1.getId(); - final CharSequence imiId2 = imi2.loadLabel(mPackageManager) + "/" + imi2.getId(); + final CharSequence imiId1 = imi1.loadLabel(pm) + "/" + imi1.getId(); + final CharSequence imiId2 = imi2.loadLabel(pm) + "/" + imi2.getId(); return imiId1.toString().compareTo(imiId2.toString()); } }); @@ -302,6 +303,7 @@ public class InputMethodManagerCompatWrapper { index++; } + final InputMethodServiceCompatWrapper service = mService; final OnClickListener buttonListener = new OnClickListener() { @Override public void onClick(DialogInterface di, int whichButton) { @@ -309,10 +311,9 @@ public class InputMethodManagerCompatWrapper { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_CLEAR_TOP); - mService.startActivity(intent); + service.startActivity(intent); } }; - final InputMethodServiceCompatWrapper service = mService; final IBinder token = service.getWindow().getWindow().getAttributes().token; final OnClickListener selectionListener = new OnClickListener() { @Override diff --git a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java index a9e48404a..df55aee94 100644 --- a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java +++ b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java @@ -129,7 +129,7 @@ public class SuggestionSpanUtils { // TODO: Share the implementation for checking typed word validity between the IME // and the spell checker. final int flag = (sameAsTyped && !suggestedWords.mTypedWordValid) - ? ((int)OBJ_FLAG_EASY_CORRECT | (int)OBJ_FLAG_MISSPELLED) + ? (OBJ_FLAG_EASY_CORRECT | OBJ_FLAG_MISSPELLED) : 0; final Object[] args = diff --git a/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java b/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java index 6a0d4dd9e..723ec2862 100644 --- a/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java @@ -24,7 +24,7 @@ public class SuggestionsInfoCompatUtils { private static final Field FIELD_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = CompatUtils.getField( SuggestionsInfo.class, "RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS"); private static final Integer OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = (Integer) CompatUtils - .getFieldValue(null, null, FIELD_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS);; + .getFieldValue(null, null, FIELD_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS); private static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS != null ? OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS : 0; @@ -34,7 +34,7 @@ public class SuggestionsInfoCompatUtils { /** * Returns the flag value of the attributes of the suggestions that can be obtained by - * {@link #getSuggestionsAttributes}: this tells that the text service thinks + * {@link SuggestionsInfo#getSuggestionsAttributes()}: this tells that the text service thinks * the result suggestions include highly recommended ones. */ public static int getValueOf_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS() { diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java index 16b4eafc9..275aacf36 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java @@ -42,13 +42,13 @@ public interface KeyboardActionListener { * * @param primaryCode this is the code of the key that was pressed * @param x x-coordinate pixel of touched event. If {@link #onCodeInput} is not called by - * {@link PointerTracker#onTouchEvent} or so, the value should be - * {@link #NOT_A_TOUCH_COORDINATE}. If it's called on insertion from the suggestion - * strip, it should be {@link #SUGGESTION_STRIP_COORDINATE}. + * {@link PointerTracker} or so, the value should be {@link #NOT_A_TOUCH_COORDINATE}. + * If it's called on insertion from the suggestion strip, it should be + * {@link #SUGGESTION_STRIP_COORDINATE}. * @param y y-coordinate pixel of touched event. If {@link #onCodeInput} is not called by - * {@link PointerTracker#onTouchEvent} or so, the value should be - * {@link #NOT_A_TOUCH_COORDINATE}. If it's called on insertion from the suggestion - * strip, it should be {@link #SUGGESTION_STRIP_COORDINATE}. + * {@link PointerTracker} or so, the value should be {@link #NOT_A_TOUCH_COORDINATE}. + * If it's called on insertion from the suggestion strip, it should be + * {@link #SUGGESTION_STRIP_COORDINATE}. */ public void onCodeInput(int primaryCode, int x, int y); diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java index 8ec440500..311d3dc9d 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java @@ -252,7 +252,7 @@ public class BinaryDictionaryFileDumper { * also apply. * * @param input the stream to be copied. - * @param outputFile an outputstream to copy the data to. + * @param output an output stream to copy the data to. */ private static void checkMagicAndCopyFileTo(final BufferedInputStream input, final FileOutputStream output) throws FileNotFoundException, IOException { diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index 79bf33850..9d26a2343 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -38,7 +38,7 @@ public abstract class Dictionary { /** * Interface to be implemented by classes requesting words to be fetched from the dictionary. - * @see #getWords(WordComposer, WordCallback) + * @see #getWords(WordComposer, WordCallback, ProximityInfo) */ public interface WordCallback { /** diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 86c153958..9f9f6b87d 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -68,7 +68,6 @@ import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.keyboard.LatinKeyboardView; -import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils; import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.latin.suggestions.SuggestionsView; diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java index 732efadd6..dc0868e7c 100644 --- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java +++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java @@ -16,7 +16,6 @@ package com.android.inputmethod.latin; -import android.content.Context; import android.content.SharedPreferences; import android.view.inputmethod.EditorInfo; diff --git a/java/src/com/android/inputmethod/latin/ResearchLogger.java b/java/src/com/android/inputmethod/latin/ResearchLogger.java index 0694ffe77..7f3be8584 100644 --- a/java/src/com/android/inputmethod/latin/ResearchLogger.java +++ b/java/src/com/android/inputmethod/latin/ResearchLogger.java @@ -178,8 +178,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } if (prefs != null) { sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false); + prefs.registerOnSharedPreferenceChangeListener(this); } - prefs.registerOnSharedPreferenceChangeListener(this); } /** diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 555a49ef4..bd8532ebd 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -144,9 +144,7 @@ public class WordComposer { } /** - * Add a new keystroke, with codes[0] containing the pressed key's unicode and the rest of - * the array containing unicode for adjacent keys, sorted by reducing probability/proximity. - * @param codes the array of unicode values + * Add a new keystroke, with the pressed key's code point with the touch point coordinates. */ private void add(int primaryCode, int keyX, int keyY) { final int newIndex = size(); -- cgit v1.2.3-83-g751a From 4b5b46bb66bf74ef5edd65c55e186b02f3c56e5d Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 26 Apr 2012 18:01:13 +0900 Subject: Don't autocorrect after suggestion resuming Bug: 6105732 Change-Id: I92e7a9c6d6eb648f747c3b396d7993479fd8478a --- java/src/com/android/inputmethod/latin/Suggest.java | 1 + java/src/com/android/inputmethod/latin/WordComposer.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 7cbee4f71..112bde6a3 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -385,6 +385,7 @@ public class Suggest implements Dictionary.WordCallback { } // Don't auto-correct words with multiple capital letter autoCorrectionAvailable &= !wordComposer.isMostlyCaps(); + autoCorrectionAvailable &= !wordComposer.isResumed(); if (allowsToBeAutoCorrected && suggestionsList.size() > 1 && mAutoCorrectionThreshold > 0 && Suggest.shouldBlockAutoCorrectionBySafetyNet(typedWord, suggestionsList.get(1).mWord)) { diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index bd8532ebd..e27a546c5 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -38,6 +38,7 @@ public class WordComposer { private int[] mYCoordinates; private StringBuilder mTypedWord; private CharSequence mAutoCorrection; + private boolean mIsResumed; // Cache these values for performance private int mCapsCount; @@ -57,6 +58,7 @@ public class WordComposer { mYCoordinates = new int[N]; mAutoCorrection = null; mTrailingSingleQuotesCount = 0; + mIsResumed = false; refreshSize(); } @@ -73,6 +75,7 @@ public class WordComposer { mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount; + mIsResumed = source.mIsResumed; refreshSize(); } @@ -85,6 +88,7 @@ public class WordComposer { mCapsCount = 0; mIsFirstCharCapitalized = false; mTrailingSingleQuotesCount = 0; + mIsResumed = false; refreshSize(); } @@ -193,6 +197,7 @@ public class WordComposer { int codePoint = Character.codePointAt(word, i); addKeyInfo(codePoint, keyboard); } + mIsResumed = true; } /** @@ -299,6 +304,13 @@ public class WordComposer { return mAutoCorrection; } + /** + * @return whether we started composing this word by resuming suggestion on an existing string + */ + public boolean isResumed() { + return mIsResumed; + } + // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. public LastComposedWord commitWord(final int type, final String committedWord, final int separatorCode) { @@ -320,6 +332,7 @@ public class WordComposer { mTypedWord.setLength(0); refreshSize(); mAutoCorrection = null; + mIsResumed = false; return lastComposedWord; } @@ -331,5 +344,6 @@ public class WordComposer { mTypedWord.append(lastComposedWord.mTypedWord); refreshSize(); mAutoCorrection = null; // This will be filled by the next call to updateSuggestion. + mIsResumed = true; } } -- cgit v1.2.3-83-g751a From c54d558e2e70bdfb2c1078cae7b88440d421dc67 Mon Sep 17 00:00:00 2001 From: satok Date: Thu, 24 May 2012 12:11:02 +0900 Subject: Cancel adding user history bigram when autocorrection is cancelled Bug: 6465474 Change-Id: Ifbfe0ddc2ce5fab070939ede3db7bf03a8535a45 --- .../inputmethod/latin/ExpandableDictionary.java | 338 +++++++++++---------- .../inputmethod/latin/LastComposedWord.java | 6 +- .../com/android/inputmethod/latin/LatinIME.java | 41 +-- .../inputmethod/latin/UserHistoryDictionary.java | 9 + .../android/inputmethod/latin/WordComposer.java | 5 +- 5 files changed, 219 insertions(+), 180 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 7a740b3f1..dd9c57e0c 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -261,6 +261,28 @@ public class ExpandableDictionary extends Dictionary { return (node == null) ? false : !node.mShortcutOnly; } + protected boolean removeBigram(String word1, String word2) { + // Refer to addOrSetBigram() about word1.toLowerCase() + final Node firstWord = searchWord(mRoots, word1.toLowerCase(), 0, null); + final Node secondWord = searchWord(mRoots, word2, 0, null); + LinkedList bigram = firstWord.mNGrams; + NextWord bigramNode = null; + if (bigram == null || bigram.size() == 0) { + return false; + } else { + for (NextWord nw : bigram) { + if (nw.mWord == secondWord) { + bigramNode = nw; + break; + } + } + } + if (bigramNode == null) { + return false; + } + return bigram.remove(bigramNode); + } + /** * Returns the word's frequency or -1 if not found */ @@ -639,167 +661,167 @@ public class ExpandableDictionary extends Dictionary { * is combined. */ 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, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, - 0x0020, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, - 0x0020, 0x00a9, 0x0061, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0020, - 0x00b0, 0x00b1, 0x0032, 0x0033, 0x0020, 0x03bc, 0x00b6, 0x00b7, - 0x0020, 0x0031, 0x006f, 0x00bb, 0x0031, 0x0031, 0x0033, 0x00bf, - 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x00c6, 0x0043, - 0x0045, 0x0045, 0x0045, 0x0045, 0x0049, 0x0049, 0x0049, 0x0049, - 0x00d0, 0x004e, 0x004f, 0x004f, 0x004f, 0x004f, 0x004f, 0x00d7, + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x0020, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, + 0x0020, 0x00a9, 0x0061, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0020, + 0x00b0, 0x00b1, 0x0032, 0x0033, 0x0020, 0x03bc, 0x00b6, 0x00b7, + 0x0020, 0x0031, 0x006f, 0x00bb, 0x0031, 0x0031, 0x0033, 0x00bf, + 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x00c6, 0x0043, + 0x0045, 0x0045, 0x0045, 0x0045, 0x0049, 0x0049, 0x0049, 0x0049, + 0x00d0, 0x004e, 0x004f, 0x004f, 0x004f, 0x004f, 0x004f, 0x00d7, 0x004f, 0x0055, 0x0055, 0x0055, 0x0055, 0x0059, 0x00de, 0x0073, // Manually changed d8 to 4f // Manually changed df to 73 - 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x00e6, 0x0063, - 0x0065, 0x0065, 0x0065, 0x0065, 0x0069, 0x0069, 0x0069, 0x0069, - 0x00f0, 0x006e, 0x006f, 0x006f, 0x006f, 0x006f, 0x006f, 0x00f7, + 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x00e6, 0x0063, + 0x0065, 0x0065, 0x0065, 0x0065, 0x0069, 0x0069, 0x0069, 0x0069, + 0x00f0, 0x006e, 0x006f, 0x006f, 0x006f, 0x006f, 0x006f, 0x00f7, 0x006f, 0x0075, 0x0075, 0x0075, 0x0075, 0x0079, 0x00fe, 0x0079, // Manually changed f8 to 6f - 0x0041, 0x0061, 0x0041, 0x0061, 0x0041, 0x0061, 0x0043, 0x0063, - 0x0043, 0x0063, 0x0043, 0x0063, 0x0043, 0x0063, 0x0044, 0x0064, - 0x0110, 0x0111, 0x0045, 0x0065, 0x0045, 0x0065, 0x0045, 0x0065, - 0x0045, 0x0065, 0x0045, 0x0065, 0x0047, 0x0067, 0x0047, 0x0067, - 0x0047, 0x0067, 0x0047, 0x0067, 0x0048, 0x0068, 0x0126, 0x0127, - 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, - 0x0049, 0x0131, 0x0049, 0x0069, 0x004a, 0x006a, 0x004b, 0x006b, - 0x0138, 0x004c, 0x006c, 0x004c, 0x006c, 0x004c, 0x006c, 0x004c, - 0x006c, 0x0141, 0x0142, 0x004e, 0x006e, 0x004e, 0x006e, 0x004e, - 0x006e, 0x02bc, 0x014a, 0x014b, 0x004f, 0x006f, 0x004f, 0x006f, - 0x004f, 0x006f, 0x0152, 0x0153, 0x0052, 0x0072, 0x0052, 0x0072, - 0x0052, 0x0072, 0x0053, 0x0073, 0x0053, 0x0073, 0x0053, 0x0073, - 0x0053, 0x0073, 0x0054, 0x0074, 0x0054, 0x0074, 0x0166, 0x0167, - 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, - 0x0055, 0x0075, 0x0055, 0x0075, 0x0057, 0x0077, 0x0059, 0x0079, - 0x0059, 0x005a, 0x007a, 0x005a, 0x007a, 0x005a, 0x007a, 0x0073, - 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185, 0x0186, 0x0187, - 0x0188, 0x0189, 0x018a, 0x018b, 0x018c, 0x018d, 0x018e, 0x018f, - 0x0190, 0x0191, 0x0192, 0x0193, 0x0194, 0x0195, 0x0196, 0x0197, - 0x0198, 0x0199, 0x019a, 0x019b, 0x019c, 0x019d, 0x019e, 0x019f, - 0x004f, 0x006f, 0x01a2, 0x01a3, 0x01a4, 0x01a5, 0x01a6, 0x01a7, - 0x01a8, 0x01a9, 0x01aa, 0x01ab, 0x01ac, 0x01ad, 0x01ae, 0x0055, - 0x0075, 0x01b1, 0x01b2, 0x01b3, 0x01b4, 0x01b5, 0x01b6, 0x01b7, - 0x01b8, 0x01b9, 0x01ba, 0x01bb, 0x01bc, 0x01bd, 0x01be, 0x01bf, - 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x0044, 0x0044, 0x0064, 0x004c, - 0x004c, 0x006c, 0x004e, 0x004e, 0x006e, 0x0041, 0x0061, 0x0049, - 0x0069, 0x004f, 0x006f, 0x0055, 0x0075, 0x00dc, 0x00fc, 0x00dc, - 0x00fc, 0x00dc, 0x00fc, 0x00dc, 0x00fc, 0x01dd, 0x00c4, 0x00e4, - 0x0226, 0x0227, 0x00c6, 0x00e6, 0x01e4, 0x01e5, 0x0047, 0x0067, - 0x004b, 0x006b, 0x004f, 0x006f, 0x01ea, 0x01eb, 0x01b7, 0x0292, - 0x006a, 0x0044, 0x0044, 0x0064, 0x0047, 0x0067, 0x01f6, 0x01f7, - 0x004e, 0x006e, 0x00c5, 0x00e5, 0x00c6, 0x00e6, 0x00d8, 0x00f8, - 0x0041, 0x0061, 0x0041, 0x0061, 0x0045, 0x0065, 0x0045, 0x0065, - 0x0049, 0x0069, 0x0049, 0x0069, 0x004f, 0x006f, 0x004f, 0x006f, - 0x0052, 0x0072, 0x0052, 0x0072, 0x0055, 0x0075, 0x0055, 0x0075, - 0x0053, 0x0073, 0x0054, 0x0074, 0x021c, 0x021d, 0x0048, 0x0068, - 0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0225, 0x0041, 0x0061, - 0x0045, 0x0065, 0x00d6, 0x00f6, 0x00d5, 0x00f5, 0x004f, 0x006f, - 0x022e, 0x022f, 0x0059, 0x0079, 0x0234, 0x0235, 0x0236, 0x0237, - 0x0238, 0x0239, 0x023a, 0x023b, 0x023c, 0x023d, 0x023e, 0x023f, - 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, - 0x0248, 0x0249, 0x024a, 0x024b, 0x024c, 0x024d, 0x024e, 0x024f, - 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257, - 0x0258, 0x0259, 0x025a, 0x025b, 0x025c, 0x025d, 0x025e, 0x025f, - 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267, - 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f, - 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, - 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f, - 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, - 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f, - 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, - 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f, - 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7, - 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af, - 0x0068, 0x0266, 0x006a, 0x0072, 0x0279, 0x027b, 0x0281, 0x0077, - 0x0079, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf, - 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7, - 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf, - 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7, - 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x02de, 0x02df, - 0x0263, 0x006c, 0x0073, 0x0078, 0x0295, 0x02e5, 0x02e6, 0x02e7, - 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef, - 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7, - 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff, - 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, - 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f, - 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, - 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f, - 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, - 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f, - 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, - 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f, - 0x0300, 0x0301, 0x0342, 0x0313, 0x0308, 0x0345, 0x0346, 0x0347, - 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f, - 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, - 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f, - 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, - 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f, - 0x0370, 0x0371, 0x0372, 0x0373, 0x02b9, 0x0375, 0x0376, 0x0377, - 0x0378, 0x0379, 0x0020, 0x037b, 0x037c, 0x037d, 0x003b, 0x037f, - 0x0380, 0x0381, 0x0382, 0x0383, 0x0020, 0x00a8, 0x0391, 0x00b7, - 0x0395, 0x0397, 0x0399, 0x038b, 0x039f, 0x038d, 0x03a5, 0x03a9, - 0x03ca, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, - 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, - 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, - 0x03a8, 0x03a9, 0x0399, 0x03a5, 0x03b1, 0x03b5, 0x03b7, 0x03b9, - 0x03cb, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, - 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, - 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, - 0x03c8, 0x03c9, 0x03b9, 0x03c5, 0x03bf, 0x03c5, 0x03c9, 0x03cf, - 0x03b2, 0x03b8, 0x03a5, 0x03d2, 0x03d2, 0x03c6, 0x03c0, 0x03d7, - 0x03d8, 0x03d9, 0x03da, 0x03db, 0x03dc, 0x03dd, 0x03de, 0x03df, - 0x03e0, 0x03e1, 0x03e2, 0x03e3, 0x03e4, 0x03e5, 0x03e6, 0x03e7, - 0x03e8, 0x03e9, 0x03ea, 0x03eb, 0x03ec, 0x03ed, 0x03ee, 0x03ef, - 0x03ba, 0x03c1, 0x03c2, 0x03f3, 0x0398, 0x03b5, 0x03f6, 0x03f7, - 0x03f8, 0x03a3, 0x03fa, 0x03fb, 0x03fc, 0x03fd, 0x03fe, 0x03ff, - 0x0415, 0x0415, 0x0402, 0x0413, 0x0404, 0x0405, 0x0406, 0x0406, - 0x0408, 0x0409, 0x040a, 0x040b, 0x041a, 0x0418, 0x0423, 0x040f, - 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, - 0x0418, 0x0418, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, - 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, - 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, - 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, - 0x0438, 0x0438, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, - 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, - 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, - 0x0435, 0x0435, 0x0452, 0x0433, 0x0454, 0x0455, 0x0456, 0x0456, - 0x0458, 0x0459, 0x045a, 0x045b, 0x043a, 0x0438, 0x0443, 0x045f, - 0x0460, 0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467, - 0x0468, 0x0469, 0x046a, 0x046b, 0x046c, 0x046d, 0x046e, 0x046f, - 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0474, 0x0475, - 0x0478, 0x0479, 0x047a, 0x047b, 0x047c, 0x047d, 0x047e, 0x047f, - 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, - 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x048f, - 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, - 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x049f, - 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, - 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x04af, - 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, - 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x04be, 0x04bf, - 0x04c0, 0x0416, 0x0436, 0x04c3, 0x04c4, 0x04c5, 0x04c6, 0x04c7, - 0x04c8, 0x04c9, 0x04ca, 0x04cb, 0x04cc, 0x04cd, 0x04ce, 0x04cf, - 0x0410, 0x0430, 0x0410, 0x0430, 0x04d4, 0x04d5, 0x0415, 0x0435, - 0x04d8, 0x04d9, 0x04d8, 0x04d9, 0x0416, 0x0436, 0x0417, 0x0437, - 0x04e0, 0x04e1, 0x0418, 0x0438, 0x0418, 0x0438, 0x041e, 0x043e, - 0x04e8, 0x04e9, 0x04e8, 0x04e9, 0x042d, 0x044d, 0x0423, 0x0443, - 0x0423, 0x0443, 0x0423, 0x0443, 0x0427, 0x0447, 0x04f6, 0x04f7, - 0x042b, 0x044b, 0x04fa, 0x04fb, 0x04fc, 0x04fd, 0x04fe, 0x04ff, + 0x0041, 0x0061, 0x0041, 0x0061, 0x0041, 0x0061, 0x0043, 0x0063, + 0x0043, 0x0063, 0x0043, 0x0063, 0x0043, 0x0063, 0x0044, 0x0064, + 0x0110, 0x0111, 0x0045, 0x0065, 0x0045, 0x0065, 0x0045, 0x0065, + 0x0045, 0x0065, 0x0045, 0x0065, 0x0047, 0x0067, 0x0047, 0x0067, + 0x0047, 0x0067, 0x0047, 0x0067, 0x0048, 0x0068, 0x0126, 0x0127, + 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, + 0x0049, 0x0131, 0x0049, 0x0069, 0x004a, 0x006a, 0x004b, 0x006b, + 0x0138, 0x004c, 0x006c, 0x004c, 0x006c, 0x004c, 0x006c, 0x004c, + 0x006c, 0x0141, 0x0142, 0x004e, 0x006e, 0x004e, 0x006e, 0x004e, + 0x006e, 0x02bc, 0x014a, 0x014b, 0x004f, 0x006f, 0x004f, 0x006f, + 0x004f, 0x006f, 0x0152, 0x0153, 0x0052, 0x0072, 0x0052, 0x0072, + 0x0052, 0x0072, 0x0053, 0x0073, 0x0053, 0x0073, 0x0053, 0x0073, + 0x0053, 0x0073, 0x0054, 0x0074, 0x0054, 0x0074, 0x0166, 0x0167, + 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, + 0x0055, 0x0075, 0x0055, 0x0075, 0x0057, 0x0077, 0x0059, 0x0079, + 0x0059, 0x005a, 0x007a, 0x005a, 0x007a, 0x005a, 0x007a, 0x0073, + 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185, 0x0186, 0x0187, + 0x0188, 0x0189, 0x018a, 0x018b, 0x018c, 0x018d, 0x018e, 0x018f, + 0x0190, 0x0191, 0x0192, 0x0193, 0x0194, 0x0195, 0x0196, 0x0197, + 0x0198, 0x0199, 0x019a, 0x019b, 0x019c, 0x019d, 0x019e, 0x019f, + 0x004f, 0x006f, 0x01a2, 0x01a3, 0x01a4, 0x01a5, 0x01a6, 0x01a7, + 0x01a8, 0x01a9, 0x01aa, 0x01ab, 0x01ac, 0x01ad, 0x01ae, 0x0055, + 0x0075, 0x01b1, 0x01b2, 0x01b3, 0x01b4, 0x01b5, 0x01b6, 0x01b7, + 0x01b8, 0x01b9, 0x01ba, 0x01bb, 0x01bc, 0x01bd, 0x01be, 0x01bf, + 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x0044, 0x0044, 0x0064, 0x004c, + 0x004c, 0x006c, 0x004e, 0x004e, 0x006e, 0x0041, 0x0061, 0x0049, + 0x0069, 0x004f, 0x006f, 0x0055, 0x0075, 0x00dc, 0x00fc, 0x00dc, + 0x00fc, 0x00dc, 0x00fc, 0x00dc, 0x00fc, 0x01dd, 0x00c4, 0x00e4, + 0x0226, 0x0227, 0x00c6, 0x00e6, 0x01e4, 0x01e5, 0x0047, 0x0067, + 0x004b, 0x006b, 0x004f, 0x006f, 0x01ea, 0x01eb, 0x01b7, 0x0292, + 0x006a, 0x0044, 0x0044, 0x0064, 0x0047, 0x0067, 0x01f6, 0x01f7, + 0x004e, 0x006e, 0x00c5, 0x00e5, 0x00c6, 0x00e6, 0x00d8, 0x00f8, + 0x0041, 0x0061, 0x0041, 0x0061, 0x0045, 0x0065, 0x0045, 0x0065, + 0x0049, 0x0069, 0x0049, 0x0069, 0x004f, 0x006f, 0x004f, 0x006f, + 0x0052, 0x0072, 0x0052, 0x0072, 0x0055, 0x0075, 0x0055, 0x0075, + 0x0053, 0x0073, 0x0054, 0x0074, 0x021c, 0x021d, 0x0048, 0x0068, + 0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0225, 0x0041, 0x0061, + 0x0045, 0x0065, 0x00d6, 0x00f6, 0x00d5, 0x00f5, 0x004f, 0x006f, + 0x022e, 0x022f, 0x0059, 0x0079, 0x0234, 0x0235, 0x0236, 0x0237, + 0x0238, 0x0239, 0x023a, 0x023b, 0x023c, 0x023d, 0x023e, 0x023f, + 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, + 0x0248, 0x0249, 0x024a, 0x024b, 0x024c, 0x024d, 0x024e, 0x024f, + 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257, + 0x0258, 0x0259, 0x025a, 0x025b, 0x025c, 0x025d, 0x025e, 0x025f, + 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267, + 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f, + 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, + 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f, + 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, + 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f, + 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, + 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f, + 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7, + 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af, + 0x0068, 0x0266, 0x006a, 0x0072, 0x0279, 0x027b, 0x0281, 0x0077, + 0x0079, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf, + 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7, + 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf, + 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x02de, 0x02df, + 0x0263, 0x006c, 0x0073, 0x0078, 0x0295, 0x02e5, 0x02e6, 0x02e7, + 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef, + 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7, + 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff, + 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, + 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f, + 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, + 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f, + 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, + 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f, + 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, + 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f, + 0x0300, 0x0301, 0x0342, 0x0313, 0x0308, 0x0345, 0x0346, 0x0347, + 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f, + 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, + 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f, + 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, + 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f, + 0x0370, 0x0371, 0x0372, 0x0373, 0x02b9, 0x0375, 0x0376, 0x0377, + 0x0378, 0x0379, 0x0020, 0x037b, 0x037c, 0x037d, 0x003b, 0x037f, + 0x0380, 0x0381, 0x0382, 0x0383, 0x0020, 0x00a8, 0x0391, 0x00b7, + 0x0395, 0x0397, 0x0399, 0x038b, 0x039f, 0x038d, 0x03a5, 0x03a9, + 0x03ca, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, + 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, + 0x03a8, 0x03a9, 0x0399, 0x03a5, 0x03b1, 0x03b5, 0x03b7, 0x03b9, + 0x03cb, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, + 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, + 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, + 0x03c8, 0x03c9, 0x03b9, 0x03c5, 0x03bf, 0x03c5, 0x03c9, 0x03cf, + 0x03b2, 0x03b8, 0x03a5, 0x03d2, 0x03d2, 0x03c6, 0x03c0, 0x03d7, + 0x03d8, 0x03d9, 0x03da, 0x03db, 0x03dc, 0x03dd, 0x03de, 0x03df, + 0x03e0, 0x03e1, 0x03e2, 0x03e3, 0x03e4, 0x03e5, 0x03e6, 0x03e7, + 0x03e8, 0x03e9, 0x03ea, 0x03eb, 0x03ec, 0x03ed, 0x03ee, 0x03ef, + 0x03ba, 0x03c1, 0x03c2, 0x03f3, 0x0398, 0x03b5, 0x03f6, 0x03f7, + 0x03f8, 0x03a3, 0x03fa, 0x03fb, 0x03fc, 0x03fd, 0x03fe, 0x03ff, + 0x0415, 0x0415, 0x0402, 0x0413, 0x0404, 0x0405, 0x0406, 0x0406, + 0x0408, 0x0409, 0x040a, 0x040b, 0x041a, 0x0418, 0x0423, 0x040f, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0418, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0438, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, + 0x0435, 0x0435, 0x0452, 0x0433, 0x0454, 0x0455, 0x0456, 0x0456, + 0x0458, 0x0459, 0x045a, 0x045b, 0x043a, 0x0438, 0x0443, 0x045f, + 0x0460, 0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467, + 0x0468, 0x0469, 0x046a, 0x046b, 0x046c, 0x046d, 0x046e, 0x046f, + 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0474, 0x0475, + 0x0478, 0x0479, 0x047a, 0x047b, 0x047c, 0x047d, 0x047e, 0x047f, + 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, + 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x048f, + 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, + 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x049f, + 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, + 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x04af, + 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, + 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x04be, 0x04bf, + 0x04c0, 0x0416, 0x0436, 0x04c3, 0x04c4, 0x04c5, 0x04c6, 0x04c7, + 0x04c8, 0x04c9, 0x04ca, 0x04cb, 0x04cc, 0x04cd, 0x04ce, 0x04cf, + 0x0410, 0x0430, 0x0410, 0x0430, 0x04d4, 0x04d5, 0x0415, 0x0435, + 0x04d8, 0x04d9, 0x04d8, 0x04d9, 0x0416, 0x0436, 0x0417, 0x0437, + 0x04e0, 0x04e1, 0x0418, 0x0438, 0x0418, 0x0438, 0x041e, 0x043e, + 0x04e8, 0x04e9, 0x04e8, 0x04e9, 0x042d, 0x044d, 0x0423, 0x0443, + 0x0423, 0x0443, 0x0423, 0x0443, 0x0427, 0x0447, 0x04f6, 0x04f7, + 0x042b, 0x044b, 0x04fa, 0x04fb, 0x04fc, 0x04fd, 0x04fe, 0x04ff, }; // generated with: diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index af0ef4b37..4e1f5fe92 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -46,17 +46,18 @@ public class LastComposedWord { public final String mTypedWord; public final String mCommittedWord; public final int mSeparatorCode; + public final CharSequence mPrevWord; private boolean mActive; public static final LastComposedWord NOT_A_COMPOSED_WORD = - new LastComposedWord(null, null, null, "", "", NOT_A_SEPARATOR); + new LastComposedWord(null, null, null, "", "", NOT_A_SEPARATOR, null); // Warning: this is using the passed objects as is and fully expects them to be // immutable. Do not fiddle with their contents after you passed them to this constructor. public LastComposedWord(final int[] primaryKeyCodes, final int[] xCoordinates, final int[] yCoordinates, final String typedWord, final String committedWord, - final int separatorCode) { + final int separatorCode, final CharSequence prevWord) { mPrimaryKeyCodes = primaryKeyCodes; mXCoordinates = xCoordinates; mYCoordinates = yCoordinates; @@ -64,6 +65,7 @@ public class LastComposedWord { mCommittedWord = committedWord; mSeparatorCode = separatorCode; mActive = true; + mPrevWord = prevWord; } public void deactivate() { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 83658f77e..d7d27b5e3 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1027,16 +1027,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (!mWordComposer.isComposingWord()) return; final CharSequence typedWord = mWordComposer.getTypedWord(); if (typedWord.length() > 0) { - mLastComposedWord = mWordComposer.commitWord( - LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, typedWord.toString(), - separatorCode); if (ic != null) { ic.commitText(typedWord, 1); if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.latinIME_commitText(typedWord); } } - addToUserHistoryDictionary(typedWord); + final CharSequence prevWord = addToUserHistoryDictionary(typedWord); + mLastComposedWord = mWordComposer.commitWord( + LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, typedWord.toString(), + separatorCode, prevWord); } updateSuggestions(); } @@ -1836,8 +1836,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mExpectingUpdateSelection = true; commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, separatorCodePoint); - // Add the word to the user history dictionary - addToUserHistoryDictionary(autoCorrection); if (!typedWord.equals(autoCorrection) && null != ic) { // This will make the correction flash for a short while as a visual clue // to the user that auto-correction happened. @@ -1915,8 +1913,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen LastComposedWord.NOT_A_SEPARATOR); // Don't allow cancellation of manual pick mLastComposedWord.deactivate(); - // Add the word to the user history dictionary - addToUserHistoryDictionary(suggestion); mSpaceState = SPACE_STATE_PHANTOM; // TODO: is this necessary? mKeyboardSwitcher.updateShiftState(); @@ -1959,31 +1955,33 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen /** * Commits the chosen word to the text field and saves it for later retrieval. */ - private void commitChosenWord(final CharSequence bestWord, final int commitType, + private void commitChosenWord(final CharSequence chosenWord, final int commitType, final int separatorCode) { final InputConnection ic = getCurrentInputConnection(); if (ic != null) { if (mSettingsValues.mEnableSuggestionSpanInsertion) { final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions(); ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( - this, bestWord, suggestedWords, mIsMainDictionaryAvailable), + this, chosenWord, suggestedWords, mIsMainDictionaryAvailable), 1); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_commitText(bestWord); + ResearchLogger.latinIME_commitText(chosenWord); } } else { - ic.commitText(bestWord, 1); + ic.commitText(chosenWord, 1); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_commitText(bestWord); + ResearchLogger.latinIME_commitText(chosenWord); } } } + // Add the word to the user history dictionary + final CharSequence prevWord = addToUserHistoryDictionary(chosenWord); // TODO: figure out here if this is an auto-correct or if the best word is actually // what user typed. Note: currently this is done much later in // LastComposedWord#didCommitTypedWord by string equality of the remembered // strings. - mLastComposedWord = mWordComposer.commitWord(commitType, bestWord.toString(), - separatorCode); + mLastComposedWord = mWordComposer.commitWord(commitType, chosenWord.toString(), + separatorCode, prevWord); } public void updateBigramPredictions() { @@ -2023,15 +2021,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen setSuggestionStripShown(isSuggestionsStripVisible()); } - private void addToUserHistoryDictionary(final CharSequence suggestion) { - if (TextUtils.isEmpty(suggestion)) return; + private CharSequence addToUserHistoryDictionary(final CharSequence suggestion) { + if (TextUtils.isEmpty(suggestion)) return null; // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be // adding words in situations where the user or application really didn't // want corrections enabled or learned. if (!(mCorrectionMode == Suggest.CORRECTION_FULL || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) { - return; + return null; } if (mUserHistoryDictionary != null) { @@ -2051,7 +2049,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } mUserHistoryDictionary.addToUserHistory(null == prevWord ? null : prevWord.toString(), secondWord); + return prevWord; } + return null; } public boolean isCursorTouchingWord() { @@ -2136,6 +2136,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // "ic" must not be null private void revertCommit(final InputConnection ic) { + final CharSequence previousWord = mLastComposedWord.mPrevWord; final String originallyTypedWord = mLastComposedWord.mTypedWord; final CharSequence committedWord = mLastComposedWord.mCommittedWord; final int cancelLength = committedWord.length(); @@ -2160,6 +2161,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.latinIME_deleteSurroundingText(deleteLength); } + if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) { + mUserHistoryDictionary.cancelAddingUserHistory( + previousWord.toString(), committedWord.toString()); + } if (0 == separatorLength || mLastComposedWord.didCommitTypedWord()) { // This is the case when we cancel a manual pick. // We should restart suggestion on the word right away. diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java index e13602e50..efafacc8a 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java @@ -202,6 +202,15 @@ public class UserHistoryDictionary extends ExpandableDictionary { return freq; } + public boolean cancelAddingUserHistory(String word1, String word2) { + final Bigram bi = new Bigram(word1, word2, 0); + if (mPendingWrites.contains(bi)) { + mPendingWrites.remove(bi); + return super.removeBigram(word1, word2); + } + return false; + } + /** * Schedules a background thread to write any pending words to the database. */ diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index e27a546c5..ca9caa1d3 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -313,7 +313,7 @@ public class WordComposer { // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. public LastComposedWord commitWord(final int type, final String committedWord, - final int separatorCode) { + final int separatorCode, final CharSequence prevWord) { // Note: currently, we come here whenever we commit a word. If it's a MANUAL_PICK // or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate // the last composed word to ensure this does not happen. @@ -324,7 +324,8 @@ public class WordComposer { mXCoordinates = new int[N]; mYCoordinates = new int[N]; final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes, - xCoordinates, yCoordinates, mTypedWord.toString(), committedWord, separatorCode); + xCoordinates, yCoordinates, mTypedWord.toString(), committedWord, separatorCode, + prevWord); if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD && type != LastComposedWord.COMMIT_TYPE_MANUAL_PICK) { lastComposedWord.deactivate(); -- cgit v1.2.3-83-g751a From e55c23e4b0b8d9d66349a3b275d0fa1540d7450a Mon Sep 17 00:00:00 2001 From: Ken Wakasa Date: Wed, 27 Jun 2012 14:35:24 +0900 Subject: Small cleanups Change-Id: Ic1a198ab1b4f0323fde9e4245729fd0e6011b914 --- .../com/android/inputmethod/latin/ContactsBinaryDictionary.java | 8 ++++---- java/src/com/android/inputmethod/latin/SuggestedWords.java | 2 +- java/src/com/android/inputmethod/latin/WordComposer.java | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java index 2a02603ca..620c553af 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -161,7 +161,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { * bigrams depending on locale. */ private void addName(String name) { - int len = name.codePointCount(0, name.length()); + int len = StringUtils.codePointCount(name); String prevWord = null; // TODO: Better tokenization for non-Latin writing systems for (int i = 0; i < len; i++) { @@ -171,7 +171,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { i = end - 1; // Don't add single letter words, possibly confuses // capitalization of i. - final int wordLen = word.codePointCount(0, word.length()); + final int wordLen = StringUtils.codePointCount(word); if (wordLen < MAX_WORD_LENGTH && wordLen > 1) { super.addWord(word, null /* shortcut */, FREQUENCY_FOR_CONTACTS); if (!TextUtils.isEmpty(prevWord)) { @@ -260,14 +260,14 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { * Checks if the words in a name are in the current binary dictionary. */ private boolean isNameInDictionary(String name) { - int len = name.codePointCount(0, name.length()); + int len = StringUtils.codePointCount(name); String prevWord = null; for (int i = 0; i < len; i++) { if (Character.isLetter(name.codePointAt(i))) { int end = getWordEndPosition(name, len, i); String word = name.substring(i, end); i = end - 1; - final int wordLen = word.codePointCount(0, word.length()); + final int wordLen = StringUtils.codePointCount(word); if (wordLen < MAX_WORD_LENGTH && wordLen > 1) { if (!TextUtils.isEmpty(prevWord) && mUseFirstLastBigrams) { if (!super.isValidBigramLocked(prevWord, word)) { diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index 45ac9ff53..9883cd6bc 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -142,7 +142,7 @@ public class SuggestedWords { mWord = word; mScore = score; mKind = kind; - mCodePointCount = mWordStr.codePointCount(0, mWordStr.length()); + mCodePointCount = StringUtils.codePointCount(mWordStr); } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index ca9caa1d3..bcd295d25 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -92,7 +92,7 @@ public class WordComposer { refreshSize(); } - public final void refreshSize() { + private final void refreshSize() { mCodePointSize = mTypedWord.codePointCount(0, mTypedWord.length()); } -- cgit v1.2.3-83-g751a From 71538b08e4e08d556f700ad344562ca2c7b74d82 Mon Sep 17 00:00:00 2001 From: Satoshi Kataoka Date: Fri, 29 Jun 2012 18:42:15 +0900 Subject: Add input pointers Change-Id: I95300bf0a847fb86d026e846ff4ad723bb45284f --- .../inputmethod/latin/BinaryDictionary.java | 8 +- .../inputmethod/latin/ExpandableDictionary.java | 5 +- .../android/inputmethod/latin/InputPointers.java | 131 +++++++++++++++++++++ .../inputmethod/latin/LastComposedWord.java | 14 +-- .../android/inputmethod/latin/WordComposer.java | 30 ++--- 5 files changed, 155 insertions(+), 33 deletions(-) create mode 100644 java/src/com/android/inputmethod/latin/InputPointers.java (limited to 'java/src/com/android/inputmethod/latin/WordComposer.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index e4ffa7599..ae415d0ab 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -199,10 +199,12 @@ public class BinaryDictionary extends Dictionary { //final int commitPoint = codes.getCommitPoint(); //codes.clearCommitPoint(); + final InputPointers ips = codes.getInputPointers(); + return getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), - codes.getXCoordinates(), codes.getYCoordinates(), emptyArray, emptyArray, mInputCodes, - codesSize, 0 /* unused */, false, prevWordCodePointArray, mUseFullEditDistance, - outputChars, scores, spaceIndices); + ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), + mInputCodes, codesSize, 0 /* unused */, false, prevWordCodePointArray, + mUseFullEditDistance, outputChars, scores, spaceIndices); } public static float calcNormalizedScore(String before, String after, int score) { diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index cfecc664a..76213c0da 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -268,8 +268,9 @@ public class ExpandableDictionary extends Dictionary { final ArrayList suggestions = new ArrayList(); mInputLength = codes.size(); if (mCodes.length < mInputLength) mCodes = new int[mInputLength][]; - final int[] xCoordinates = codes.getXCoordinates(); - final int[] yCoordinates = codes.getYCoordinates(); + final InputPointers ips = codes.getInputPointers(); + final int[] xCoordinates = ips.getXCoordinates(); + final int[] yCoordinates = ips.getYCoordinates(); // Cache the codes so that we don't have to lookup an array list for (int i = 0; i < mInputLength; i++) { // TODO: Calculate proximity info here. diff --git a/java/src/com/android/inputmethod/latin/InputPointers.java b/java/src/com/android/inputmethod/latin/InputPointers.java new file mode 100644 index 000000000..218243e9f --- /dev/null +++ b/java/src/com/android/inputmethod/latin/InputPointers.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +import java.util.Arrays; + +public class InputPointers { + private final ScalableIntArray mXCoordinates = new ScalableIntArray(); + private final ScalableIntArray mYCoordinates = new ScalableIntArray(); + private final ScalableIntArray mPointerIds = new ScalableIntArray(); + private final ScalableIntArray mTimes = new ScalableIntArray(); + + public void addPointer(int index, int x, int y, int pointerId, int time) { + mXCoordinates.add(index, x); + mYCoordinates.add(index, y); + mPointerIds.add(index, pointerId); + mTimes.add(index, time); + } + + public void addPointer(int x, int y, int pointerId, int time) { + mXCoordinates.add(x); + mYCoordinates.add(y); + mPointerIds.add(pointerId); + mTimes.add(time); + } + + public void set(InputPointers ip) { + mXCoordinates.set(ip.mXCoordinates); + mYCoordinates.set(ip.mYCoordinates); + mPointerIds.set(ip.mPointerIds); + mTimes.set(ip.mTimes); + } + + public void copy(InputPointers ip) { + mXCoordinates.copy(ip.mXCoordinates); + mYCoordinates.copy(ip.mYCoordinates); + mPointerIds.copy(ip.mPointerIds); + mTimes.copy(ip.mTimes); + } + + public void reset() { + mXCoordinates.reset(); + mYCoordinates.reset(); + mPointerIds.reset(); + mTimes.reset(); + } + + public int getPointerSize() { + return mXCoordinates.getLength(); + } + + public int[] getXCoordinates() { + return mXCoordinates.mArray; + } + + public int[] getYCoordinates() { + return mYCoordinates.mArray; + } + + public int[] getPointerIds() { + return mPointerIds.mArray; + } + + public int[] getTimes() { + return mTimes.mArray; + } + + private static class ScalableIntArray { + private static final int DEFAULT_SIZE = BinaryDictionary.MAX_WORD_LENGTH; + private int[] mArray; + private int mLength; + + public ScalableIntArray() { + reset(); + } + + public void add(int index, int val) { + if (mLength < index + 1) { + mLength = index; + add(val); + } else { + mArray[index] = val; + } + } + + public void add(int val) { + if (mLength >= mArray.length) { + final int[] newArray = new int[mLength * 2]; + System.arraycopy(mArray, 0, newArray, 0, mLength); + } + mArray[mLength] = val; + ++mLength; + } + + public int getLength() { + return mLength; + } + + public void reset() { + mArray = new int[DEFAULT_SIZE]; + mLength = 0; + } + + public int[] getPrimitiveArray() { + return mArray; + } + + public void copy(ScalableIntArray ip) { + mArray = Arrays.copyOf(ip.mArray, ip.mArray.length); + } + + public void set(ScalableIntArray ip) { + mArray = ip.mArray; + mLength = ip.mLength; + } + } +} diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index 4e1f5fe92..318aecb50 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -41,26 +41,26 @@ public class LastComposedWord { public static final int NOT_A_SEPARATOR = -1; public final int[] mPrimaryKeyCodes; - public final int[] mXCoordinates; - public final int[] mYCoordinates; public final String mTypedWord; public final String mCommittedWord; public final int mSeparatorCode; public final CharSequence mPrevWord; + public final InputPointers mInputPointers = new InputPointers(); private boolean mActive; public static final LastComposedWord NOT_A_COMPOSED_WORD = - new LastComposedWord(null, null, null, "", "", NOT_A_SEPARATOR, null); + new LastComposedWord(null, null, "", "", NOT_A_SEPARATOR, null); // Warning: this is using the passed objects as is and fully expects them to be // immutable. Do not fiddle with their contents after you passed them to this constructor. - public LastComposedWord(final int[] primaryKeyCodes, final int[] xCoordinates, - final int[] yCoordinates, final String typedWord, final String committedWord, + public LastComposedWord(final int[] primaryKeyCodes, final InputPointers inputPointers, + final String typedWord, final String committedWord, final int separatorCode, final CharSequence prevWord) { mPrimaryKeyCodes = primaryKeyCodes; - mXCoordinates = xCoordinates; - mYCoordinates = yCoordinates; + if (inputPointers != null) { + mInputPointers.copy(inputPointers); + } mTypedWord = typedWord; mCommittedWord = committedWord; mSeparatorCode = separatorCode; diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index bcd295d25..98282f970 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -34,8 +34,7 @@ public class WordComposer { private static final int N = BinaryDictionary.MAX_WORD_LENGTH; private int[] mPrimaryKeyCodes; - private int[] mXCoordinates; - private int[] mYCoordinates; + private final InputPointers mInputPointers = new InputPointers(); private StringBuilder mTypedWord; private CharSequence mAutoCorrection; private boolean mIsResumed; @@ -54,8 +53,6 @@ public class WordComposer { public WordComposer() { mPrimaryKeyCodes = new int[N]; mTypedWord = new StringBuilder(N); - mXCoordinates = new int[N]; - mYCoordinates = new int[N]; mAutoCorrection = null; mTrailingSingleQuotesCount = 0; mIsResumed = false; @@ -69,8 +66,7 @@ public class WordComposer { public void init(WordComposer source) { mPrimaryKeyCodes = Arrays.copyOf(source.mPrimaryKeyCodes, source.mPrimaryKeyCodes.length); mTypedWord = new StringBuilder(source.mTypedWord); - mXCoordinates = Arrays.copyOf(source.mXCoordinates, source.mXCoordinates.length); - mYCoordinates = Arrays.copyOf(source.mYCoordinates, source.mYCoordinates.length); + mInputPointers.copy(source.mInputPointers); mCapsCount = source.mCapsCount; mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; @@ -116,12 +112,8 @@ public class WordComposer { return mPrimaryKeyCodes[index]; } - public int[] getXCoordinates() { - return mXCoordinates; - } - - public int[] getYCoordinates() { - return mYCoordinates; + public InputPointers getInputPointers() { + return mInputPointers; } private static boolean isFirstCharCapitalized(int index, int codePoint, boolean previous) { @@ -157,8 +149,8 @@ public class WordComposer { if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { mPrimaryKeyCodes[newIndex] = primaryCode >= Keyboard.CODE_SPACE ? Character.toLowerCase(primaryCode) : primaryCode; - mXCoordinates[newIndex] = keyX; - mYCoordinates[newIndex] = keyY; + // TODO: Set correct pointer id and time + mInputPointers.addPointer(newIndex, keyX, keyY, 0, 0); } mIsFirstCharCapitalized = isFirstCharCapitalized( newIndex, primaryCode, mIsFirstCharCapitalized); @@ -318,14 +310,11 @@ public class WordComposer { // or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate // the last composed word to ensure this does not happen. final int[] primaryKeyCodes = mPrimaryKeyCodes; - final int[] xCoordinates = mXCoordinates; - final int[] yCoordinates = mYCoordinates; mPrimaryKeyCodes = new int[N]; - mXCoordinates = new int[N]; - mYCoordinates = new int[N]; final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes, - xCoordinates, yCoordinates, mTypedWord.toString(), committedWord, separatorCode, + mInputPointers, mTypedWord.toString(), committedWord, separatorCode, prevWord); + mInputPointers.reset(); if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD && type != LastComposedWord.COMMIT_TYPE_MANUAL_PICK) { lastComposedWord.deactivate(); @@ -339,8 +328,7 @@ public class WordComposer { public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) { mPrimaryKeyCodes = lastComposedWord.mPrimaryKeyCodes; - mXCoordinates = lastComposedWord.mXCoordinates; - mYCoordinates = lastComposedWord.mYCoordinates; + mInputPointers.set(lastComposedWord.mInputPointers); mTypedWord.setLength(0); mTypedWord.append(lastComposedWord.mTypedWord); refreshSize(); -- cgit v1.2.3-83-g751a