Loading java/src/com/android/inputmethod/latin/Suggest.java +8 −8 Original line number Diff line number Diff line Loading @@ -110,7 +110,7 @@ public final class Suggest { wordComposer, prevWordsInfo, proximityInfo, blockOffensiveWords, additionalFeaturesOptions, SESSION_TYPING, rawSuggestions); final boolean isFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); final boolean isOnlyFirstCharCapitalized = wordComposer.isOnlyFirstCharCapitalized(); // If resumed, then we don't want to upcase everything: resuming on a fully-capitalized // words is rarely done to switch to another fully-capitalized word, but usually to a // normal, non-capitalized suggestion. Loading @@ -122,7 +122,7 @@ public final class Suggest { } else { final SuggestedWordInfo firstSuggestedWordInfo = getTransformedSuggestedWordInfo( suggestionResults.first(), suggestionResults.mLocale, isAllUpperCase, isFirstCharCapitalized, trailingSingleQuotesCount); isOnlyFirstCharCapitalized, trailingSingleQuotesCount); firstSuggestion = firstSuggestedWordInfo.mWord; if (!firstSuggestedWordInfo.isKindOf(SuggestedWordInfo.KIND_WHITELIST)) { whitelistedWord = null; Loading @@ -142,7 +142,7 @@ public final class Suggest { final boolean allowsToBeAutoCorrected = (null != whitelistedWord && !whitelistedWord.equals(typedWord)) || (consideredWord.length() > 1 && !mDictionaryFacilitator.isValidWord( consideredWord, wordComposer.isFirstCharCapitalized()) consideredWord, isOnlyFirstCharCapitalized) && !typedWord.equals(firstSuggestion)); final boolean hasAutoCorrection; Loading Loading @@ -173,12 +173,12 @@ public final class Suggest { final ArrayList<SuggestedWordInfo> suggestionsContainer = new ArrayList<>(suggestionResults); final int suggestionsCount = suggestionsContainer.size(); if (isFirstCharCapitalized || isAllUpperCase || 0 != trailingSingleQuotesCount) { if (isOnlyFirstCharCapitalized || isAllUpperCase || 0 != trailingSingleQuotesCount) { for (int i = 0; i < suggestionsCount; ++i) { final SuggestedWordInfo wordInfo = suggestionsContainer.get(i); final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo( wordInfo, suggestionResults.mLocale, isAllUpperCase, isFirstCharCapitalized, trailingSingleQuotesCount); wordInfo, suggestionResults.mLocale, isAllUpperCase, isOnlyFirstCharCapitalized, trailingSingleQuotesCount); suggestionsContainer.set(i, transformedWordInfo); } } Loading Loading @@ -292,11 +292,11 @@ public final class Suggest { /* package for test */ static SuggestedWordInfo getTransformedSuggestedWordInfo( final SuggestedWordInfo wordInfo, final Locale locale, final boolean isAllUpperCase, final boolean isFirstCharCapitalized, final int trailingSingleQuotesCount) { final boolean isOnlyFirstCharCapitalized, final int trailingSingleQuotesCount) { final StringBuilder sb = new StringBuilder(wordInfo.mWord.length()); if (isAllUpperCase) { sb.append(wordInfo.mWord.toUpperCase(locale)); } else if (isFirstCharCapitalized) { } else if (isOnlyFirstCharCapitalized) { sb.append(StringUtils.capitalizeFirstCodePoint(wordInfo.mWord, locale)); } else { sb.append(wordInfo.mWord); Loading java/src/com/android/inputmethod/latin/WordComposer.java +19 −45 Original line number Diff line number Diff line Loading @@ -45,9 +45,6 @@ public final class WordComposer { // The list of events that served to compose this string. private final ArrayList<Event> mEvents; private final InputPointers mInputPointers = new InputPointers(MAX_WORD_LENGTH); // The information of previous words (before the composing word). Must not be null. Used as // context for suggestions. private PrevWordsInfo mPrevWordsInfo; private String mAutoCorrection; private boolean mIsResumed; private boolean mIsBatchMode; Loading @@ -72,9 +69,9 @@ public final class WordComposer { private int mCursorPositionWithinWord; /** * Whether the user chose to capitalize the first char of the word. * Whether the composing word has the only first char capitalized. */ private boolean mIsFirstCharCapitalized; private boolean mIsOnlyFirstCharCapitalized; public WordComposer() { mCombinerChain = new CombinerChain(""); Loading @@ -84,7 +81,6 @@ public final class WordComposer { mIsBatchMode = false; mCursorPositionWithinWord = 0; mRejectedBatchModeSuggestion = null; mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO; refreshTypedWordCache(); } Loading @@ -111,12 +107,11 @@ public final class WordComposer { mAutoCorrection = null; mCapsCount = 0; mDigitsCount = 0; mIsFirstCharCapitalized = false; mIsOnlyFirstCharCapitalized = false; mIsResumed = false; mIsBatchMode = false; mCursorPositionWithinWord = 0; mRejectedBatchModeSuggestion = null; mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO; refreshTypedWordCache(); } Loading Loading @@ -178,12 +173,6 @@ public final class WordComposer { return mInputPointers; } private static boolean isFirstCharCapitalized(final int index, final int codePoint, final boolean previous) { if (index == 0) return Character.isUpperCase(codePoint); return previous && !Character.isUpperCase(codePoint); } /** * Process an input event. * Loading @@ -203,7 +192,7 @@ public final class WordComposer { mCursorPositionWithinWord = mCodePointSize; // We may have deleted the last one. if (0 == mCodePointSize) { mIsFirstCharCapitalized = false; mIsOnlyFirstCharCapitalized = false; } if (Constants.CODE_DELETE != event.mKeyCode) { if (newIndex < MAX_WORD_LENGTH) { Loading @@ -215,8 +204,12 @@ public final class WordComposer { mInputPointers.addPointerAt(newIndex, keyX, keyY, 0, 0); } } mIsFirstCharCapitalized = isFirstCharCapitalized( newIndex, primaryCode, mIsFirstCharCapitalized); if (0 == newIndex) { mIsOnlyFirstCharCapitalized = Character.isUpperCase(primaryCode); } else { mIsOnlyFirstCharCapitalized = mIsOnlyFirstCharCapitalized && !Character.isUpperCase(primaryCode); } if (Character.isUpperCase(primaryCode)) mCapsCount++; if (Character.isDigit(primaryCode)) mDigitsCount++; } Loading Loading @@ -296,10 +289,8 @@ public final class WordComposer { * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. * @param codePoints the code points to set as the composing word. * @param coordinates the x, y coordinates of the key in the CoordinateUtils format * @param prevWordsInfo the information of previous words, to use as context for suggestions */ public void setComposingWord(final int[] codePoints, final int[] coordinates, final PrevWordsInfo prevWordsInfo) { public void setComposingWord(final int[] codePoints, final int[] coordinates) { reset(); final int length = codePoints.length; for (int i = 0; i < length; ++i) { Loading @@ -308,7 +299,6 @@ public final class WordComposer { CoordinateUtils.yFromArray(coordinates, i))); } mIsResumed = true; mPrevWordsInfo = prevWordsInfo; } /** Loading @@ -319,16 +309,13 @@ public final class WordComposer { return mTypedWordCache.toString(); } public PrevWordsInfo getPrevWordsInfoForSuggestion() { return mPrevWordsInfo; } /** * Whether or not the user typed a capital letter as the first letter in the word * Whether or not the user typed a capital letter as the first letter in the word, and no * other letter is capitalized * @return capitalization preference */ public boolean isFirstCharCapitalized() { return mIsFirstCharCapitalized; public boolean isOnlyFirstCharCapitalized() { return mIsOnlyFirstCharCapitalized; } /** Loading Loading @@ -364,7 +351,7 @@ public final class WordComposer { } /** * Saves the caps mode and the previous word at the start of composing. * Saves the caps mode at the start of composing. * * WordComposer needs to know about the caps mode for several reasons. The first is, we need * to know after the fact what the reason was, to register the correct form into the user Loading @@ -373,12 +360,9 @@ public final class WordComposer { * Also, batch input needs to know about the current caps mode to display correctly * capitalized suggestions. * @param mode the mode at the time of start * @param prevWordsInfo the information of previous words */ public void setCapitalizedModeAndPreviousWordAtStartComposingTime(final int mode, final PrevWordsInfo prevWordsInfo) { public void setCapitalizedModeAtStartComposingTime(final int mode) { mCapitalizedMode = mode; mPrevWordsInfo = prevWordsInfo; } /** Loading Loading @@ -429,11 +413,10 @@ public final class WordComposer { mCapsCount = 0; mDigitsCount = 0; mIsBatchMode = false; mPrevWordsInfo = new PrevWordsInfo(committedWord.toString()); mCombinerChain.reset(); mEvents.clear(); mCodePointSize = 0; mIsFirstCharCapitalized = false; mIsOnlyFirstCharCapitalized = false; mCapitalizedMode = CAPS_MODE_OFF; refreshTypedWordCache(); mAutoCorrection = null; Loading @@ -443,15 +426,7 @@ public final class WordComposer { return lastComposedWord; } // Call this when the recorded previous word should be discarded. This is typically called // when the user inputs a separator that's not whitespace (including the case of the // double-space-to-period feature). public void discardPreviousWordForSuggestion() { mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO; } public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord, final PrevWordsInfo prevWordsInfo) { public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) { mEvents.clear(); Collections.copy(mEvents, lastComposedWord.mEvents); mInputPointers.set(lastComposedWord.mInputPointers); Loading @@ -462,7 +437,6 @@ public final class WordComposer { mCursorPositionWithinWord = mCodePointSize; mRejectedBatchModeSuggestion = null; mIsResumed = true; mPrevWordsInfo = prevWordsInfo; } public boolean isBatchMode() { Loading java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +10 −44 Original line number Diff line number Diff line Loading @@ -544,11 +544,8 @@ public final class InputLogic { } } mConnection.endBatchEdit(); mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode()), // Prev word is 1st word before cursor getPrevWordsInfoFromNthPreviousWordForSuggestion( settingsValues.mSpacingAndPunctuations, 1 /* nthPreviousWord */)); mWordComposer.setCapitalizedModeAtStartComposingTime( getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode())); } /* The sequence number member is only used in onUpdateBatchInput. It is increased each time Loading Loading @@ -584,10 +581,8 @@ public final class InputLogic { mSpaceState = SpaceState.PHANTOM; keyboardSwitcher.requestUpdatingShiftState( getCurrentAutoCapsState(settingsValues), getCurrentRecapitalizeState()); mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode()), new PrevWordsInfo(commitParts[0])); mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode( settingsValues, keyboardSwitcher.getKeyboardShiftMode())); ++mAutoCommitSequenceNumber; } } Loading Loading @@ -724,15 +719,7 @@ public final class InputLogic { mWordComposer.processEvent(inputTransaction.mEvent); // If it's the first letter, make note of auto-caps state if (mWordComposer.isSingleLetter()) { // We pass 2 to getPreviousWordForSuggestion when the previous code point is a word // connector. Otherwise, we pass 1 because we were not composing a word yet, so the // word we want is the 1st word before the cursor. mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( inputTransaction.mShiftState, getPrevWordsInfoFromNthPreviousWordForSuggestion( settingsValues.mSpacingAndPunctuations, settingsValues.mSpacingAndPunctuations.isWordConnector( mConnection.getCodePointBeforeCursor()) ? 2 : 1)); mWordComposer.setCapitalizedModeAtStartComposingTime(inputTransaction.mShiftState); } mConnection.setComposingText(getTextWithUnderline( mWordComposer.getTypedWord()), 1); Loading Loading @@ -924,10 +911,8 @@ public final class InputLogic { // No need to reset mSpaceState, it has already be done (that's why we // receive it as a parameter) inputTransaction.setRequiresUpdateSuggestions(); mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( WordComposer.CAPS_MODE_OFF, getPrevWordsInfoFromNthPreviousWordForSuggestion( inputTransaction.mSettingsValues.mSpacingAndPunctuations, 1)); mWordComposer.setCapitalizedModeAtStartComposingTime( WordComposer.CAPS_MODE_OFF); return; } } else if (SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) { Loading Loading @@ -1107,7 +1092,6 @@ public final class InputLogic { final String textToInsert = inputTransaction.mSettingsValues.mSpacingAndPunctuations .mSentenceSeparatorAndSpace; mConnection.commitText(textToInsert, 1); mWordComposer.discardPreviousWordForSuggestion(); return true; } return false; Loading Loading @@ -1267,10 +1251,7 @@ public final class InputLogic { final int expectedCursorPosition = mConnection.getExpectedSelectionStart(); if (!mConnection.isCursorTouchingWord(settingsValues.mSpacingAndPunctuations)) { // Show predictions. mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( WordComposer.CAPS_MODE_OFF, getPrevWordsInfoFromNthPreviousWordForSuggestion( settingsValues.mSpacingAndPunctuations, 1)); mWordComposer.setCapitalizedModeAtStartComposingTime(WordComposer.CAPS_MODE_OFF); mLatinIME.mHandler.postUpdateSuggestionStrip(); return; } Loading Loading @@ -1322,7 +1303,7 @@ public final class InputLogic { settingsValues.mSpacingAndPunctuations, 0 == numberOfCharsInWordBeforeCursor ? 1 : 2); mWordComposer.setComposingWord(codePoints, mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), prevWordsInfo); mLatinIME.getCoordinatesForCurrentKeyboard(codePoints)); mWordComposer.setCursorPositionWithinWord( typedWord.codePointCount(0, numberOfCharsInWordBeforeCursor)); mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor, Loading Loading @@ -1450,7 +1431,7 @@ public final class InputLogic { // with the typed word, so we need to resume suggestions right away. final int[] codePoints = StringUtils.toCodePointArray(stringToCommit); mWordComposer.setComposingWord(codePoints, mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), prevWordsInfo); mLatinIME.getCoordinatesForCurrentKeyboard(codePoints)); mConnection.setComposingText(textToCommit, 1); } // Don't restart suggestion yet. We'll restart if the user deletes the separator. Loading Loading @@ -1897,21 +1878,6 @@ public final class InputLogic { // strings. mLastComposedWord = mWordComposer.commitWord(commitType, chosenWordWithSuggestions, separatorString, prevWordsInfo); final boolean shouldDiscardPreviousWordForSuggestion; if (0 == StringUtils.codePointCount(separatorString)) { // Separator is 0-length, we can keep the previous word for suggestion. Either this // was a manual pick or the language has no spaces in which case we want to keep the // previous word, or it was the keyboard closing or the cursor moving in which case it // will be reset anyway. shouldDiscardPreviousWordForSuggestion = false; } else { // Otherwise, we discard if the separator contains any non-whitespace. shouldDiscardPreviousWordForSuggestion = !StringUtils.containsOnlyWhitespace(separatorString); } if (shouldDiscardPreviousWordForSuggestion) { mWordComposer.discardPreviousWordForSuggestion(); } } /** Loading java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java +1 −1 Original line number Diff line number Diff line Loading @@ -323,7 +323,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { } else { coordinates = dictInfo.mKeyboard.getCoordinates(codePoints); } composer.setComposingWord(codePoints, coordinates, null /* previousWord */); composer.setComposingWord(codePoints, coordinates); // TODO: make a spell checker option to block offensive words or not final ArrayList<SuggestedWordInfo> suggestions = dictInfo.mDictionary.getSuggestions(composer, prevWordsInfo, Loading tests/src/com/android/inputmethod/latin/WordComposerTests.java +19 −35 Original line number Diff line number Diff line Loading @@ -40,8 +40,7 @@ public class WordComposerTests extends AndroidTestCase { final int[] COORDINATES_WITHIN_BMP = CoordinateUtils.newCoordinateArray(CODEPOINTS_WITHIN_BMP.length, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); final PrevWordsInfo PREV_WORDS_INFO = new PrevWordsInfo("prevword"); wc.setComposingWord(CODEPOINTS_WITHIN_BMP, COORDINATES_WITHIN_BMP, PREV_WORDS_INFO); wc.setComposingWord(CODEPOINTS_WITHIN_BMP, COORDINATES_WITHIN_BMP); assertEquals(wc.size(), STR_WITHIN_BMP.codePointCount(0, STR_WITHIN_BMP.length())); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); wc.setCursorPositionWithinWord(2); Loading @@ -56,15 +55,12 @@ public class WordComposerTests extends AndroidTestCase { // Move the cursor to after the 'f' assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1)); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); // Check the previous word is still there assertEquals(PREV_WORDS_INFO, wc.getPrevWordsInfoForSuggestion()); // Move the cursor past the end of the word assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(1)); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(15)); // Do what LatinIME does when the cursor is moved outside of the word, // and check the behavior is correct. wc.reset(); assertNull(wc.getPrevWordsInfoForSuggestion().mPrevWord); // \uD861\uDED7 is 𨛗, a character outside the BMP final String STR_WITH_SUPPLEMENTARY_CHAR = "abcde\uD861\uDED7fgh"; Loading @@ -73,8 +69,8 @@ public class WordComposerTests extends AndroidTestCase { final int[] COORDINATES_WITH_SUPPLEMENTARY_CHAR = CoordinateUtils.newCoordinateArray(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PrevWordsInfo.EMPTY_PREV_WORDS_INFO); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); assertEquals(wc.size(), CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); wc.setCursorPositionWithinWord(3); Loading @@ -83,55 +79,43 @@ public class WordComposerTests extends AndroidTestCase { assertTrue(wc.isCursorFrontOrMiddleOfComposingWord()); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1)); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); assertNull(wc.getPrevWordsInfoForSuggestion().mPrevWord); final PrevWordsInfo PREV_WORDS_INFO_STR_WITHIN_BMP = new PrevWordsInfo(STR_WITHIN_BMP); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_STR_WITHIN_BMP); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7)); assertEquals(PREV_WORDS_INFO_STR_WITHIN_BMP, wc.getPrevWordsInfoForSuggestion()); final PrevWordsInfo PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR = new PrevWordsInfo(STR_WITH_SUPPLEMENTARY_CHAR); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7)); assertEquals(PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR, wc.getPrevWordsInfoForSuggestion()); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_STR_WITHIN_BMP); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-3)); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-1)); assertEquals(PREV_WORDS_INFO_STR_WITHIN_BMP, wc.getPrevWordsInfoForSuggestion()); final PrevWordsInfo PREV_WORDS_INFO_NULL = PrevWordsInfo.EMPTY_PREV_WORDS_INFO; wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_NULL); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); wc.setCursorPositionWithinWord(3); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-9)); assertNull(wc.getPrevWordsInfoForSuggestion().mPrevWord); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-10)); assertEquals(PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR, wc.getPrevWordsInfoForSuggestion()); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_NULL); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-11)); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_NULL); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0)); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_NULL); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); wc.setCursorPositionWithinWord(2); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0)); } Loading Loading
java/src/com/android/inputmethod/latin/Suggest.java +8 −8 Original line number Diff line number Diff line Loading @@ -110,7 +110,7 @@ public final class Suggest { wordComposer, prevWordsInfo, proximityInfo, blockOffensiveWords, additionalFeaturesOptions, SESSION_TYPING, rawSuggestions); final boolean isFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); final boolean isOnlyFirstCharCapitalized = wordComposer.isOnlyFirstCharCapitalized(); // If resumed, then we don't want to upcase everything: resuming on a fully-capitalized // words is rarely done to switch to another fully-capitalized word, but usually to a // normal, non-capitalized suggestion. Loading @@ -122,7 +122,7 @@ public final class Suggest { } else { final SuggestedWordInfo firstSuggestedWordInfo = getTransformedSuggestedWordInfo( suggestionResults.first(), suggestionResults.mLocale, isAllUpperCase, isFirstCharCapitalized, trailingSingleQuotesCount); isOnlyFirstCharCapitalized, trailingSingleQuotesCount); firstSuggestion = firstSuggestedWordInfo.mWord; if (!firstSuggestedWordInfo.isKindOf(SuggestedWordInfo.KIND_WHITELIST)) { whitelistedWord = null; Loading @@ -142,7 +142,7 @@ public final class Suggest { final boolean allowsToBeAutoCorrected = (null != whitelistedWord && !whitelistedWord.equals(typedWord)) || (consideredWord.length() > 1 && !mDictionaryFacilitator.isValidWord( consideredWord, wordComposer.isFirstCharCapitalized()) consideredWord, isOnlyFirstCharCapitalized) && !typedWord.equals(firstSuggestion)); final boolean hasAutoCorrection; Loading Loading @@ -173,12 +173,12 @@ public final class Suggest { final ArrayList<SuggestedWordInfo> suggestionsContainer = new ArrayList<>(suggestionResults); final int suggestionsCount = suggestionsContainer.size(); if (isFirstCharCapitalized || isAllUpperCase || 0 != trailingSingleQuotesCount) { if (isOnlyFirstCharCapitalized || isAllUpperCase || 0 != trailingSingleQuotesCount) { for (int i = 0; i < suggestionsCount; ++i) { final SuggestedWordInfo wordInfo = suggestionsContainer.get(i); final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo( wordInfo, suggestionResults.mLocale, isAllUpperCase, isFirstCharCapitalized, trailingSingleQuotesCount); wordInfo, suggestionResults.mLocale, isAllUpperCase, isOnlyFirstCharCapitalized, trailingSingleQuotesCount); suggestionsContainer.set(i, transformedWordInfo); } } Loading Loading @@ -292,11 +292,11 @@ public final class Suggest { /* package for test */ static SuggestedWordInfo getTransformedSuggestedWordInfo( final SuggestedWordInfo wordInfo, final Locale locale, final boolean isAllUpperCase, final boolean isFirstCharCapitalized, final int trailingSingleQuotesCount) { final boolean isOnlyFirstCharCapitalized, final int trailingSingleQuotesCount) { final StringBuilder sb = new StringBuilder(wordInfo.mWord.length()); if (isAllUpperCase) { sb.append(wordInfo.mWord.toUpperCase(locale)); } else if (isFirstCharCapitalized) { } else if (isOnlyFirstCharCapitalized) { sb.append(StringUtils.capitalizeFirstCodePoint(wordInfo.mWord, locale)); } else { sb.append(wordInfo.mWord); Loading
java/src/com/android/inputmethod/latin/WordComposer.java +19 −45 Original line number Diff line number Diff line Loading @@ -45,9 +45,6 @@ public final class WordComposer { // The list of events that served to compose this string. private final ArrayList<Event> mEvents; private final InputPointers mInputPointers = new InputPointers(MAX_WORD_LENGTH); // The information of previous words (before the composing word). Must not be null. Used as // context for suggestions. private PrevWordsInfo mPrevWordsInfo; private String mAutoCorrection; private boolean mIsResumed; private boolean mIsBatchMode; Loading @@ -72,9 +69,9 @@ public final class WordComposer { private int mCursorPositionWithinWord; /** * Whether the user chose to capitalize the first char of the word. * Whether the composing word has the only first char capitalized. */ private boolean mIsFirstCharCapitalized; private boolean mIsOnlyFirstCharCapitalized; public WordComposer() { mCombinerChain = new CombinerChain(""); Loading @@ -84,7 +81,6 @@ public final class WordComposer { mIsBatchMode = false; mCursorPositionWithinWord = 0; mRejectedBatchModeSuggestion = null; mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO; refreshTypedWordCache(); } Loading @@ -111,12 +107,11 @@ public final class WordComposer { mAutoCorrection = null; mCapsCount = 0; mDigitsCount = 0; mIsFirstCharCapitalized = false; mIsOnlyFirstCharCapitalized = false; mIsResumed = false; mIsBatchMode = false; mCursorPositionWithinWord = 0; mRejectedBatchModeSuggestion = null; mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO; refreshTypedWordCache(); } Loading Loading @@ -178,12 +173,6 @@ public final class WordComposer { return mInputPointers; } private static boolean isFirstCharCapitalized(final int index, final int codePoint, final boolean previous) { if (index == 0) return Character.isUpperCase(codePoint); return previous && !Character.isUpperCase(codePoint); } /** * Process an input event. * Loading @@ -203,7 +192,7 @@ public final class WordComposer { mCursorPositionWithinWord = mCodePointSize; // We may have deleted the last one. if (0 == mCodePointSize) { mIsFirstCharCapitalized = false; mIsOnlyFirstCharCapitalized = false; } if (Constants.CODE_DELETE != event.mKeyCode) { if (newIndex < MAX_WORD_LENGTH) { Loading @@ -215,8 +204,12 @@ public final class WordComposer { mInputPointers.addPointerAt(newIndex, keyX, keyY, 0, 0); } } mIsFirstCharCapitalized = isFirstCharCapitalized( newIndex, primaryCode, mIsFirstCharCapitalized); if (0 == newIndex) { mIsOnlyFirstCharCapitalized = Character.isUpperCase(primaryCode); } else { mIsOnlyFirstCharCapitalized = mIsOnlyFirstCharCapitalized && !Character.isUpperCase(primaryCode); } if (Character.isUpperCase(primaryCode)) mCapsCount++; if (Character.isDigit(primaryCode)) mDigitsCount++; } Loading Loading @@ -296,10 +289,8 @@ public final class WordComposer { * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. * @param codePoints the code points to set as the composing word. * @param coordinates the x, y coordinates of the key in the CoordinateUtils format * @param prevWordsInfo the information of previous words, to use as context for suggestions */ public void setComposingWord(final int[] codePoints, final int[] coordinates, final PrevWordsInfo prevWordsInfo) { public void setComposingWord(final int[] codePoints, final int[] coordinates) { reset(); final int length = codePoints.length; for (int i = 0; i < length; ++i) { Loading @@ -308,7 +299,6 @@ public final class WordComposer { CoordinateUtils.yFromArray(coordinates, i))); } mIsResumed = true; mPrevWordsInfo = prevWordsInfo; } /** Loading @@ -319,16 +309,13 @@ public final class WordComposer { return mTypedWordCache.toString(); } public PrevWordsInfo getPrevWordsInfoForSuggestion() { return mPrevWordsInfo; } /** * Whether or not the user typed a capital letter as the first letter in the word * Whether or not the user typed a capital letter as the first letter in the word, and no * other letter is capitalized * @return capitalization preference */ public boolean isFirstCharCapitalized() { return mIsFirstCharCapitalized; public boolean isOnlyFirstCharCapitalized() { return mIsOnlyFirstCharCapitalized; } /** Loading Loading @@ -364,7 +351,7 @@ public final class WordComposer { } /** * Saves the caps mode and the previous word at the start of composing. * Saves the caps mode at the start of composing. * * WordComposer needs to know about the caps mode for several reasons. The first is, we need * to know after the fact what the reason was, to register the correct form into the user Loading @@ -373,12 +360,9 @@ public final class WordComposer { * Also, batch input needs to know about the current caps mode to display correctly * capitalized suggestions. * @param mode the mode at the time of start * @param prevWordsInfo the information of previous words */ public void setCapitalizedModeAndPreviousWordAtStartComposingTime(final int mode, final PrevWordsInfo prevWordsInfo) { public void setCapitalizedModeAtStartComposingTime(final int mode) { mCapitalizedMode = mode; mPrevWordsInfo = prevWordsInfo; } /** Loading Loading @@ -429,11 +413,10 @@ public final class WordComposer { mCapsCount = 0; mDigitsCount = 0; mIsBatchMode = false; mPrevWordsInfo = new PrevWordsInfo(committedWord.toString()); mCombinerChain.reset(); mEvents.clear(); mCodePointSize = 0; mIsFirstCharCapitalized = false; mIsOnlyFirstCharCapitalized = false; mCapitalizedMode = CAPS_MODE_OFF; refreshTypedWordCache(); mAutoCorrection = null; Loading @@ -443,15 +426,7 @@ public final class WordComposer { return lastComposedWord; } // Call this when the recorded previous word should be discarded. This is typically called // when the user inputs a separator that's not whitespace (including the case of the // double-space-to-period feature). public void discardPreviousWordForSuggestion() { mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO; } public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord, final PrevWordsInfo prevWordsInfo) { public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) { mEvents.clear(); Collections.copy(mEvents, lastComposedWord.mEvents); mInputPointers.set(lastComposedWord.mInputPointers); Loading @@ -462,7 +437,6 @@ public final class WordComposer { mCursorPositionWithinWord = mCodePointSize; mRejectedBatchModeSuggestion = null; mIsResumed = true; mPrevWordsInfo = prevWordsInfo; } public boolean isBatchMode() { Loading
java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +10 −44 Original line number Diff line number Diff line Loading @@ -544,11 +544,8 @@ public final class InputLogic { } } mConnection.endBatchEdit(); mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode()), // Prev word is 1st word before cursor getPrevWordsInfoFromNthPreviousWordForSuggestion( settingsValues.mSpacingAndPunctuations, 1 /* nthPreviousWord */)); mWordComposer.setCapitalizedModeAtStartComposingTime( getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode())); } /* The sequence number member is only used in onUpdateBatchInput. It is increased each time Loading Loading @@ -584,10 +581,8 @@ public final class InputLogic { mSpaceState = SpaceState.PHANTOM; keyboardSwitcher.requestUpdatingShiftState( getCurrentAutoCapsState(settingsValues), getCurrentRecapitalizeState()); mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode()), new PrevWordsInfo(commitParts[0])); mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode( settingsValues, keyboardSwitcher.getKeyboardShiftMode())); ++mAutoCommitSequenceNumber; } } Loading Loading @@ -724,15 +719,7 @@ public final class InputLogic { mWordComposer.processEvent(inputTransaction.mEvent); // If it's the first letter, make note of auto-caps state if (mWordComposer.isSingleLetter()) { // We pass 2 to getPreviousWordForSuggestion when the previous code point is a word // connector. Otherwise, we pass 1 because we were not composing a word yet, so the // word we want is the 1st word before the cursor. mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( inputTransaction.mShiftState, getPrevWordsInfoFromNthPreviousWordForSuggestion( settingsValues.mSpacingAndPunctuations, settingsValues.mSpacingAndPunctuations.isWordConnector( mConnection.getCodePointBeforeCursor()) ? 2 : 1)); mWordComposer.setCapitalizedModeAtStartComposingTime(inputTransaction.mShiftState); } mConnection.setComposingText(getTextWithUnderline( mWordComposer.getTypedWord()), 1); Loading Loading @@ -924,10 +911,8 @@ public final class InputLogic { // No need to reset mSpaceState, it has already be done (that's why we // receive it as a parameter) inputTransaction.setRequiresUpdateSuggestions(); mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( WordComposer.CAPS_MODE_OFF, getPrevWordsInfoFromNthPreviousWordForSuggestion( inputTransaction.mSettingsValues.mSpacingAndPunctuations, 1)); mWordComposer.setCapitalizedModeAtStartComposingTime( WordComposer.CAPS_MODE_OFF); return; } } else if (SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) { Loading Loading @@ -1107,7 +1092,6 @@ public final class InputLogic { final String textToInsert = inputTransaction.mSettingsValues.mSpacingAndPunctuations .mSentenceSeparatorAndSpace; mConnection.commitText(textToInsert, 1); mWordComposer.discardPreviousWordForSuggestion(); return true; } return false; Loading Loading @@ -1267,10 +1251,7 @@ public final class InputLogic { final int expectedCursorPosition = mConnection.getExpectedSelectionStart(); if (!mConnection.isCursorTouchingWord(settingsValues.mSpacingAndPunctuations)) { // Show predictions. mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( WordComposer.CAPS_MODE_OFF, getPrevWordsInfoFromNthPreviousWordForSuggestion( settingsValues.mSpacingAndPunctuations, 1)); mWordComposer.setCapitalizedModeAtStartComposingTime(WordComposer.CAPS_MODE_OFF); mLatinIME.mHandler.postUpdateSuggestionStrip(); return; } Loading Loading @@ -1322,7 +1303,7 @@ public final class InputLogic { settingsValues.mSpacingAndPunctuations, 0 == numberOfCharsInWordBeforeCursor ? 1 : 2); mWordComposer.setComposingWord(codePoints, mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), prevWordsInfo); mLatinIME.getCoordinatesForCurrentKeyboard(codePoints)); mWordComposer.setCursorPositionWithinWord( typedWord.codePointCount(0, numberOfCharsInWordBeforeCursor)); mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor, Loading Loading @@ -1450,7 +1431,7 @@ public final class InputLogic { // with the typed word, so we need to resume suggestions right away. final int[] codePoints = StringUtils.toCodePointArray(stringToCommit); mWordComposer.setComposingWord(codePoints, mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), prevWordsInfo); mLatinIME.getCoordinatesForCurrentKeyboard(codePoints)); mConnection.setComposingText(textToCommit, 1); } // Don't restart suggestion yet. We'll restart if the user deletes the separator. Loading Loading @@ -1897,21 +1878,6 @@ public final class InputLogic { // strings. mLastComposedWord = mWordComposer.commitWord(commitType, chosenWordWithSuggestions, separatorString, prevWordsInfo); final boolean shouldDiscardPreviousWordForSuggestion; if (0 == StringUtils.codePointCount(separatorString)) { // Separator is 0-length, we can keep the previous word for suggestion. Either this // was a manual pick or the language has no spaces in which case we want to keep the // previous word, or it was the keyboard closing or the cursor moving in which case it // will be reset anyway. shouldDiscardPreviousWordForSuggestion = false; } else { // Otherwise, we discard if the separator contains any non-whitespace. shouldDiscardPreviousWordForSuggestion = !StringUtils.containsOnlyWhitespace(separatorString); } if (shouldDiscardPreviousWordForSuggestion) { mWordComposer.discardPreviousWordForSuggestion(); } } /** Loading
java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java +1 −1 Original line number Diff line number Diff line Loading @@ -323,7 +323,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { } else { coordinates = dictInfo.mKeyboard.getCoordinates(codePoints); } composer.setComposingWord(codePoints, coordinates, null /* previousWord */); composer.setComposingWord(codePoints, coordinates); // TODO: make a spell checker option to block offensive words or not final ArrayList<SuggestedWordInfo> suggestions = dictInfo.mDictionary.getSuggestions(composer, prevWordsInfo, Loading
tests/src/com/android/inputmethod/latin/WordComposerTests.java +19 −35 Original line number Diff line number Diff line Loading @@ -40,8 +40,7 @@ public class WordComposerTests extends AndroidTestCase { final int[] COORDINATES_WITHIN_BMP = CoordinateUtils.newCoordinateArray(CODEPOINTS_WITHIN_BMP.length, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); final PrevWordsInfo PREV_WORDS_INFO = new PrevWordsInfo("prevword"); wc.setComposingWord(CODEPOINTS_WITHIN_BMP, COORDINATES_WITHIN_BMP, PREV_WORDS_INFO); wc.setComposingWord(CODEPOINTS_WITHIN_BMP, COORDINATES_WITHIN_BMP); assertEquals(wc.size(), STR_WITHIN_BMP.codePointCount(0, STR_WITHIN_BMP.length())); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); wc.setCursorPositionWithinWord(2); Loading @@ -56,15 +55,12 @@ public class WordComposerTests extends AndroidTestCase { // Move the cursor to after the 'f' assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1)); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); // Check the previous word is still there assertEquals(PREV_WORDS_INFO, wc.getPrevWordsInfoForSuggestion()); // Move the cursor past the end of the word assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(1)); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(15)); // Do what LatinIME does when the cursor is moved outside of the word, // and check the behavior is correct. wc.reset(); assertNull(wc.getPrevWordsInfoForSuggestion().mPrevWord); // \uD861\uDED7 is 𨛗, a character outside the BMP final String STR_WITH_SUPPLEMENTARY_CHAR = "abcde\uD861\uDED7fgh"; Loading @@ -73,8 +69,8 @@ public class WordComposerTests extends AndroidTestCase { final int[] COORDINATES_WITH_SUPPLEMENTARY_CHAR = CoordinateUtils.newCoordinateArray(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PrevWordsInfo.EMPTY_PREV_WORDS_INFO); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); assertEquals(wc.size(), CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); wc.setCursorPositionWithinWord(3); Loading @@ -83,55 +79,43 @@ public class WordComposerTests extends AndroidTestCase { assertTrue(wc.isCursorFrontOrMiddleOfComposingWord()); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1)); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); assertNull(wc.getPrevWordsInfoForSuggestion().mPrevWord); final PrevWordsInfo PREV_WORDS_INFO_STR_WITHIN_BMP = new PrevWordsInfo(STR_WITHIN_BMP); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_STR_WITHIN_BMP); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7)); assertEquals(PREV_WORDS_INFO_STR_WITHIN_BMP, wc.getPrevWordsInfoForSuggestion()); final PrevWordsInfo PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR = new PrevWordsInfo(STR_WITH_SUPPLEMENTARY_CHAR); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7)); assertEquals(PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR, wc.getPrevWordsInfoForSuggestion()); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_STR_WITHIN_BMP); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-3)); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-1)); assertEquals(PREV_WORDS_INFO_STR_WITHIN_BMP, wc.getPrevWordsInfoForSuggestion()); final PrevWordsInfo PREV_WORDS_INFO_NULL = PrevWordsInfo.EMPTY_PREV_WORDS_INFO; wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_NULL); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); wc.setCursorPositionWithinWord(3); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-9)); assertNull(wc.getPrevWordsInfoForSuggestion().mPrevWord); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-10)); assertEquals(PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR, wc.getPrevWordsInfoForSuggestion()); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_NULL); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-11)); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_NULL); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0)); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, PREV_WORDS_INFO_NULL); wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR); wc.setCursorPositionWithinWord(2); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0)); } Loading