Merge "If there are no suggestion span, recompute suggestions."
commit
a022c53882
|
@ -1466,8 +1466,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
|
||||||
"", mWordComposer.getTypedWord(), " ", mWordComposer);
|
"", 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);
|
commitTyped(LastComposedWord.NOT_A_SEPARATOR);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
final int keyX, keyY;
|
final int keyX, keyY;
|
||||||
final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
|
final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
|
||||||
if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) {
|
if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) {
|
||||||
|
@ -1522,8 +1528,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
|
||||||
}
|
}
|
||||||
final int wordComposerSize = mWordComposer.size();
|
final int wordComposerSize = mWordComposer.size();
|
||||||
// Since isComposingWord() is true, the size is at least 1.
|
// Since isComposingWord() is true, the size is at least 1.
|
||||||
final int lastChar = mWordComposer.getCodeAt(wordComposerSize - 1);
|
final int lastChar = mWordComposer.getCodeBeforeCursor();
|
||||||
if (wordComposerSize <= 1) {
|
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
|
// 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
|
// 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
|
// tap one-letter words and you want them auto-corrected (typically, "i" in English
|
||||||
|
@ -1734,8 +1744,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
|
||||||
// during key repeat.
|
// during key repeat.
|
||||||
mHandler.postUpdateShiftState();
|
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);
|
resetEntireInputState(mLastSelectionStart);
|
||||||
|
// When we exit this if-clause, mWordComposer.isComposingWord() will return false.
|
||||||
}
|
}
|
||||||
if (mWordComposer.isComposingWord()) {
|
if (mWordComposer.isComposingWord()) {
|
||||||
final int length = mWordComposer.size();
|
final int length = mWordComposer.size();
|
||||||
|
@ -1870,7 +1883,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
|
||||||
promotePhantomSpace();
|
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);
|
resetEntireInputState(mLastSelectionStart);
|
||||||
isComposingWord = false;
|
isComposingWord = false;
|
||||||
}
|
}
|
||||||
|
@ -1935,7 +1950,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
|
||||||
ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord());
|
ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord());
|
||||||
}
|
}
|
||||||
boolean didAutoCorrect = false;
|
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 (mWordComposer.isComposingWord()) {
|
||||||
if (mSettings.getCurrent().mCorrectionEnabled) {
|
if (mSettings.getCurrent().mCorrectionEnabled) {
|
||||||
// TODO: maybe cache Strings in an <String> sparse array or something
|
// TODO: maybe cache Strings in an <String> sparse array or something
|
||||||
|
@ -2357,9 +2376,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
|
||||||
final Range range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(),
|
final Range range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(),
|
||||||
0 /* additionalPrecedingWordsCount */);
|
0 /* additionalPrecedingWordsCount */);
|
||||||
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
|
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
|
||||||
|
final String typedWord = range.mWord.toString();
|
||||||
if (range.mWord instanceof SpannableString) {
|
if (range.mWord instanceof SpannableString) {
|
||||||
final SpannableString spannableString = (SpannableString)range.mWord;
|
final SpannableString spannableString = (SpannableString)range.mWord;
|
||||||
final String typedWord = spannableString.toString();
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Object object : spannableString.getSpans(0, spannableString.length(),
|
for (Object object : spannableString.getSpans(0, spannableString.length(),
|
||||||
SuggestionSpan.class)) {
|
SuggestionSpan.class)) {
|
||||||
|
@ -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);
|
mWordComposer.setCursorPositionWithinWord(range.mCharsBefore);
|
||||||
mConnection.setComposingRegion(mLastSelectionStart - range.mCharsBefore,
|
mConnection.setComposingRegion(mLastSelectionStart - range.mCharsBefore,
|
||||||
mLastSelectionEnd + range.mCharsAfter);
|
mLastSelectionEnd + range.mCharsAfter);
|
||||||
|
final SuggestedWords suggestedWords;
|
||||||
if (suggestions.isEmpty()) {
|
if (suggestions.isEmpty()) {
|
||||||
suggestions.add(new SuggestedWordInfo(range.mWord.toString(), 1,
|
// We come here if there weren't any suggestion spans on this word. We will try to
|
||||||
SuggestedWordInfo.KIND_TYPED, Dictionary.TYPE_RESUMED));
|
// 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 */,
|
true /* typedWordValid */, false /* willAutoCorrect */,
|
||||||
false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */,
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.util.Arrays;
|
||||||
*/
|
*/
|
||||||
public final class WordComposer {
|
public final class WordComposer {
|
||||||
private static final int MAX_WORD_LENGTH = Constants.Dictionary.MAX_WORD_LENGTH;
|
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;
|
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
|
// 1 is shift bit, 2 is caps bit, 4 is auto bit but this is just a convention as these bits
|
||||||
|
@ -132,6 +133,13 @@ public final class WordComposer {
|
||||||
return mPrimaryKeyCodes[index];
|
return mPrimaryKeyCodes[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getCodeBeforeCursor() {
|
||||||
|
if (mCursorPositionWithinWord < 1 || mCursorPositionWithinWord > mPrimaryKeyCodes.length) {
|
||||||
|
return Constants.NOT_A_CODE;
|
||||||
|
}
|
||||||
|
return mPrimaryKeyCodes[mCursorPositionWithinWord - 1];
|
||||||
|
}
|
||||||
|
|
||||||
public InputPointers getInputPointers() {
|
public InputPointers getInputPointers() {
|
||||||
return mInputPointers;
|
return mInputPointers;
|
||||||
}
|
}
|
||||||
|
@ -177,8 +185,12 @@ public final class WordComposer {
|
||||||
mCursorPositionWithinWord = posWithinWord;
|
mCursorPositionWithinWord = posWithinWord;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCursorAtEndOfComposingWord() {
|
public boolean isCursorFrontOrMiddleOfComposingWord() {
|
||||||
return mCursorPositionWithinWord == mCodePointSize;
|
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) {
|
public void setBatchInputPointers(final InputPointers batchPointers) {
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* 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…
Reference in New Issue