Fix a bug where recorrection would stop on connectors

Bug: 16733686
Change-Id: I7a9f79a81e33a1f5bf5f3daf0b78d0f1e4447e7a
This commit is contained in:
Jean Chalard 2014-09-03 15:27:01 +09:00
parent 42665f0ee2
commit 914078fd91
4 changed files with 54 additions and 26 deletions

View File

@ -623,14 +623,24 @@ public final class RichInputConnection {
return Arrays.binarySearch(sortedSeparators, code) >= 0;
}
private static boolean isPartOfCompositionForScript(final int codePoint,
final SpacingAndPunctuations spacingAndPunctuations, final int scriptId) {
// We always consider word connectors part of compositions.
return spacingAndPunctuations.isWordConnector(codePoint)
// Otherwise, it's part of composition if it's part of script and not a separator.
|| (!spacingAndPunctuations.isWordSeparator(codePoint)
&& ScriptUtils.isLetterPartOfScript(codePoint, scriptId));
}
/**
* Returns the text surrounding the cursor.
*
* @param sortedSeparators a sorted array of code points that split words.
* @param spacingAndPunctuations the rules for spacing and punctuation
* @param scriptId the script we consider to be writing words, as one of ScriptUtils.SCRIPT_*
* @return a range containing the text surrounding the cursor
*/
public TextRange getWordRangeAtCursor(final int[] sortedSeparators, final int scriptId) {
public TextRange getWordRangeAtCursor(final SpacingAndPunctuations spacingAndPunctuations,
final int scriptId) {
mIC = mParent.getCurrentInputConnection();
if (mIC == null) {
return null;
@ -647,8 +657,7 @@ public final class RichInputConnection {
int startIndexInBefore = before.length();
while (startIndexInBefore > 0) {
final int codePoint = Character.codePointBefore(before, startIndexInBefore);
if (isSeparator(codePoint, sortedSeparators)
|| !ScriptUtils.isLetterPartOfScript(codePoint, scriptId)) {
if (!isPartOfCompositionForScript(codePoint, spacingAndPunctuations, scriptId)) {
break;
}
--startIndexInBefore;
@ -661,8 +670,7 @@ public final class RichInputConnection {
int endIndexInAfter = -1;
while (++endIndexInAfter < after.length()) {
final int codePoint = Character.codePointAt(after, endIndexInAfter);
if (isSeparator(codePoint, sortedSeparators)
|| !ScriptUtils.isLetterPartOfScript(codePoint, scriptId)) {
if (!isPartOfCompositionForScript(codePoint, spacingAndPunctuations, scriptId)) {
break;
}
if (Character.isSupplementaryCodePoint(codePoint)) {

View File

@ -1478,8 +1478,7 @@ public final class InputLogic {
return;
}
final TextRange range = mConnection.getWordRangeAtCursor(
settingsValues.mSpacingAndPunctuations.mSortedWordSeparators,
currentKeyboardScriptId);
settingsValues.mSpacingAndPunctuations, currentKeyboardScriptId);
if (null == range) return; // Happens if we don't have an input connection at all
if (range.length() <= 0) {
// Race condition, or touching a word in a non-supported script.

View File

@ -18,6 +18,7 @@ package com.android.inputmethod.latin.settings;
import android.content.res.Resources;
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.internal.MoreKeySpec;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.PunctuationSuggestions;
@ -68,6 +69,22 @@ public final class SpacingAndPunctuations {
mSuggestPuncList = PunctuationSuggestions.newPunctuationSuggestions(suggestPuncsSpec);
}
@UsedForTesting
public SpacingAndPunctuations(final SpacingAndPunctuations model,
final int[] overrideSortedWordSeparators) {
mSortedSymbolsPrecededBySpace = model.mSortedSymbolsPrecededBySpace;
mSortedSymbolsFollowedBySpace = model.mSortedSymbolsFollowedBySpace;
mSortedSymbolsClusteringTogether = model.mSortedSymbolsClusteringTogether;
mSortedWordConnectors = model.mSortedWordConnectors;
mSortedWordSeparators = overrideSortedWordSeparators;
mSuggestPuncList = model.mSuggestPuncList;
mSentenceSeparator = model.mSentenceSeparator;
mSentenceSeparatorAndSpace = model.mSentenceSeparatorAndSpace;
mCurrentLanguageHasSpaces = model.mCurrentLanguageHasSpaces;
mUsesAmericanTypography = model.mUsesAmericanTypography;
mUsesGermanRules = model.mUsesGermanRules;
}
public boolean isWordSeparator(final int code) {
return Arrays.binarySearch(mSortedWordSeparators, code) >= 0;
}

View File

@ -215,18 +215,23 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
"abc 'def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO);
}
/**
* Test logic in getting the word range at the cursor.
*/
private static final int[] SPACE = { Constants.CODE_SPACE };
static final int[] TAB = { Constants.CODE_TAB };
private static final int[] SPACE_TAB = StringUtils.toSortedCodePointArray(" \t");
// A character that needs surrogate pair to represent its code point (U+2008A).
private static final String SUPPLEMENTARY_CHAR = "\uD840\uDC8A";
private static final String HIRAGANA_WORD = "\u3042\u3044\u3046\u3048\u304A"; // あいうえお
private static final String GREEK_WORD = "\u03BA\u03B1\u03B9"; // και
public void testGetWordRangeAtCursor() {
/**
* Test logic in getting the word range at the cursor.
*/
final SpacingAndPunctuations SPACE = new SpacingAndPunctuations(
mSpacingAndPunctuations, new int[] { Constants.CODE_SPACE });
final SpacingAndPunctuations TAB = new SpacingAndPunctuations(
mSpacingAndPunctuations, new int[] { Constants.CODE_TAB });
final int[] SPACE_TAB = StringUtils.toSortedCodePointArray(" \t");
// A character that needs surrogate pair to represent its code point (U+2008A).
final String SUPPLEMENTARY_CHAR_STRING = "\uD840\uDC8A";
final SpacingAndPunctuations SUPPLEMENTARY_CHAR = new SpacingAndPunctuations(
mSpacingAndPunctuations, StringUtils.toSortedCodePointArray(
SUPPLEMENTARY_CHAR_STRING));
final String HIRAGANA_WORD = "\u3042\u3044\u3046\u3048\u304A"; // あいうえお
final String GREEK_WORD = "\u03BA\u03B1\u03B9"; // και
ExtractedText et = new ExtractedText();
final MockInputMethodService mockInputMethodService = new MockInputMethodService();
final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
@ -249,10 +254,9 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
// splitting on supplementary character
mockInputMethodService.setInputConnection(
new MockConnection("one word" + SUPPLEMENTARY_CHAR + "wo", "rd", et));
new MockConnection("one word" + SUPPLEMENTARY_CHAR_STRING + "wo", "rd", et));
ic.beginBatchEdit();
r = ic.getWordRangeAtCursor(StringUtils.toSortedCodePointArray(SUPPLEMENTARY_CHAR),
ScriptUtils.SCRIPT_LATIN);
r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_LATIN);
ic.endBatchEdit();
assertTrue(TextUtils.equals("word", r.mWord));
@ -260,8 +264,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
mockInputMethodService.setInputConnection(
new MockConnection(HIRAGANA_WORD + "wo", "rd" + GREEK_WORD, et));
ic.beginBatchEdit();
r = ic.getWordRangeAtCursor(StringUtils.toSortedCodePointArray(SUPPLEMENTARY_CHAR),
ScriptUtils.SCRIPT_LATIN);
r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_LATIN);
ic.endBatchEdit();
assertTrue(TextUtils.equals("word", r.mWord));
@ -269,8 +272,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
mockInputMethodService.setInputConnection(
new MockConnection("text" + GREEK_WORD, "text", et));
ic.beginBatchEdit();
r = ic.getWordRangeAtCursor(StringUtils.toSortedCodePointArray(SUPPLEMENTARY_CHAR),
ScriptUtils.SCRIPT_GREEK);
r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_GREEK);
ic.endBatchEdit();
assertTrue(TextUtils.equals(GREEK_WORD, r.mWord));
}
@ -286,6 +288,8 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
}
private void helpTestGetSuggestionSpansAtWord(final int cursorPos) {
final SpacingAndPunctuations SPACE = new SpacingAndPunctuations(
mSpacingAndPunctuations, new int[] { Constants.CODE_SPACE });
final MockInputMethodService mockInputMethodService = new MockInputMethodService();
final RichInputConnection ic = new RichInputConnection(mockInputMethodService);