diff options
20 files changed, 381 insertions, 299 deletions
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml index 70ace776f..36412b48f 100644 --- a/java/res/values/donottranslate.xml +++ b/java/res/values/donottranslate.xml @@ -29,19 +29,6 @@ <string name="symbols_word_separators">"	 \n"()[]{}*&<>+=|.,;:!?/_\"</string> <!-- Word connectors --> <string name="symbols_word_connectors">\'-</string> - <!-- Symbol characters list that should switch back to the main layout --> - <!-- U+2018: "‘" LEFT SINGLE QUOTATION MARK - U+2019: "’" RIGHT SINGLE QUOTATION MARK - U+201A: "‚" SINGLE LOW-9 QUOTATION MARK - U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK - U+201C: "“" LEFT DOUBLE QUOTATION MARK - U+201D: "”" RIGHT DOUBLE QUOTATION MARK - U+201E: "„" DOUBLE LOW-9 QUOTATION MARK - U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK - U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK --> - <!-- <string name="layout_switch_back_symbols">\"\'‘’‚‛“”„‟«»</string> --> - <string name="layout_switch_back_symbols"></string> <!-- Always show the suggestion strip --> <string name="prefs_suggestion_visibility_show_value">0</string> diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index bc9dbc049..bad9a8aed 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -149,7 +149,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { settingsValues.isLanguageSwitchKeyEnabled()); mKeyboardLayoutSet = builder.build(); try { - mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols)); + mState.onLoadKeyboard(); mFeedbackManager.onSettingsChanged(settingsValues); } catch (KeyboardLayoutSetException e) { Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause()); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java index 25a1c6a00..5a77044b5 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -26,7 +26,7 @@ import com.android.inputmethod.latin.Constants; * * This class contains all keyboard state transition logic. * - * The input events are {@link #onLoadKeyboard(String)}, {@link #onSaveKeyboardState()}, + * The input events are {@link #onLoadKeyboard()}, {@link #onSaveKeyboardState()}, * {@link #onPressKey(int, boolean, int)}, {@link #onReleaseKey(int, boolean)}, * {@link #onCodeInput(int, boolean, int)}, {@link #onCancelInput(boolean)}, * {@link #onUpdateShiftState(int)}, {@link #onLongPressTimeout(int)}. @@ -74,7 +74,6 @@ public final class KeyboardState { private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3; private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4; private int mSwitchState = SWITCH_STATE_ALPHA; - private String mLayoutSwitchBackSymbols; private boolean mIsAlphabetMode; private AlphabetShiftState mAlphabetShiftState = new AlphabetShiftState(); @@ -109,15 +108,14 @@ public final class KeyboardState { } } - public KeyboardState(SwitchActions switchActions) { + public KeyboardState(final SwitchActions switchActions) { mSwitchActions = switchActions; } - public void onLoadKeyboard(String layoutSwitchBackSymbols) { + public void onLoadKeyboard() { if (DEBUG_EVENT) { Log.d(TAG, "onLoadKeyboard: " + this); } - mLayoutSwitchBackSymbols = layoutSwitchBackSymbols; // Reset alphabet shift state. mAlphabetShiftState.setShiftLocked(false); mPrevMainKeyboardWasShiftLocked = false; @@ -177,7 +175,7 @@ public final class KeyboardState { private static final int AUTOMATIC_SHIFT = 2; private static final int SHIFT_LOCK_SHIFTED = 3; - private void setShifted(int shiftMode) { + private void setShifted(final int shiftMode) { if (DEBUG_ACTION) { Log.d(TAG, "setShifted: shiftMode=" + shiftModeToString(shiftMode) + " " + this); } @@ -216,7 +214,7 @@ public final class KeyboardState { } } - private void setShiftLocked(boolean shiftLocked) { + private void setShiftLocked(final boolean shiftLocked) { if (DEBUG_ACTION) { Log.d(TAG, "setShiftLocked: shiftLocked=" + shiftLocked + " " + this); } @@ -313,7 +311,7 @@ public final class KeyboardState { mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; } - public void onPressKey(int code, boolean isSinglePointer, int autoCaps) { + public void onPressKey(final int code, final boolean isSinglePointer, final int autoCaps) { if (DEBUG_EVENT) { Log.d(TAG, "onPressKey: code=" + Constants.printableCode(code) + " single=" + isSinglePointer + " autoCaps=" + autoCaps + " " + this); @@ -346,7 +344,7 @@ public final class KeyboardState { } } - public void onReleaseKey(int code, boolean withSliding) { + public void onReleaseKey(final int code, final boolean withSliding) { if (DEBUG_EVENT) { Log.d(TAG, "onReleaseKey: code=" + Constants.printableCode(code) + " sliding=" + withSliding + " " + this); @@ -364,7 +362,7 @@ public final class KeyboardState { mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL; } - private void onReleaseSymbol(boolean withSliding) { + private void onReleaseSymbol(final boolean withSliding) { if (mSymbolKeyState.isChording()) { // Switch back to the previous keyboard mode if the user chords the mode change key and // another key, then releases the mode change key. @@ -378,7 +376,7 @@ public final class KeyboardState { mSymbolKeyState.onRelease(); } - public void onLongPressTimeout(int code) { + public void onLongPressTimeout(final int code) { if (DEBUG_EVENT) { Log.d(TAG, "onLongPressTimeout: code=" + Constants.printableCode(code) + " " + this); } @@ -388,7 +386,7 @@ public final class KeyboardState { } } - public void onUpdateShiftState(int autoCaps) { + public void onUpdateShiftState(final int autoCaps) { if (DEBUG_EVENT) { Log.d(TAG, "onUpdateShiftState: autoCaps=" + autoCaps + " " + this); } @@ -404,7 +402,7 @@ public final class KeyboardState { resetKeyboardStateToAlphabet(); } - private void updateAlphabetShiftState(int autoCaps) { + private void updateAlphabetShiftState(final int autoCaps) { if (!mIsAlphabetMode) return; if (!mShiftKeyState.isReleasing()) { // Ignore update shift state event while the shift key is being pressed (including @@ -468,7 +466,7 @@ public final class KeyboardState { } } - private void onReleaseShift(boolean withSliding) { + private void onReleaseShift(final boolean withSliding) { if (mIsAlphabetMode) { final boolean isShiftLocked = mAlphabetShiftState.isShiftLocked(); mIsInAlphabetUnshiftedFromShifted = false; @@ -523,7 +521,7 @@ public final class KeyboardState { mShiftKeyState.onRelease(); } - public void onCancelInput(boolean isSinglePointer) { + public void onCancelInput(final boolean isSinglePointer) { if (DEBUG_EVENT) { Log.d(TAG, "onCancelInput: single=" + isSinglePointer + " " + this); } @@ -542,17 +540,11 @@ public final class KeyboardState { || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE; } - private static boolean isSpaceCharacter(int c) { + private static boolean isSpaceCharacter(final int c) { return c == Constants.CODE_SPACE || c == Constants.CODE_ENTER; } - private boolean isLayoutSwitchBackCharacter(int c) { - if (TextUtils.isEmpty(mLayoutSwitchBackSymbols)) return false; - if (mLayoutSwitchBackSymbols.indexOf(c) >= 0) return true; - return false; - } - - public void onCodeInput(int code, boolean isSinglePointer, int autoCaps) { + public void onCodeInput(final int code, final boolean isSinglePointer, final int autoCaps) { if (DEBUG_EVENT) { Log.d(TAG, "onCodeInput: code=" + Constants.printableCode(code) + " single=" + isSinglePointer @@ -592,17 +584,11 @@ public final class KeyboardState { || code == Constants.CODE_OUTPUT_TEXT)) { mSwitchState = SWITCH_STATE_SYMBOL; } - // Switch back to alpha keyboard mode immediately if user types one of the switch back - // characters. - if (isLayoutSwitchBackCharacter(code)) { - toggleAlphabetAndSymbols(); - mPrevSymbolsKeyboardWasShifted = false; - } break; case SWITCH_STATE_SYMBOL: // Switch back to alpha keyboard mode if user types one or more non-space/enter - // characters followed by a space/enter or one of the switch back characters. - if (isSpaceCharacter(code) || isLayoutSwitchBackCharacter(code)) { + // characters followed by a space/enter. + if (isSpaceCharacter(code)) { toggleAlphabetAndSymbols(); mPrevSymbolsKeyboardWasShifted = false; } @@ -615,7 +601,7 @@ public final class KeyboardState { } } - private static String shiftModeToString(int shiftMode) { + private static String shiftModeToString(final int shiftMode) { switch (shiftMode) { case UNSHIFT: return "UNSHIFT"; case MANUAL_SHIFT: return "MANUAL"; @@ -624,7 +610,7 @@ public final class KeyboardState { } } - private static String switchStateToString(int switchState) { + private static String switchStateToString(final int switchState) { switch (switchState) { case SWITCH_STATE_ALPHA: return "ALPHA"; case SWITCH_STATE_SYMBOL_BEGIN: return "SYMBOL-BEGIN"; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index d02c4df7e..f4b7a1708 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -773,7 +773,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // to the user dictionary. if (null != mPositionalInfoForUserDictPendingAddition && mPositionalInfoForUserDictPendingAddition.tryReplaceWithActualWord( - mConnection, editorInfo, mLastSelectionEnd)) { + mConnection, editorInfo, mLastSelectionEnd, + mSubtypeSwitcher.getCurrentSubtypeLocale())) { mPositionalInfoForUserDictPendingAddition = null; } // If tryReplaceWithActualWord returns false, we don't know what word was @@ -1223,11 +1224,17 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mPositionalInfoForUserDictPendingAddition = null; return; } + final String wordToEdit; + if (StringUtils.isAutoCapsMode(mLastComposedWord.mCapitalizedMode)) { + wordToEdit = word.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale()); + } else { + wordToEdit = word; + } mPositionalInfoForUserDictPendingAddition = new PositionalInfoForUserDictPendingAddition( - word, mLastSelectionEnd, getCurrentInputEditorInfo(), + wordToEdit, mLastSelectionEnd, getCurrentInputEditorInfo(), mLastComposedWord.mCapitalizedMode); - mUserDictionary.addWordToUserDictionary(word, 128); + mUserDictionary.addWordToUserDictionary(wordToEdit); } public void onWordAddedToUserDictionary(final String newSpelling) { @@ -1240,7 +1247,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } mPositionalInfoForUserDictPendingAddition.setActualWordBeingAdded(newSpelling); if (mPositionalInfoForUserDictPendingAddition.tryReplaceWithActualWord( - mConnection, getCurrentInputEditorInfo(), mLastSelectionEnd)) { + mConnection, getCurrentInputEditorInfo(), mLastSelectionEnd, + mSubtypeSwitcher.getCurrentSubtypeLocale())) { mPositionalInfoForUserDictPendingAddition = null; } } @@ -1476,7 +1484,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction Stats.onAutoCorrection("", mWordComposer.getTypedWord(), " ", mWordComposer); } } - if (mWordComposer.size() <= 1) { + final int wordComposerSize = mWordComposer.size(); + // Since isComposingWord() is true, the size is at least 1. + final int lastChar = mWordComposer.getCodeAt(wordComposerSize - 1); + if (wordComposerSize <= 1) { // We auto-correct the previous (typed, not gestured) string iff it's one character // long. The reason for this is, even in the middle of gesture typing, you'll still // tap one-letter words and you want them auto-corrected (typically, "i" in English @@ -1490,8 +1501,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } mExpectingUpdateSelection = true; // The following is necessary for the case where the user typed something but didn't - // manual pick it and didn't input any separator. - mSpaceState = SPACE_STATE_PHANTOM; + // manual pick it and didn't input any separator: we want to put a space between what + // has been entered and the coming gesture input result, so we go into phantom space + // state, which will be promoted to a space when the gesture result is committed. But if + // the current input ends in a word connector on the other hand, then we want to have + // the next input stick to the current input so we don't switch to phantom space state. + if (!mSettings.getCurrent().isWordConnector(lastChar)) { + mSpaceState = SPACE_STATE_PHANTOM; + } } else { final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor(); if (mSettings.getCurrent().isUsuallyFollowedBySpace(codePointBeforeCursor)) { diff --git a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java b/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java index a33cefcd6..8493ef669 100644 --- a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java +++ b/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java @@ -18,6 +18,8 @@ package com.android.inputmethod.latin; import android.view.inputmethod.EditorInfo; +import java.util.Locale; + /** * Holder class for data about a word already committed but that may still be edited. * @@ -70,10 +72,11 @@ public final class PositionalInfoForUserDictPendingAddition { * @param connection The RichInputConnection through which to contact the editor. * @param editorInfo Information pertaining to the editor we are currently in. * @param currentCursorPosition The current cursor position, for checking purposes. + * @param locale The locale for changing case, if necessary * @return true if the edit has been successfully made, false if we need to try again later */ public boolean tryReplaceWithActualWord(final RichInputConnection connection, - final EditorInfo editorInfo, final int currentCursorPosition) { + final EditorInfo editorInfo, final int currentCursorPosition, final Locale locale) { // If we still don't know the actual word being added, we need to try again later. if (null == mActualWordBeingAdded) return false; // The entered text and the registered text were the same anyway : we can @@ -92,9 +95,12 @@ public final class PositionalInfoForUserDictPendingAddition { // so that it won't be tried again if (currentCursorPosition != mCursorPos) return true; // We have made all the checks : do the replacement and report success + // If this was auto-capitalized, we need to restore the case before committing + final String wordWithCaseFixed = StringUtils.applyAutoCapsMode(mActualWordBeingAdded, + mCapitalizedMode, locale); connection.setComposingRegion(currentCursorPosition - mOriginalWord.length(), currentCursorPosition); - connection.commitText(mActualWordBeingAdded, mActualWordBeingAdded.length()); + connection.commitText(wordWithCaseFixed, wordWithCaseFixed.length()); return true; } } diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index ddaa5ff5b..d00edbe92 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -103,6 +103,37 @@ public final class StringUtils { } } + /** + * Apply an auto-caps mode to a string. + * + * This intentionally does NOT apply manual caps mode. It only changes the capitalization if + * the mode is one of the auto-caps modes. + * @param s The string to capitalize. + * @param capitalizeMode The mode in which to capitalize. + * @param locale The locale for capitalizing. + * @return The capitalized string. + */ + public static String applyAutoCapsMode(final String s, final int capitalizeMode, + final Locale locale) { + if (WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED == capitalizeMode) { + return s.toUpperCase(locale); + } else if (WordComposer.CAPS_MODE_AUTO_SHIFTED == capitalizeMode) { + return toTitleCase(s, locale); + } else { + return s; + } + } + + /** + * Return whether a constant represents an auto-caps mode (either auto-shift or auto-shift-lock) + * @param mode The mode to test for + * @return true if this represents an auto-caps mode, false otherwise + */ + public static boolean isAutoCapsMode(final int mode) { + return WordComposer.CAPS_MODE_AUTO_SHIFTED == mode + || WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED == mode; + } + public static String toTitleCase(final String s, final Locale locale) { if (s.length() <= 1) { // TODO: is this really correct? Shouldn't this be s.toUpperCase()? diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java index a16784985..0d5bde623 100644 --- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java @@ -216,17 +216,13 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { * * @param word the word to add. If the word is capitalized, then the dictionary will * recognize it as a capitalized word when searched. - * @param frequency the frequency of occurrence of the word. A frequency of 255 is considered - * the highest. - * @TODO use a higher or float range for frequency */ - public synchronized void addWordToUserDictionary(final String word, final int frequency) { + public synchronized void addWordToUserDictionary(final String word) { // TODO: do something for the UI. With the following, any sufficiently long word will // look like it will go to the user dictionary but it won't. // Safeguard against adding long words. Can cause stack overflow. if (word.length() >= MAX_WORD_LENGTH) return; - // TODO: Add an argument to the intent to specify the frequency. Intent intent = new Intent(ACTION_USER_DICTIONARY_INSERT); intent.putExtra(Words.WORD, word); intent.putExtra(Words.LOCALE, mLocale); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index b9ec4979d..01629fefa 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -360,8 +360,10 @@ public final class WordComposer { mDigitsCount = 0; mIsBatchMode = false; mTypedWord.setLength(0); + mCodePointSize = 0; mTrailingSingleQuotesCount = 0; mIsFirstCharCapitalized = false; + mCapitalizedMode = CAPS_MODE_OFF; refreshSize(); mAutoCorrection = null; mIsResumed = false; diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java index cfba28909..70bbf9dc0 100644 --- a/java/src/com/android/inputmethod/research/LogUnit.java +++ b/java/src/com/android/inputmethod/research/LogUnit.java @@ -60,6 +60,7 @@ import java.util.Map; private String mWord; private boolean mMayContainDigit; private boolean mIsPartOfMegaword; + private boolean mContainsCorrection; public LogUnit() { mLogStatementList = new ArrayList<LogStatement>(); @@ -274,6 +275,14 @@ import java.util.Map; return mMayContainDigit; } + public void setContainsCorrection() { + mContainsCorrection = true; + } + + public boolean containsCorrection() { + return mContainsCorrection; + } + public boolean isEmpty() { return mLogStatementList.isEmpty(); } @@ -301,6 +310,7 @@ import java.util.Map; true /* isPartOfMegaword */); newLogUnit.mWord = null; newLogUnit.mMayContainDigit = mMayContainDigit; + newLogUnit.mContainsCorrection = mContainsCorrection; // Purge the logStatements and associated data from this LogUnit. laterLogStatements.clear(); @@ -320,6 +330,7 @@ import java.util.Map; mTimeList.addAll(logUnit.mTimeList); mWord = null; mMayContainDigit = mMayContainDigit || logUnit.mMayContainDigit; + mContainsCorrection = mContainsCorrection || logUnit.mContainsCorrection; mIsPartOfMegaword = false; } } diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index a2bcf4441..a46216c5e 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -720,6 +720,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mCurrentLogUnit.setMayContainDigit(); } + private void setCurrentLogUnitContainsCorrection() { + mCurrentLogUnit.setContainsCorrection(); + } + /* package for test */ void commitCurrentLogUnit() { if (DEBUG) { Log.d(TAG, "commitCurrentLogUnit" + (mCurrentLogUnit.hasWord() ? @@ -850,7 +854,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mCurrentLogUnit.setWord(word); final boolean isDictionaryWord = dictionary != null && dictionary.isValidWord(word); - mStatistics.recordWordEntered(isDictionaryWord); + mStatistics.recordWordEntered(isDictionaryWord, mCurrentLogUnit.containsCorrection()); } final LogUnit newLogUnit = mCurrentLogUnit.splitByTime(maxTime); enqueueCommitText(word, isBatchMode); @@ -1181,6 +1185,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang scrubDigitsFromString(replacedWord), index, suggestion == null ? null : scrubbedWord, Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE); + researchLogger.setCurrentLogUnitContainsCorrection(); researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE, isBatchMode); researchLogger.mStatistics.recordManualSuggestion(SystemClock.uptimeMillis()); } @@ -1340,6 +1345,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang researchLogger.enqueueEvent(logUnit != null ? logUnit : researchLogger.mCurrentLogUnit, LOGSTATEMENT_LATINIME_REVERTCOMMIT, committedWord, originallyTypedWord, separatorString); + if (logUnit != null) { + logUnit.setContainsCorrection(); + } researchLogger.mStatistics.recordRevertCommit(SystemClock.uptimeMillis()); researchLogger.commitCurrentLogUnitAsWord(originallyTypedWord, Long.MAX_VALUE, isBatchMode); } @@ -1500,6 +1508,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang final ResearchLogger researchLogger = getInstance(); final String scrubbedWord = scrubDigitsFromString(committedWord); researchLogger.enqueueEvent(LOGSTATEMENT_COMMIT_PARTIAL_TEXT); + researchLogger.mStatistics.recordAutoCorrection(SystemClock.uptimeMillis()); researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, lastTimestampOfWordData, isBatchMode); } @@ -1740,7 +1749,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang "averageTimeDuringRepeatedDelete", "averageTimeAfterDelete", "dictionaryWordCount", "splitWordsCount", "gestureInputCount", "gestureCharsCount", "gesturesDeletedCount", "manualSuggestionsCount", - "revertCommitsCount"); + "revertCommitsCount", "correctedWordsCount", "autoCorrectionsCount"); private static void logStatistics() { final ResearchLogger researchLogger = getInstance(); final Statistics statistics = researchLogger.mStatistics; @@ -1754,6 +1763,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang statistics.mDictionaryWordCount, statistics.mSplitWordsCount, statistics.mGesturesInputCount, statistics.mGesturesCharsCount, statistics.mGesturesDeletedCount, statistics.mManualSuggestionsCount, - statistics.mRevertCommitsCount); + statistics.mRevertCommitsCount, statistics.mCorrectedWordsCount, + statistics.mAutoCorrectionsCount); } } diff --git a/java/src/com/android/inputmethod/research/Statistics.java b/java/src/com/android/inputmethod/research/Statistics.java index a9202651e..f0cb1578c 100644 --- a/java/src/com/android/inputmethod/research/Statistics.java +++ b/java/src/com/android/inputmethod/research/Statistics.java @@ -25,6 +25,7 @@ public class Statistics { private static final String TAG = Statistics.class.getSimpleName(); private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG; + // TODO: Cleanup comments to only including those giving meaningful information. // Number of characters entered during a typing session int mCharCount; // Number of letter characters entered during a typing session @@ -41,6 +42,8 @@ public class Statistics { int mDictionaryWordCount; // Number of words split and spaces automatically entered. int mSplitWordsCount; + // Number of words entered during a session. + int mCorrectedWordsCount; // Number of gestures that were input. int mGesturesInputCount; // Number of gestures that were deleted. @@ -49,6 +52,8 @@ public class Statistics { int mGesturesCharsCount; // Number of manual suggestions chosen. int mManualSuggestionsCount; + // Number of times that autocorrection was invoked. + int mAutoCorrectionsCount; // Number of times a commit was reverted in this session. int mRevertCommitsCount; // Whether the text field was empty upon editing @@ -113,10 +118,12 @@ public class Statistics { mWordCount = 0; mDictionaryWordCount = 0; mSplitWordsCount = 0; + mCorrectedWordsCount = 0; mGesturesInputCount = 0; mGesturesDeletedCount = 0; mManualSuggestionsCount = 0; mRevertCommitsCount = 0; + mAutoCorrectionsCount = 0; mIsEmptyUponStarting = true; mIsEmptinessStateKnown = false; mKeyCounter.reset(); @@ -152,11 +159,15 @@ public class Statistics { } } - public void recordWordEntered(final boolean isDictionaryWord) { + public void recordWordEntered(final boolean isDictionaryWord, + final boolean containsCorrection) { mWordCount++; if (isDictionaryWord) { mDictionaryWordCount++; } + if (containsCorrection) { + mCorrectedWordsCount++; + } } public void recordSplitWords() { @@ -184,6 +195,11 @@ public class Statistics { recordUserAction(time, false /* isDeletion */); } + public void recordAutoCorrection(final long time) { + mAutoCorrectionsCount++; + recordUserAction(time, false /* isDeletion */); + } + public void recordRevertCommit(final long time) { mRevertCommitsCount++; recordUserAction(time, true /* isDeletion */); diff --git a/native/jni/src/additional_proximity_chars.h b/native/jni/src/additional_proximity_chars.h index 21eb0bf8d..a88fd6cea 100644 --- a/native/jni/src/additional_proximity_chars.h +++ b/native/jni/src/additional_proximity_chars.h @@ -45,7 +45,7 @@ class AdditionalProximityChars { } public: - static int getAdditionalCharsSize(const char *localeStr, const int c) { + static int getAdditionalCharsSize(const char *const localeStr, const int c) { if (!isEnLocale(localeStr)) { return 0; } @@ -65,7 +65,7 @@ class AdditionalProximityChars { } } - static const int *getAdditionalChars(const char *localeStr, const int c) { + static const int *getAdditionalChars(const char *const localeStr, const int c) { if (!isEnLocale(localeStr)) { return 0; } diff --git a/native/jni/src/proximity_info.cpp b/native/jni/src/proximity_info.cpp index 9b99554d6..08646afa2 100644 --- a/native/jni/src/proximity_info.cpp +++ b/native/jni/src/proximity_info.cpp @@ -94,11 +94,6 @@ ProximityInfo::~ProximityInfo() { delete[] mProximityCharsArray; } -inline int ProximityInfo::getStartIndexFromCoordinates(const int x, const int y) const { - return ((y / CELL_HEIGHT) * GRID_WIDTH + (x / CELL_WIDTH)) - * MAX_PROXIMITY_CHARS_SIZE; -} - bool ProximityInfo::hasSpaceProximity(const int x, const int y) const { if (x < 0 || y < 0) { if (DEBUG_DICT) { @@ -109,7 +104,8 @@ bool ProximityInfo::hasSpaceProximity(const int x, const int y) const { return false; } - const int startIndex = getStartIndexFromCoordinates(x, y); + const int startIndex = ProximityInfoUtils::getStartIndexFromCoordinates( + MAX_PROXIMITY_CHARS_SIZE, x, y, CELL_HEIGHT, CELL_WIDTH, GRID_WIDTH); if (DEBUG_PROXIMITY_INFO) { AKLOGI("hasSpaceProximity: index %d, %d, %d", startIndex, x, y); } @@ -147,100 +143,6 @@ float ProximityInfo::getNormalizedSquaredDistanceFromCenterFloatG( return getSquaredDistanceFloat(centerX, centerY, touchX, touchY) / SQUARE_FLOAT(keyWidth); } -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]; - 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); - const int dx = x - edgeX; - const int dy = y - edgeY; - return dx * dx + dy * dy; -} - -void ProximityInfo::calculateNearbyKeyCodes( - const int x, const int y, const int primaryKey, int *inputCodes) const { - int *proximityCharsArray = mProximityCharsArray; - int insertPos = 0; - inputCodes[insertPos++] = primaryKey; - const int startIndex = getStartIndexFromCoordinates(x, y); - if (startIndex >= 0) { - for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) { - const int c = proximityCharsArray[startIndex + i]; - if (c < KEYCODE_SPACE || c == primaryKey) { - continue; - } - const int keyIndex = getKeyIndexOf(c); - const bool onKey = isOnKey(keyIndex, x, y); - const int distance = squaredDistanceToEdge(keyIndex, x, y); - if (onKey || distance < MOST_COMMON_KEY_WIDTH_SQUARE) { - inputCodes[insertPos++] = c; - 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 int *additionalProximityChars = - AdditionalProximityChars::getAdditionalChars(mLocaleStr, primaryKey); - for (int j = 0; j < additionalProximitySize; ++j) { - const int ac = additionalProximityChars[j]; - int k = 0; - for (; k < insertPos; ++k) { - if (ac == inputCodes[k]) { - break; - } - } - if (k < insertPos) { - continue; - } - inputCodes[insertPos++] = ac; - if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) { - if (DEBUG_DICT) { - ASSERT(false); - } - return; - } - } - } - } - // Add a delimiter for the proximity characters - for (int i = insertPos; i < MAX_PROXIMITY_CHARS_SIZE; ++i) { - inputCodes[i] = NOT_A_CODE_POINT; - } -} - -int ProximityInfo::getKeyIndexOf(const int c) const { - if (KEY_COUNT == 0) { - // We do not have the coordinate data - return NOT_AN_INDEX; - } - if (c == NOT_A_CODE_POINT) { - return NOT_AN_INDEX; - } - const int lowerCode = toLowerCase(c); - hash_map_compat<int, int>::const_iterator mapPos = mCodeToKeyMap.find(lowerCode); - if (mapPos != mCodeToKeyMap.end()) { - return mapPos->second; - } - return NOT_AN_INDEX; -} - int ProximityInfo::getCodePointOf(const int keyIndex) const { if (keyIndex < 0 || keyIndex >= KEY_COUNT) { return NOT_A_CODE_POINT; @@ -269,11 +171,13 @@ void ProximityInfo::initializeG() { } int ProximityInfo::getKeyCenterXOfCodePointG(int charCode) const { - return getKeyCenterXOfKeyIdG(getKeyIndexOf(charCode)); + return getKeyCenterXOfKeyIdG( + ProximityInfoUtils::getKeyIndexOf(KEY_COUNT, charCode, &mCodeToKeyMap)); } int ProximityInfo::getKeyCenterYOfCodePointG(int charCode) const { - return getKeyCenterYOfKeyIdG(getKeyIndexOf(charCode)); + return getKeyCenterYOfKeyIdG( + ProximityInfoUtils::getKeyIndexOf(KEY_COUNT, charCode, &mCodeToKeyMap)); } int ProximityInfo::getKeyCenterXOfKeyIdG(int keyId) const { diff --git a/native/jni/src/proximity_info.h b/native/jni/src/proximity_info.h index d00228359..6be42a057 100644 --- a/native/jni/src/proximity_info.h +++ b/native/jni/src/proximity_info.h @@ -20,6 +20,7 @@ #include "defines.h" #include "hash_map_compat.h" #include "jni.h" +#include "proximity_info_utils.h" namespace latinime { @@ -40,7 +41,6 @@ class ProximityInfo { float getNormalizedSquaredDistanceFromCenterFloatG( const int keyId, const int x, const int y) const; bool sameAsTyped(const unsigned short *word, int length) const; - int getKeyIndexOf(const int c) const; int getCodePointOf(const int keyIndex) const; bool hasSweetSpotData(const int keyIndex) const { // When there are no calibration data for a key, @@ -109,23 +109,26 @@ class ProximityInfo { int getKeyCenterYOfKeyIdG(int keyId) const; int getKeyKeyDistanceG(int keyId0, int keyId1) const; + void initializeProximities(const int *const inputCodes, const int *const inputXCoordinates, + const int *const inputYCoordinates, const int inputSize, int *allInputCodes) const { + ProximityInfoUtils::initializeProximities(inputCodes, inputXCoordinates, inputYCoordinates, + inputSize, mKeyXCoordinates, mKeyYCoordinates, mKeyWidths, mKeyHeights, + mProximityCharsArray, MAX_PROXIMITY_CHARS_SIZE, CELL_HEIGHT, CELL_WIDTH, + GRID_WIDTH, MOST_COMMON_KEY_WIDTH, KEY_COUNT, mLocaleStr, &mCodeToKeyMap, + allInputCodes); + } + + int getKeyIndexOf(const int c) const { + return ProximityInfoUtils::getKeyIndexOf(KEY_COUNT, c, &mCodeToKeyMap); + } + private: DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfo); static const float NOT_A_DISTANCE_FLOAT; - int getStartIndexFromCoordinates(const int x, const int y) const; void initializeG(); float calculateNormalizedSquaredDistance(const int keyIndex, const int inputIndex) const; bool hasInputCoordinates() const; - int squaredDistanceToEdge(const int keyId, const int x, const int y) const; - bool 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]; - const int right = left + mKeyWidths[keyId] + 1; - const int bottom = top + mKeyHeights[keyId]; - return left < right && top < bottom && x >= left && x < right && y >= top && y < bottom; - } const int MAX_PROXIMITY_CHARS_SIZE; const int GRID_WIDTH; diff --git a/native/jni/src/proximity_info_state.cpp b/native/jni/src/proximity_info_state.cpp index aa029297e..1e1413a5d 100644 --- a/native/jni/src/proximity_info_state.cpp +++ b/native/jni/src/proximity_info_state.cpp @@ -53,33 +53,11 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi mGridHeight = proximityInfo->getGridWidth(); mGridWidth = proximityInfo->getGridHeight(); - memset(mInputCodes, 0, sizeof(mInputCodes)); + memset(mInputProximities, 0, sizeof(mInputProximities)); if (!isGeometric && pointerId == 0) { - // Initialize - // - mInputCodes - // - mNormalizedSquaredDistances - // TODO: Merge - for (int i = 0; i < inputSize; ++i) { - const int primaryKey = inputCodes[i]; - const int x = xCoordinates[i]; - const int y = yCoordinates[i]; - int *proximities = &mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL]; - mProximityInfo->calculateNearbyKeyCodes(x, y, primaryKey, proximities); - } - - if (DEBUG_PROXIMITY_CHARS) { - for (int i = 0; i < inputSize; ++i) { - AKLOGI("---"); - for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL; ++j) { - int icc = mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j]; - int icfjc = inputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j]; - icc += 0; - icfjc += 0; - AKLOGI("--- (%d)%c,%c", i, icc, icfjc); AKLOGI("--- A<%d>,B<%d>", icc, icfjc); - } - } - } + mProximityInfo->initializeProximities(inputCodes, xCoordinates, yCoordinates, + inputSize, mInputProximities); } /////////////////////// diff --git a/native/jni/src/proximity_info_state.h b/native/jni/src/proximity_info_state.h index d747bae2a..bc2cf505c 100644 --- a/native/jni/src/proximity_info_state.h +++ b/native/jni/src/proximity_info_state.h @@ -61,7 +61,7 @@ class ProximityInfoState { mInputIndice(), mLengthCache(), mBeelineSpeedPercentiles(), mDistanceCache_G(), mSpeedRates(), mDirections(), mCharProbabilities(), mNearKeysVector(), mSearchKeysVector(), mTouchPositionCorrectionEnabled(false), mSampledInputSize(0) { - memset(mInputCodes, 0, sizeof(mInputCodes)); + memset(mInputProximities, 0, sizeof(mInputProximities)); memset(mNormalizedSquaredDistances, 0, sizeof(mNormalizedSquaredDistances)); memset(mPrimaryInputWord, 0, sizeof(mPrimaryInputWord)); } @@ -117,12 +117,12 @@ class ProximityInfoState { if (length != mSampledInputSize) { return false; } - const int *inputCodes = mInputCodes; + const int *inputProximities = mInputProximities; while (length--) { - if (*inputCodes != *word) { + if (*inputProximities != *word) { return false; } - inputCodes += MAX_PROXIMITY_CHARS_SIZE_INTERNAL; + inputProximities += MAX_PROXIMITY_CHARS_SIZE_INTERNAL; word++; } return true; @@ -229,7 +229,7 @@ class ProximityInfoState { } inline const int *getProximityCodePointsAt(const int index) const { - return mInputCodes + (index * MAX_PROXIMITY_CHARS_SIZE_INTERNAL); + return mInputProximities + (index * MAX_PROXIMITY_CHARS_SIZE_INTERNAL); } float updateNearKeysDistances(const int x, const int y, @@ -289,7 +289,7 @@ class ProximityInfoState { // inputs including the current input point. std::vector<NearKeycodesSet> mSearchKeysVector; bool mTouchPositionCorrectionEnabled; - int mInputCodes[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH]; + int mInputProximities[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH]; int mNormalizedSquaredDistances[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH]; int mSampledInputSize; int mPrimaryInputWord[MAX_WORD_LENGTH]; diff --git a/native/jni/src/proximity_info_utils.h b/native/jni/src/proximity_info_utils.h new file mode 100644 index 000000000..b9348d885 --- /dev/null +++ b/native/jni/src/proximity_info_utils.h @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef LATINIME_PROXIMITY_INFO_UTILS_H +#define LATINIME_PROXIMITY_INFO_UTILS_H + +#include "additional_proximity_chars.h" +#include "char_utils.h" +#include "defines.h" +#include "hash_map_compat.h" + +namespace latinime { +class ProximityInfoUtils { + public: + static int getKeyIndexOf(const int keyCount, const int c, + const hash_map_compat<int, int> *const codeToKeyMap) { + if (keyCount == 0) { + // We do not have the coordinate data + return NOT_AN_INDEX; + } + if (c == NOT_A_CODE_POINT) { + return NOT_AN_INDEX; + } + const int lowerCode = toLowerCase(c); + hash_map_compat<int, int>::const_iterator mapPos = codeToKeyMap->find(lowerCode); + if (mapPos != codeToKeyMap->end()) { + return mapPos->second; + } + return NOT_AN_INDEX; + } + + static void initializeProximities(const int *const inputCodes, + const int *const inputXCoordinates, const int *const inputYCoordinates, + const int inputSize, const int *const keyXCoordinates, + const int *const keyYCoordinates, const int *const keyWidths, const int *keyHeights, + const int *const proximityCharsArray, const int maxProximityCharsSize, + const int cellHeight, const int cellWidth, const int gridWidth, + const int mostCommonKeyWidth, const int keyCount, const char *const localeStr, + const hash_map_compat<int, int> *const codeToKeyMap, int *inputProximities) { + // Initialize + // - mInputCodes + // - mNormalizedSquaredDistances + // TODO: Merge + for (int i = 0; i < inputSize; ++i) { + const int primaryKey = inputCodes[i]; + const int x = inputXCoordinates[i]; + const int y = inputYCoordinates[i]; + int *proximities = &inputProximities[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL]; + calculateProximities(keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, + proximityCharsArray, maxProximityCharsSize, cellHeight, cellWidth, gridWidth, + mostCommonKeyWidth, keyCount, x, y, primaryKey, localeStr, codeToKeyMap, + proximities); + } + + if (DEBUG_PROXIMITY_CHARS) { + for (int i = 0; i < inputSize; ++i) { + AKLOGI("---"); + for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL; ++j) { + int proximityChar = + inputProximities[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j]; + proximityChar += 0; + AKLOGI("--- (%d)%c", i, proximityChar); + } + } + } + } + + AK_FORCE_INLINE static int getStartIndexFromCoordinates(const int maxProximityCharsSize, + const int x, const int y, const int cellHeight, const int cellWidth, + const int gridWidth) { + return ((y / cellHeight) * gridWidth + (x / cellWidth)) * maxProximityCharsSize; + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfoUtils); + + static bool isOnKey(const int *const keyXCoordinates, const int *const keyYCoordinates, + const int *const keyWidths, const int *keyHeights, 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 = keyXCoordinates[keyId]; + const int top = keyYCoordinates[keyId]; + const int right = left + keyWidths[keyId] + 1; + const int bottom = top + keyHeights[keyId]; + return left < right && top < bottom && x >= left && x < right && y >= top && y < bottom; + } + + static void calculateProximities( + const int *const keyXCoordinates, const int *const keyYCoordinates, + const int *const keyWidths, const int *keyHeights, + const int *const proximityCharsArray, + const int maxProximityCharsSize, const int cellHeight, const int cellWidth, + const int gridWidth, const int mostCommonKeyWidth, const int keyCount, + const int x, const int y, const int primaryKey, const char *const localeStr, + const hash_map_compat<int, int> *const codeToKeyMap, int *proximities) { + const int mostCommonKeyWidthSquare = mostCommonKeyWidth * mostCommonKeyWidth; + int insertPos = 0; + proximities[insertPos++] = primaryKey; + const int startIndex = getStartIndexFromCoordinates( + maxProximityCharsSize, x, y, cellHeight, cellWidth, gridWidth); + if (startIndex >= 0) { + for (int i = 0; i < maxProximityCharsSize; ++i) { + const int c = proximityCharsArray[startIndex + i]; + if (c < KEYCODE_SPACE || c == primaryKey) { + continue; + } + const int keyIndex = getKeyIndexOf(keyCount, c, codeToKeyMap); + const bool onKey = isOnKey(keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, + keyIndex, x, y); + const int distance = squaredLengthToEdge(keyXCoordinates, keyYCoordinates, + keyWidths, keyHeights, keyIndex, x, y); + if (onKey || distance < mostCommonKeyWidthSquare) { + proximities[insertPos++] = c; + if (insertPos >= maxProximityCharsSize) { + if (DEBUG_DICT) { + ASSERT(false); + } + return; + } + } + } + const int additionalProximitySize = + AdditionalProximityChars::getAdditionalCharsSize(localeStr, primaryKey); + if (additionalProximitySize > 0) { + proximities[insertPos++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE; + if (insertPos >= maxProximityCharsSize) { + if (DEBUG_DICT) { + ASSERT(false); + } + return; + } + + const int *additionalProximityChars = + AdditionalProximityChars::getAdditionalChars(localeStr, primaryKey); + for (int j = 0; j < additionalProximitySize; ++j) { + const int ac = additionalProximityChars[j]; + int k = 0; + for (; k < insertPos; ++k) { + if (ac == proximities[k]) { + break; + } + } + if (k < insertPos) { + continue; + } + proximities[insertPos++] = ac; + if (insertPos >= maxProximityCharsSize) { + if (DEBUG_DICT) { + ASSERT(false); + } + return; + } + } + } + } + // Add a delimiter for the proximity characters + for (int i = insertPos; i < maxProximityCharsSize; ++i) { + proximities[i] = NOT_A_CODE_POINT; + } + } + + static int squaredLengthToEdge(const int *const keyXCoordinates, + const int *const keyYCoordinates, const int *const keyWidths, const int *keyHeights, + const int keyId, const int x, const int y) { + // NOT_A_ID is -1, but return whenever < 0 just in case + if (keyId < 0) return MAX_POINT_TO_KEY_LENGTH; + const int left = keyXCoordinates[keyId]; + const int top = keyYCoordinates[keyId]; + const int right = left + keyWidths[keyId]; + const int bottom = top + keyHeights[keyId]; + const int edgeX = x < left ? left : (x > right ? right : x); + const int edgeY = y < top ? top : (y > bottom ? bottom : y); + const int dx = x - edgeX; + const int dy = y - edgeY; + return dx * dx + dy * dy; + } +}; +} // namespace latinime +#endif // LATINIME_PROXIMITY_INFO_UTILS_H diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java index a1ceb8e2e..74ff87977 100644 --- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java +++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java @@ -150,59 +150,6 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase { pressAndReleaseKey(CODE_SPACE, SYMBOLS_SHIFTED, ALPHABET_SHIFT_LOCKED); } - // Automatic switch back to alphabet by registered letters. - public void testSwitchBackChar() { - // Set switch back chars. - final String switchBackSymbols = "'"; - final int switchBackCode = switchBackSymbols.codePointAt(0); - setLayoutSwitchBackSymbols(switchBackSymbols); - loadKeyboard(ALPHABET_UNSHIFTED); - - // Press/release "?123" key, enter into symbols. - pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); - // Enter symbol letter. - pressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); - // Enter switch back letter, switch back to alphabet. - pressAndReleaseKey(switchBackCode, SYMBOLS_UNSHIFTED, ALPHABET_UNSHIFTED); - - // Press/release "?123" key, enter into symbols. - pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); - // Press/release "=\<" key, enter into symbols shifted. - pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); - // Enter symbol shift letter. - pressAndReleaseKey('~', SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); - // Enter switch abck letter, switch back to alphabet. - pressAndReleaseKey(switchBackCode, SYMBOLS_SHIFTED, ALPHABET_UNSHIFTED); - } - - // Automatic switch back to alphabet shift locked by registered letters. - public void testSwitchBackCharShiftLocked() { - // Set switch back chars. - final String switchBackSymbols = "'"; - final int switchBackCode = switchBackSymbols.codePointAt(0); - setLayoutSwitchBackSymbols(switchBackSymbols); - loadKeyboard(ALPHABET_UNSHIFTED); - // Long press shift key, enter alphabet shift locked. - longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED, - ALPHABET_SHIFT_LOCKED); - - // Press/release "?123" key, enter into symbols. - pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); - // Enter symbol letter. - pressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); - // Enter switch back letter, switch back to alphabet shift locked. - pressAndReleaseKey(switchBackCode, SYMBOLS_UNSHIFTED, ALPHABET_SHIFT_LOCKED); - - // Press/release "?123" key, enter into symbols. - pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); - // Press/release "=\<" key, enter into symbols shifted. - pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); - // Enter symbol shift letter. - pressAndReleaseKey(CODE_SPACE, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); - // Enter switch back letter, switch back to alphabet shift locked. - pressAndReleaseKey(switchBackCode, SYMBOLS_SHIFTED, ALPHABET_SHIFT_LOCKED); - } - // Automatic upper case test public void testAutomaticUpperCase() { // Set capitalize the first character of all words mode. diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java index c75f8269a..08199a074 100644 --- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java +++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java @@ -22,8 +22,6 @@ public class KeyboardStateTestsBase extends AndroidTestCase implements MockKeyboardSwitcher.MockConstants { protected MockKeyboardSwitcher mSwitcher; - private String mLayoutSwitchBackSymbols = ""; - @Override protected void setUp() throws Exception { super.setUp(); @@ -34,88 +32,86 @@ public class KeyboardStateTestsBase extends AndroidTestCase loadKeyboard(ALPHABET_UNSHIFTED); } - public void setAutoCapsMode(int autoCaps) { + public void setAutoCapsMode(final int autoCaps) { mSwitcher.setAutoCapsMode(autoCaps); } - public void setLayoutSwitchBackSymbols(String switchBackSymbols) { - mLayoutSwitchBackSymbols = switchBackSymbols; - } - - private static void assertLayout(String message, int expected, int actual) { + private static void assertLayout(final String message, final int expected, final int actual) { assertTrue(message + ": expected=" + MockKeyboardSwitcher.getLayoutName(expected) + " actual=" + MockKeyboardSwitcher.getLayoutName(actual), expected == actual); } - public void updateShiftState(int afterUpdate) { + public void updateShiftState(final int afterUpdate) { mSwitcher.updateShiftState(); assertLayout("afterUpdate", afterUpdate, mSwitcher.getLayoutId()); } - public void loadKeyboard(int afterLoad) { - mSwitcher.loadKeyboard(mLayoutSwitchBackSymbols); + public void loadKeyboard(final int afterLoad) { + mSwitcher.loadKeyboard(); mSwitcher.updateShiftState(); assertLayout("afterLoad", afterLoad, mSwitcher.getLayoutId()); } - public void rotateDevice(int afterRotate) { + public void rotateDevice(final int afterRotate) { mSwitcher.saveKeyboardState(); - mSwitcher.loadKeyboard(mLayoutSwitchBackSymbols); + mSwitcher.loadKeyboard(); assertLayout("afterRotate", afterRotate, mSwitcher.getLayoutId()); } - private void pressKeyWithoutTimerExpire(int code, boolean isSinglePointer, int afterPress) { + private void pressKeyWithoutTimerExpire(final int code, final boolean isSinglePointer, + final int afterPress) { mSwitcher.onPressKey(code, isSinglePointer); assertLayout("afterPress", afterPress, mSwitcher.getLayoutId()); } - public void pressKey(int code, int afterPress) { + public void pressKey(final int code, final int afterPress) { mSwitcher.expireDoubleTapTimeout(); pressKeyWithoutTimerExpire(code, true, afterPress); } - public void releaseKey(int code, int afterRelease) { + public void releaseKey(final int code, final int afterRelease) { mSwitcher.onCodeInput(code, SINGLE); mSwitcher.onReleaseKey(code, NOT_SLIDING); assertLayout("afterRelease", afterRelease, mSwitcher.getLayoutId()); } - public void pressAndReleaseKey(int code, int afterPress, int afterRelease) { + public void pressAndReleaseKey(final int code, final int afterPress, final int afterRelease) { pressKey(code, afterPress); releaseKey(code, afterRelease); } - public void chordingPressKey(int code, int afterPress) { + public void chordingPressKey(final int code, final int afterPress) { mSwitcher.expireDoubleTapTimeout(); pressKeyWithoutTimerExpire(code, false, afterPress); } - public void chordingReleaseKey(int code, int afterRelease) { + public void chordingReleaseKey(final int code, final int afterRelease) { mSwitcher.onCodeInput(code, MULTI); mSwitcher.onReleaseKey(code, NOT_SLIDING); assertLayout("afterRelease", afterRelease, mSwitcher.getLayoutId()); } - public void chordingPressAndReleaseKey(int code, int afterPress, int afterRelease) { + public void chordingPressAndReleaseKey(final int code, final int afterPress, + final int afterRelease) { chordingPressKey(code, afterPress); chordingReleaseKey(code, afterRelease); } - public void pressAndSlideFromKey(int code, int afterPress, int afterSlide) { + public void pressAndSlideFromKey(final int code, final int afterPress, final int afterSlide) { pressKey(code, afterPress); mSwitcher.onReleaseKey(code, SLIDING); assertLayout("afterSlide", afterSlide, mSwitcher.getLayoutId()); } - public void longPressKey(int code, int afterPress, int afterLongPress) { + public void longPressKey(final int code, final int afterPress, final int afterLongPress) { pressKey(code, afterPress); mSwitcher.onLongPressTimeout(code); assertLayout("afterLongPress", afterLongPress, mSwitcher.getLayoutId()); } - public void longPressAndReleaseKey(int code, int afterPress, int afterLongPress, - int afterRelease) { + public void longPressAndReleaseKey(final int code, final int afterPress, + final int afterLongPress, final int afterRelease) { longPressKey(code, afterPress, afterLongPress); releaseKey(code, afterRelease); } diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java index 0213744fb..ac3558521 100644 --- a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java +++ b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java @@ -61,7 +61,7 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions { return mLayout; } - public static String getLayoutName(int layoutId) { + public static String getLayoutName(final int layoutId) { switch (layoutId) { case MockConstants.ALPHABET_UNSHIFTED: return "ALPHABET_UNSHIFTED"; case MockConstants.ALPHABET_MANUAL_SHIFTED: return "ALPHABET_MANUAL_SHIFTED"; @@ -74,7 +74,7 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions { } } - public void setAutoCapsMode(int autoCaps) { + public void setAutoCapsMode(final int autoCaps) { mAutoCapsMode = autoCaps; mAutoCapsState = autoCaps; } @@ -139,7 +139,7 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions { } @Override - public void startLongPressTimer(int code) { + public void startLongPressTimer(final int code) { mLongPressTimeoutCode = code; } @@ -149,11 +149,11 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions { } @Override - public void hapticAndAudioFeedback(int code) { + public void hapticAndAudioFeedback(final int code) { // Nothing to do. } - public void onLongPressTimeout(int code) { + public void onLongPressTimeout(final int code) { // TODO: Handle simultaneous long presses. if (mLongPressTimeoutCode == code) { mLongPressTimeoutCode = 0; @@ -165,26 +165,26 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions { mState.onUpdateShiftState(mAutoCapsState); } - public void loadKeyboard(String layoutSwitchBackSymbols) { - mState.onLoadKeyboard(layoutSwitchBackSymbols); + public void loadKeyboard() { + mState.onLoadKeyboard(); } public void saveKeyboardState() { mState.onSaveKeyboardState(); } - public void onPressKey(int code, boolean isSinglePointer) { + public void onPressKey(final int code, final boolean isSinglePointer) { mState.onPressKey(code, isSinglePointer, mAutoCapsState); } - public void onReleaseKey(int code, boolean withSliding) { + public void onReleaseKey(final int code, final boolean withSliding) { mState.onReleaseKey(code, withSliding); if (mLongPressTimeoutCode == code) { mLongPressTimeoutCode = 0; } } - public void onCodeInput(int code, boolean isSinglePointer) { + public void onCodeInput(final int code, final boolean isSinglePointer) { if (mAutoCapsMode == MockConstants.CAP_MODE_WORDS) { if (Constants.isLetterCode(code)) { mAutoCapsState = (code == MockConstants.CODE_AUTO_CAPS_TRIGGER) @@ -196,7 +196,7 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions { mState.onCodeInput(code, isSinglePointer, mAutoCapsState); } - public void onCancelInput(boolean isSinglePointer) { + public void onCancelInput(final boolean isSinglePointer) { mState.onCancelInput(isSinglePointer); } }
\ No newline at end of file |