Change the timing of reading the previous word.
Bug: 11328842 Change-Id: I08229e895fc34403932648b9b931583d965f0e01main
parent
da459787e2
commit
4866a3e918
|
@ -1779,9 +1779,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
mInputUpdater.onStartBatchInput();
|
||||
mHandler.cancelUpdateSuggestionStrip();
|
||||
mConnection.beginBatchEdit();
|
||||
final SettingsValues settingsValues = mSettings.getCurrent();
|
||||
final SettingsValues currentSettingsValues = mSettings.getCurrent();
|
||||
if (mWordComposer.isComposingWord()) {
|
||||
if (settingsValues.mIsInternal) {
|
||||
if (currentSettingsValues.mIsInternal) {
|
||||
if (mWordComposer.isBatchMode()) {
|
||||
LatinImeLoggerUtils.onAutoCorrection(
|
||||
"", mWordComposer.getTypedWord(), " ", mWordComposer);
|
||||
|
@ -1808,12 +1808,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
}
|
||||
final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor();
|
||||
if (Character.isLetterOrDigit(codePointBeforeCursor)
|
||||
|| settingsValues.isUsuallyFollowedBySpace(codePointBeforeCursor)) {
|
||||
|| currentSettingsValues.isUsuallyFollowedBySpace(codePointBeforeCursor)) {
|
||||
mSpaceState = SPACE_STATE_PHANTOM;
|
||||
}
|
||||
mConnection.endBatchEdit();
|
||||
mKeyboardSwitcher.updateShiftState();
|
||||
mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode());
|
||||
mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(getActualCapsMode(),
|
||||
// Prev word is 1st word before cursor
|
||||
getNthPreviousWordForSuggestion(currentSettingsValues, 1 /* nthPreviousWord */));
|
||||
}
|
||||
|
||||
static final class InputUpdater implements Handler.Callback {
|
||||
|
@ -1986,7 +1988,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
mConnection.commitText(commitParts[0], 0);
|
||||
mSpaceState = SPACE_STATE_PHANTOM;
|
||||
mKeyboardSwitcher.updateShiftState();
|
||||
mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode());
|
||||
mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(
|
||||
getActualCapsMode(), commitParts[0]);
|
||||
++mAutoCommitSequenceNumber;
|
||||
}
|
||||
}
|
||||
|
@ -2295,7 +2298,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
mWordComposer.add(primaryCode, keyX, keyY);
|
||||
// If it's the first letter, make note of auto-caps state
|
||||
if (mWordComposer.size() == 1) {
|
||||
mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode());
|
||||
// We pass 1 to getPreviousWordForSuggestion because we were not composing a word
|
||||
// yet, so the word we want is the 1st word before the cursor.
|
||||
mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(
|
||||
getActualCapsMode(),
|
||||
getNthPreviousWordForSuggestion(currentSettings, 1 /* nthPreviousWord */));
|
||||
}
|
||||
mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1);
|
||||
} else {
|
||||
|
@ -2537,12 +2544,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
}
|
||||
}
|
||||
|
||||
private String getPreviousWordForSuggestion(final SettingsValues currentSettings) {
|
||||
/**
|
||||
* Get the nth previous word before the cursor as context for the suggestion process.
|
||||
* @param currentSettings the current settings values.
|
||||
* @param nthPreviousWord reverse index of the word to get (1-indexed)
|
||||
* @return the nth previous word before the cursor.
|
||||
*/
|
||||
private String getNthPreviousWordForSuggestion(final SettingsValues currentSettings,
|
||||
final int nthPreviousWord) {
|
||||
if (currentSettings.mCurrentLanguageHasSpaces) {
|
||||
// If we are typing in a language with spaces we can just look up the previous
|
||||
// word from textview.
|
||||
return mConnection.getNthPreviousWord(currentSettings,
|
||||
mWordComposer.isComposingWord() ? 2 : 1);
|
||||
return mConnection.getNthPreviousWord(currentSettings, nthPreviousWord);
|
||||
} else {
|
||||
return LastComposedWord.NOT_A_COMPOSED_WORD == mLastComposedWord ? null
|
||||
: mLastComposedWord.mCommittedWord;
|
||||
|
@ -2562,8 +2575,31 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
// should just skip whitespace if any, so 1.
|
||||
final SettingsValues currentSettings = mSettings.getCurrent();
|
||||
final int[] additionalFeaturesOptions = currentSettings.mAdditionalFeaturesSettingValues;
|
||||
final String prevWord = getPreviousWordForSuggestion(currentSettings);
|
||||
suggest.getSuggestedWords(mWordComposer, prevWord, keyboard.getProximityInfo(),
|
||||
|
||||
final String previousWord;
|
||||
if (mWordComposer.isComposingWord() || mWordComposer.isBatchMode()) {
|
||||
previousWord = mWordComposer.getPreviousWord();
|
||||
} else {
|
||||
// Not composing: this is for prediction.
|
||||
// TODO: read the previous word earlier for prediction, like we are doing for
|
||||
// normal suggestions.
|
||||
previousWord = getNthPreviousWordForSuggestion(currentSettings, 1 /* nthPreviousWord*/);
|
||||
}
|
||||
if (DEBUG) {
|
||||
// TODO: this is for checking consistency with older versions. Remove this when
|
||||
// we are confident this is stable.
|
||||
// We're checking the previous word in the text field against the memorized previous
|
||||
// word. If we are composing a word we should have the second word before the cursor
|
||||
// memorized, otherwise we should have the first.
|
||||
final String rereadPrevWord = getNthPreviousWordForSuggestion(currentSettings,
|
||||
mWordComposer.isComposingWord() ? 2 : 1);
|
||||
if (!TextUtils.equals(previousWord, rereadPrevWord)) {
|
||||
throw new RuntimeException("Unexpected previous word: "
|
||||
+ previousWord + " <> " + rereadPrevWord);
|
||||
}
|
||||
}
|
||||
suggest.getSuggestedWords(mWordComposer, mWordComposer.getPreviousWord(),
|
||||
keyboard.getProximityInfo(),
|
||||
currentSettings.mBlockPotentiallyOffensive, currentSettings.mCorrectionEnabled,
|
||||
additionalFeaturesOptions, sessionId, sequenceNumber, callback);
|
||||
}
|
||||
|
@ -2900,7 +2936,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
}
|
||||
}
|
||||
}
|
||||
mWordComposer.setComposingWord(typedWord, mKeyboardSwitcher.getKeyboard());
|
||||
mWordComposer.setComposingWord(typedWord,
|
||||
getNthPreviousWordForSuggestion(currentSettings,
|
||||
// We want the previous word for suggestion. If we have chars in the word
|
||||
// before the cursor, then we want the word before that, hence 2; otherwise,
|
||||
// we want the word immediately before the cursor, hence 1.
|
||||
0 == numberOfCharsInWordBeforeCursor ? 1 : 2),
|
||||
mKeyboardSwitcher.getKeyboard());
|
||||
mWordComposer.setCursorPositionWithinWord(
|
||||
typedWord.codePointCount(0, numberOfCharsInWordBeforeCursor));
|
||||
mConnection.setComposingRegion(
|
||||
|
@ -2978,7 +3020,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
}
|
||||
|
||||
private void restartSuggestionsOnWordBeforeCursor(final String word) {
|
||||
mWordComposer.setComposingWord(word, mKeyboardSwitcher.getKeyboard());
|
||||
mWordComposer.setComposingWord(word,
|
||||
// Previous word is the 2nd word before cursor because we are restarting on the
|
||||
// 1st word before cursor.
|
||||
getNthPreviousWordForSuggestion(mSettings.getCurrent(), 2 /* nthPreviousWord */),
|
||||
mKeyboardSwitcher.getKeyboard());
|
||||
final int length = word.length();
|
||||
mConnection.deleteSurroundingText(length, 0);
|
||||
mConnection.setComposingText(word, 1);
|
||||
|
@ -3044,7 +3090,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
} else {
|
||||
// For languages without spaces, we revert the typed string but the cursor is flush
|
||||
// with the typed word, so we need to resume suggestions right away.
|
||||
mWordComposer.setComposingWord(stringToCommit, mKeyboardSwitcher.getKeyboard());
|
||||
mWordComposer.setComposingWord(stringToCommit, previousWord,
|
||||
mKeyboardSwitcher.getKeyboard());
|
||||
mConnection.setComposingText(stringToCommit, 1);
|
||||
}
|
||||
if (mSettings.isInternal()) {
|
||||
|
|
|
@ -48,6 +48,10 @@ public final class WordComposer {
|
|||
// at any given time. However this is not limited in size, while mPrimaryKeyCodes is limited
|
||||
// to MAX_WORD_LENGTH code points.
|
||||
private final StringBuilder mTypedWord;
|
||||
// The previous word (before the composing word). Used as context for suggestions. May be null
|
||||
// after resetting and before starting a new composing word, or when there is no context like
|
||||
// at the start of text for example.
|
||||
private String mPreviousWord;
|
||||
private String mAutoCorrection;
|
||||
private boolean mIsResumed;
|
||||
private boolean mIsBatchMode;
|
||||
|
@ -85,6 +89,7 @@ public final class WordComposer {
|
|||
mIsBatchMode = false;
|
||||
mCursorPositionWithinWord = 0;
|
||||
mRejectedBatchModeSuggestion = null;
|
||||
mPreviousWord = null;
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
|
@ -101,6 +106,7 @@ public final class WordComposer {
|
|||
mIsBatchMode = source.mIsBatchMode;
|
||||
mCursorPositionWithinWord = source.mCursorPositionWithinWord;
|
||||
mRejectedBatchModeSuggestion = source.mRejectedBatchModeSuggestion;
|
||||
mPreviousWord = source.mPreviousWord;
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
|
@ -118,6 +124,7 @@ public final class WordComposer {
|
|||
mIsBatchMode = false;
|
||||
mCursorPositionWithinWord = 0;
|
||||
mRejectedBatchModeSuggestion = null;
|
||||
mPreviousWord = null;
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
|
@ -284,8 +291,13 @@ public final class WordComposer {
|
|||
/**
|
||||
* Set the currently composing word to the one passed as an argument.
|
||||
* This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity.
|
||||
* @param word the char sequence to set as the composing word.
|
||||
* @param previousWord the previous word, to use as context for suggestions. Can be null if
|
||||
* the context is nil (typically, at start of text).
|
||||
* @param keyboard the keyboard this is typed on, for coordinate info/proximity.
|
||||
*/
|
||||
public void setComposingWord(final CharSequence word, final Keyboard keyboard) {
|
||||
public void setComposingWord(final CharSequence word, final String previousWord,
|
||||
final Keyboard keyboard) {
|
||||
reset();
|
||||
final int length = word.length();
|
||||
for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) {
|
||||
|
@ -293,6 +305,7 @@ public final class WordComposer {
|
|||
addKeyInfo(codePoint, keyboard);
|
||||
}
|
||||
mIsResumed = true;
|
||||
mPreviousWord = previousWord;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -343,6 +356,10 @@ public final class WordComposer {
|
|||
return mTypedWord.toString();
|
||||
}
|
||||
|
||||
public String getPreviousWord() {
|
||||
return mPreviousWord;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the user typed a capital letter as the first letter in the word
|
||||
* @return capitalization preference
|
||||
|
@ -388,18 +405,21 @@ public final class WordComposer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Saves the caps mode at the start of composing.
|
||||
* Saves the caps mode and the previous word at the start of composing.
|
||||
*
|
||||
* WordComposer needs to know about this 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 history
|
||||
* dictionary: if the word was automatically capitalized, we should insert it in all-lower
|
||||
* case but if it's a manual pressing of shift, then it should be inserted as is.
|
||||
* 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
|
||||
* history dictionary: if the word was automatically capitalized, we should insert it in
|
||||
* all-lower case but if it's a manual pressing of shift, then it should be inserted as is.
|
||||
* 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 previousWord the previous word as context for suggestions. May be null if none.
|
||||
*/
|
||||
public void setCapitalizedModeAtStartComposingTime(final int mode) {
|
||||
public void setCapitalizedModeAndPreviousWordAtStartComposingTime(final int mode,
|
||||
final String previousWord) {
|
||||
mCapitalizedMode = mode;
|
||||
mPreviousWord = previousWord;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -451,6 +471,7 @@ public final class WordComposer {
|
|||
mCapsCount = 0;
|
||||
mDigitsCount = 0;
|
||||
mIsBatchMode = false;
|
||||
mPreviousWord = mTypedWord.toString();
|
||||
mTypedWord.setLength(0);
|
||||
mCodePointSize = 0;
|
||||
mTrailingSingleQuotesCount = 0;
|
||||
|
@ -464,7 +485,8 @@ public final class WordComposer {
|
|||
return lastComposedWord;
|
||||
}
|
||||
|
||||
public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) {
|
||||
public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord,
|
||||
final String previousWord) {
|
||||
mPrimaryKeyCodes = lastComposedWord.mPrimaryKeyCodes;
|
||||
mInputPointers.set(lastComposedWord.mInputPointers);
|
||||
mTypedWord.setLength(0);
|
||||
|
@ -475,6 +497,7 @@ public final class WordComposer {
|
|||
mCursorPositionWithinWord = mCodePointSize;
|
||||
mRejectedBatchModeSuggestion = null;
|
||||
mIsResumed = true;
|
||||
mPreviousWord = previousWord;
|
||||
}
|
||||
|
||||
public boolean isBatchMode() {
|
||||
|
|
|
@ -26,8 +26,15 @@ import android.test.suitebuilder.annotation.SmallTest;
|
|||
public class WordComposerTests extends AndroidTestCase {
|
||||
public void testMoveCursor() {
|
||||
final WordComposer wc = new WordComposer();
|
||||
// BMP is the Basic Multilingual Plane, as defined by Unicode. This includes
|
||||
// most characters for most scripts, including all Roman alphabet languages,
|
||||
// CJK, Arabic, Hebrew. Notable exceptions include some emoji and some
|
||||
// very rare Chinese ideograms. BMP characters can be encoded on 2 bytes
|
||||
// in UTF-16, whereas those outside the BMP need 4 bytes.
|
||||
// http://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane
|
||||
final String STR_WITHIN_BMP = "abcdef";
|
||||
wc.setComposingWord(STR_WITHIN_BMP, null);
|
||||
final String PREVWORD = "prevword";
|
||||
wc.setComposingWord(STR_WITHIN_BMP, PREVWORD, null);
|
||||
assertEquals(wc.size(),
|
||||
STR_WITHIN_BMP.codePointCount(0, STR_WITHIN_BMP.length()));
|
||||
assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
|
||||
|
@ -43,13 +50,19 @@ 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(PREVWORD, wc.getPreviousWord());
|
||||
// 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.getPreviousWord());
|
||||
|
||||
// \uD861\uDED7 is 𨛗, a character outside the BMP
|
||||
final String STR_WITH_SUPPLEMENTARY_CHAR = "abcde\uD861\uDED7fgh";
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null, null);
|
||||
assertEquals(wc.size(), STR_WITH_SUPPLEMENTARY_CHAR.codePointCount(0,
|
||||
STR_WITH_SUPPLEMENTARY_CHAR.length()));
|
||||
assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
|
||||
|
@ -59,34 +72,40 @@ public class WordComposerTests extends AndroidTestCase {
|
|||
assertTrue(wc.isCursorFrontOrMiddleOfComposingWord());
|
||||
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1));
|
||||
assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
|
||||
assertNull(wc.getPreviousWord());
|
||||
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, STR_WITHIN_BMP, null);
|
||||
wc.setCursorPositionWithinWord(3);
|
||||
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7));
|
||||
assertEquals(STR_WITHIN_BMP, wc.getPreviousWord());
|
||||
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, STR_WITH_SUPPLEMENTARY_CHAR, null);
|
||||
wc.setCursorPositionWithinWord(3);
|
||||
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7));
|
||||
assertEquals(STR_WITH_SUPPLEMENTARY_CHAR, wc.getPreviousWord());
|
||||
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, STR_WITHIN_BMP, null);
|
||||
wc.setCursorPositionWithinWord(3);
|
||||
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-3));
|
||||
assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-1));
|
||||
assertEquals(STR_WITHIN_BMP, wc.getPreviousWord());
|
||||
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null, null);
|
||||
wc.setCursorPositionWithinWord(3);
|
||||
assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-9));
|
||||
assertNull(wc.getPreviousWord());
|
||||
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, STR_WITH_SUPPLEMENTARY_CHAR, null);
|
||||
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-10));
|
||||
assertEquals(STR_WITH_SUPPLEMENTARY_CHAR, wc.getPreviousWord());
|
||||
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null, null);
|
||||
assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-11));
|
||||
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null, null);
|
||||
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0));
|
||||
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
|
||||
wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null, null);
|
||||
wc.setCursorPositionWithinWord(2);
|
||||
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue