Loading java/src/com/android/inputmethod/latin/LatinIME.java +57 −14 Original line number Diff line number Diff line Loading @@ -1466,8 +1466,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction "", mWordComposer.getTypedWord(), " ", mWordComposer); } } if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the character at the current cursor position. resetEntireInputState(mLastSelectionStart); } else { commitTyped(LastComposedWord.NOT_A_SEPARATOR); } } final int keyX, keyY; final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) { Loading Loading @@ -1522,8 +1528,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } 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) { final int lastChar = mWordComposer.getCodeBeforeCursor(); if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the batch input at the current cursor position. resetEntireInputState(mLastSelectionStart); } else 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 Loading Loading @@ -1734,8 +1744,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // during key repeat. mHandler.postUpdateShiftState(); if (mWordComposer.isComposingWord() && !mWordComposer.isCursorAtEndOfComposingWord()) { if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can remove the character at the current cursor position. resetEntireInputState(mLastSelectionStart); // When we exit this if-clause, mWordComposer.isComposingWord() will return false. } if (mWordComposer.isComposingWord()) { final int length = mWordComposer.size(); Loading Loading @@ -1870,7 +1883,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction promotePhantomSpace(); } if (mWordComposer.isComposingWord() && !mWordComposer.isCursorAtEndOfComposingWord()) { if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the character at the current cursor position. resetEntireInputState(mLastSelectionStart); isComposingWord = false; } Loading Loading @@ -1935,7 +1950,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord()); } boolean didAutoCorrect = false; // Handle separator if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the separator at the current cursor position. resetEntireInputState(mLastSelectionStart); } if (mWordComposer.isComposingWord()) { if (mSettings.getCurrent().mCorrectionEnabled) { // TODO: maybe cache Strings in an <String> sparse array or something Loading Loading @@ -2357,9 +2376,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final Range range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(), 0 /* additionalPrecedingWordsCount */); final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList(); final String typedWord = range.mWord.toString(); if (range.mWord instanceof SpannableString) { final SpannableString spannableString = (SpannableString)range.mWord; final String typedWord = spannableString.toString(); int i = 0; for (Object object : spannableString.getSpans(0, spannableString.length(), SuggestionSpan.class)) { Loading @@ -2374,18 +2393,42 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } } } mWordComposer.setComposingWord(range.mWord, mKeyboardSwitcher.getKeyboard()); mWordComposer.setComposingWord(typedWord, mKeyboardSwitcher.getKeyboard()); mWordComposer.setCursorPositionWithinWord(range.mCharsBefore); mConnection.setComposingRegion(mLastSelectionStart - range.mCharsBefore, mLastSelectionEnd + range.mCharsAfter); final SuggestedWords suggestedWords; if (suggestions.isEmpty()) { suggestions.add(new SuggestedWordInfo(range.mWord.toString(), 1, SuggestedWordInfo.KIND_TYPED, Dictionary.TYPE_RESUMED)); // We come here if there weren't any suggestion spans on this word. We will try to // compute suggestions for it instead. final SuggestedWords suggestedWordsIncludingTypedWord = getSuggestedWords(Suggest.SESSION_TYPING); if (suggestedWordsIncludingTypedWord.size() > 1) { // We were able to compute new suggestions for this word. // Remove the typed word, since we don't want to display it in this case. // The #getSuggestedWordsExcludingTypedWord() method sets willAutoCorrect to false. suggestedWords = suggestedWordsIncludingTypedWord.getSuggestedWordsExcludingTypedWord(); } else { // No saved suggestions, and we were unable to compute any good one either. // Rather than displaying an empty suggestion strip, we'll display the original // word alone in the middle. // Since there is only one word, willAutoCorrect is false. suggestedWords = suggestedWordsIncludingTypedWord; } showSuggestionStrip(new SuggestedWords(suggestions, } else { // We found suggestion spans in the word. We'll create the SuggestedWords out of // them, and make willAutoCorrect false. suggestedWords = new SuggestedWords(suggestions, true /* typedWordValid */, false /* willAutoCorrect */, false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, false /* isPrediction */), range.mWord.toString()); false /* isPrediction */); } // Note that it's very important here that suggestedWords.mWillAutoCorrect is false. // We never want to auto-correct on a resumed suggestion. Please refer to the three // places above where suggestedWords is affected. showSuggestionStrip(suggestedWords, typedWord); } /** Loading java/src/com/android/inputmethod/latin/SuggestedWords.java +17 −0 Original line number Diff line number Diff line Loading @@ -195,4 +195,21 @@ public final class SuggestedWords { } } } // SuggestedWords is an immutable object, as much as possible. We must not just remove // words from the member ArrayList as some other parties may expect the object to never change. public SuggestedWords getSuggestedWordsExcludingTypedWord() { final ArrayList<SuggestedWordInfo> newSuggestions = CollectionUtils.newArrayList(); for (int i = 0; i < mSuggestedWordInfoList.size(); ++i) { final SuggestedWordInfo info = mSuggestedWordInfoList.get(i); if (SuggestedWordInfo.KIND_TYPED != info.mKind) { newSuggestions.add(info); } } // We should never autocorrect, so we say the typed word is valid. Also, in this case, // no auto-correction should take place hence willAutoCorrect = false. return new SuggestedWords(newSuggestions, true /* typedWordValid */, false /* willAutoCorrect */, mIsPunctuationSuggestions, mIsObsoleteSuggestions, mIsPrediction); } } java/src/com/android/inputmethod/latin/WordComposer.java +14 −2 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import java.util.Arrays; */ public final class WordComposer { private static final int MAX_WORD_LENGTH = Constants.Dictionary.MAX_WORD_LENGTH; private static final boolean DBG = LatinImeLogger.sDBG; public static final int CAPS_MODE_OFF = 0; // 1 is shift bit, 2 is caps bit, 4 is auto bit but this is just a convention as these bits Loading Loading @@ -132,6 +133,13 @@ public final class WordComposer { return mPrimaryKeyCodes[index]; } public int getCodeBeforeCursor() { if (mCursorPositionWithinWord < 1 || mCursorPositionWithinWord > mPrimaryKeyCodes.length) { return Constants.NOT_A_CODE; } return mPrimaryKeyCodes[mCursorPositionWithinWord - 1]; } public InputPointers getInputPointers() { return mInputPointers; } Loading Loading @@ -177,8 +185,12 @@ public final class WordComposer { mCursorPositionWithinWord = posWithinWord; } public boolean isCursorAtEndOfComposingWord() { return mCursorPositionWithinWord == mCodePointSize; public boolean isCursorFrontOrMiddleOfComposingWord() { if (DBG && mCursorPositionWithinWord > mCodePointSize) { throw new RuntimeException("Wrong cursor position : " + mCursorPositionWithinWord + "in a word of size " + mCodePointSize); } return mCursorPositionWithinWord != mCodePointSize; } public void setBatchInputPointers(final InputPointers batchPointers) { Loading tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java 0 → 100644 +60 −0 Original line number Diff line number Diff line /* * 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. */ package com.android.inputmethod.latin; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import java.util.ArrayList; import java.util.Locale; @SmallTest public class SuggestedWordsTests extends AndroidTestCase { public void testGetSuggestedWordsExcludingTypedWord() { final String TYPED_WORD = "typed"; final int TYPED_WORD_FREQ = 5; final int NUMBER_OF_ADDED_SUGGESTIONS = 5; final ArrayList<SuggestedWordInfo> list = CollectionUtils.newArrayList(); list.add(new SuggestedWordInfo(TYPED_WORD, TYPED_WORD_FREQ, SuggestedWordInfo.KIND_TYPED, "")); for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) { list.add(new SuggestedWordInfo("" + i, 1, SuggestedWordInfo.KIND_CORRECTION, "")); } final SuggestedWords words = new SuggestedWords( list, false /* typedWordValid */, false /* willAutoCorrect */, false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, false /* isPrediction*/); assertEquals(NUMBER_OF_ADDED_SUGGESTIONS + 1, words.size()); assertEquals("typed", words.getWord(0)); assertEquals(SuggestedWordInfo.KIND_TYPED, words.getInfo(0).mKind); assertEquals("0", words.getWord(1)); assertEquals(SuggestedWordInfo.KIND_CORRECTION, words.getInfo(1).mKind); assertEquals("4", words.getWord(5)); assertEquals(SuggestedWordInfo.KIND_CORRECTION, words.getInfo(5).mKind); final SuggestedWords wordsWithoutTyped = words.getSuggestedWordsExcludingTypedWord(); assertEquals(words.size() - 1, wordsWithoutTyped.size()); assertEquals("0", wordsWithoutTyped.getWord(0)); assertEquals(SuggestedWordInfo.KIND_CORRECTION, wordsWithoutTyped.getInfo(0).mKind); } } Loading
java/src/com/android/inputmethod/latin/LatinIME.java +57 −14 Original line number Diff line number Diff line Loading @@ -1466,8 +1466,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction "", mWordComposer.getTypedWord(), " ", mWordComposer); } } if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the character at the current cursor position. resetEntireInputState(mLastSelectionStart); } else { commitTyped(LastComposedWord.NOT_A_SEPARATOR); } } final int keyX, keyY; final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) { Loading Loading @@ -1522,8 +1528,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } 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) { final int lastChar = mWordComposer.getCodeBeforeCursor(); if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the batch input at the current cursor position. resetEntireInputState(mLastSelectionStart); } else 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 Loading Loading @@ -1734,8 +1744,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // during key repeat. mHandler.postUpdateShiftState(); if (mWordComposer.isComposingWord() && !mWordComposer.isCursorAtEndOfComposingWord()) { if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can remove the character at the current cursor position. resetEntireInputState(mLastSelectionStart); // When we exit this if-clause, mWordComposer.isComposingWord() will return false. } if (mWordComposer.isComposingWord()) { final int length = mWordComposer.size(); Loading Loading @@ -1870,7 +1883,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction promotePhantomSpace(); } if (mWordComposer.isComposingWord() && !mWordComposer.isCursorAtEndOfComposingWord()) { if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the character at the current cursor position. resetEntireInputState(mLastSelectionStart); isComposingWord = false; } Loading Loading @@ -1935,7 +1950,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord()); } boolean didAutoCorrect = false; // Handle separator if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the separator at the current cursor position. resetEntireInputState(mLastSelectionStart); } if (mWordComposer.isComposingWord()) { if (mSettings.getCurrent().mCorrectionEnabled) { // TODO: maybe cache Strings in an <String> sparse array or something Loading Loading @@ -2357,9 +2376,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final Range range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(), 0 /* additionalPrecedingWordsCount */); final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList(); final String typedWord = range.mWord.toString(); if (range.mWord instanceof SpannableString) { final SpannableString spannableString = (SpannableString)range.mWord; final String typedWord = spannableString.toString(); int i = 0; for (Object object : spannableString.getSpans(0, spannableString.length(), SuggestionSpan.class)) { Loading @@ -2374,18 +2393,42 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } } } mWordComposer.setComposingWord(range.mWord, mKeyboardSwitcher.getKeyboard()); mWordComposer.setComposingWord(typedWord, mKeyboardSwitcher.getKeyboard()); mWordComposer.setCursorPositionWithinWord(range.mCharsBefore); mConnection.setComposingRegion(mLastSelectionStart - range.mCharsBefore, mLastSelectionEnd + range.mCharsAfter); final SuggestedWords suggestedWords; if (suggestions.isEmpty()) { suggestions.add(new SuggestedWordInfo(range.mWord.toString(), 1, SuggestedWordInfo.KIND_TYPED, Dictionary.TYPE_RESUMED)); // We come here if there weren't any suggestion spans on this word. We will try to // compute suggestions for it instead. final SuggestedWords suggestedWordsIncludingTypedWord = getSuggestedWords(Suggest.SESSION_TYPING); if (suggestedWordsIncludingTypedWord.size() > 1) { // We were able to compute new suggestions for this word. // Remove the typed word, since we don't want to display it in this case. // The #getSuggestedWordsExcludingTypedWord() method sets willAutoCorrect to false. suggestedWords = suggestedWordsIncludingTypedWord.getSuggestedWordsExcludingTypedWord(); } else { // No saved suggestions, and we were unable to compute any good one either. // Rather than displaying an empty suggestion strip, we'll display the original // word alone in the middle. // Since there is only one word, willAutoCorrect is false. suggestedWords = suggestedWordsIncludingTypedWord; } showSuggestionStrip(new SuggestedWords(suggestions, } else { // We found suggestion spans in the word. We'll create the SuggestedWords out of // them, and make willAutoCorrect false. suggestedWords = new SuggestedWords(suggestions, true /* typedWordValid */, false /* willAutoCorrect */, false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, false /* isPrediction */), range.mWord.toString()); false /* isPrediction */); } // Note that it's very important here that suggestedWords.mWillAutoCorrect is false. // We never want to auto-correct on a resumed suggestion. Please refer to the three // places above where suggestedWords is affected. showSuggestionStrip(suggestedWords, typedWord); } /** Loading
java/src/com/android/inputmethod/latin/SuggestedWords.java +17 −0 Original line number Diff line number Diff line Loading @@ -195,4 +195,21 @@ public final class SuggestedWords { } } } // SuggestedWords is an immutable object, as much as possible. We must not just remove // words from the member ArrayList as some other parties may expect the object to never change. public SuggestedWords getSuggestedWordsExcludingTypedWord() { final ArrayList<SuggestedWordInfo> newSuggestions = CollectionUtils.newArrayList(); for (int i = 0; i < mSuggestedWordInfoList.size(); ++i) { final SuggestedWordInfo info = mSuggestedWordInfoList.get(i); if (SuggestedWordInfo.KIND_TYPED != info.mKind) { newSuggestions.add(info); } } // We should never autocorrect, so we say the typed word is valid. Also, in this case, // no auto-correction should take place hence willAutoCorrect = false. return new SuggestedWords(newSuggestions, true /* typedWordValid */, false /* willAutoCorrect */, mIsPunctuationSuggestions, mIsObsoleteSuggestions, mIsPrediction); } }
java/src/com/android/inputmethod/latin/WordComposer.java +14 −2 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import java.util.Arrays; */ public final class WordComposer { private static final int MAX_WORD_LENGTH = Constants.Dictionary.MAX_WORD_LENGTH; private static final boolean DBG = LatinImeLogger.sDBG; public static final int CAPS_MODE_OFF = 0; // 1 is shift bit, 2 is caps bit, 4 is auto bit but this is just a convention as these bits Loading Loading @@ -132,6 +133,13 @@ public final class WordComposer { return mPrimaryKeyCodes[index]; } public int getCodeBeforeCursor() { if (mCursorPositionWithinWord < 1 || mCursorPositionWithinWord > mPrimaryKeyCodes.length) { return Constants.NOT_A_CODE; } return mPrimaryKeyCodes[mCursorPositionWithinWord - 1]; } public InputPointers getInputPointers() { return mInputPointers; } Loading Loading @@ -177,8 +185,12 @@ public final class WordComposer { mCursorPositionWithinWord = posWithinWord; } public boolean isCursorAtEndOfComposingWord() { return mCursorPositionWithinWord == mCodePointSize; public boolean isCursorFrontOrMiddleOfComposingWord() { if (DBG && mCursorPositionWithinWord > mCodePointSize) { throw new RuntimeException("Wrong cursor position : " + mCursorPositionWithinWord + "in a word of size " + mCodePointSize); } return mCursorPositionWithinWord != mCodePointSize; } public void setBatchInputPointers(final InputPointers batchPointers) { Loading
tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java 0 → 100644 +60 −0 Original line number Diff line number Diff line /* * 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. */ package com.android.inputmethod.latin; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import java.util.ArrayList; import java.util.Locale; @SmallTest public class SuggestedWordsTests extends AndroidTestCase { public void testGetSuggestedWordsExcludingTypedWord() { final String TYPED_WORD = "typed"; final int TYPED_WORD_FREQ = 5; final int NUMBER_OF_ADDED_SUGGESTIONS = 5; final ArrayList<SuggestedWordInfo> list = CollectionUtils.newArrayList(); list.add(new SuggestedWordInfo(TYPED_WORD, TYPED_WORD_FREQ, SuggestedWordInfo.KIND_TYPED, "")); for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) { list.add(new SuggestedWordInfo("" + i, 1, SuggestedWordInfo.KIND_CORRECTION, "")); } final SuggestedWords words = new SuggestedWords( list, false /* typedWordValid */, false /* willAutoCorrect */, false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, false /* isPrediction*/); assertEquals(NUMBER_OF_ADDED_SUGGESTIONS + 1, words.size()); assertEquals("typed", words.getWord(0)); assertEquals(SuggestedWordInfo.KIND_TYPED, words.getInfo(0).mKind); assertEquals("0", words.getWord(1)); assertEquals(SuggestedWordInfo.KIND_CORRECTION, words.getInfo(1).mKind); assertEquals("4", words.getWord(5)); assertEquals(SuggestedWordInfo.KIND_CORRECTION, words.getInfo(5).mKind); final SuggestedWords wordsWithoutTyped = words.getSuggestedWordsExcludingTypedWord(); assertEquals(words.size() - 1, wordsWithoutTyped.size()); assertEquals("0", wordsWithoutTyped.getWord(0)); assertEquals(SuggestedWordInfo.KIND_CORRECTION, wordsWithoutTyped.getInfo(0).mKind); } }