am 914078fd
: Fix a bug where recorrection would stop on connectors
* commit '914078fd9198aeb3d7ffa034562321d688d588f7': Fix a bug where recorrection would stop on connectors
This commit is contained in:
commit
1708ff6e54
4 changed files with 54 additions and 26 deletions
|
@ -623,14 +623,24 @@ public final class RichInputConnection {
|
||||||
return Arrays.binarySearch(sortedSeparators, code) >= 0;
|
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.
|
* 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_*
|
* @param scriptId the script we consider to be writing words, as one of ScriptUtils.SCRIPT_*
|
||||||
* @return a range containing the text surrounding the cursor
|
* @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();
|
mIC = mParent.getCurrentInputConnection();
|
||||||
if (mIC == null) {
|
if (mIC == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -647,8 +657,7 @@ public final class RichInputConnection {
|
||||||
int startIndexInBefore = before.length();
|
int startIndexInBefore = before.length();
|
||||||
while (startIndexInBefore > 0) {
|
while (startIndexInBefore > 0) {
|
||||||
final int codePoint = Character.codePointBefore(before, startIndexInBefore);
|
final int codePoint = Character.codePointBefore(before, startIndexInBefore);
|
||||||
if (isSeparator(codePoint, sortedSeparators)
|
if (!isPartOfCompositionForScript(codePoint, spacingAndPunctuations, scriptId)) {
|
||||||
|| !ScriptUtils.isLetterPartOfScript(codePoint, scriptId)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
--startIndexInBefore;
|
--startIndexInBefore;
|
||||||
|
@ -661,8 +670,7 @@ public final class RichInputConnection {
|
||||||
int endIndexInAfter = -1;
|
int endIndexInAfter = -1;
|
||||||
while (++endIndexInAfter < after.length()) {
|
while (++endIndexInAfter < after.length()) {
|
||||||
final int codePoint = Character.codePointAt(after, endIndexInAfter);
|
final int codePoint = Character.codePointAt(after, endIndexInAfter);
|
||||||
if (isSeparator(codePoint, sortedSeparators)
|
if (!isPartOfCompositionForScript(codePoint, spacingAndPunctuations, scriptId)) {
|
||||||
|| !ScriptUtils.isLetterPartOfScript(codePoint, scriptId)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (Character.isSupplementaryCodePoint(codePoint)) {
|
if (Character.isSupplementaryCodePoint(codePoint)) {
|
||||||
|
|
|
@ -1478,8 +1478,7 @@ public final class InputLogic {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final TextRange range = mConnection.getWordRangeAtCursor(
|
final TextRange range = mConnection.getWordRangeAtCursor(
|
||||||
settingsValues.mSpacingAndPunctuations.mSortedWordSeparators,
|
settingsValues.mSpacingAndPunctuations, currentKeyboardScriptId);
|
||||||
currentKeyboardScriptId);
|
|
||||||
if (null == range) return; // Happens if we don't have an input connection at all
|
if (null == range) return; // Happens if we don't have an input connection at all
|
||||||
if (range.length() <= 0) {
|
if (range.length() <= 0) {
|
||||||
// Race condition, or touching a word in a non-supported script.
|
// Race condition, or touching a word in a non-supported script.
|
||||||
|
|
|
@ -18,6 +18,7 @@ package com.android.inputmethod.latin.settings;
|
||||||
|
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
|
||||||
|
import com.android.inputmethod.annotations.UsedForTesting;
|
||||||
import com.android.inputmethod.keyboard.internal.MoreKeySpec;
|
import com.android.inputmethod.keyboard.internal.MoreKeySpec;
|
||||||
import com.android.inputmethod.latin.Constants;
|
import com.android.inputmethod.latin.Constants;
|
||||||
import com.android.inputmethod.latin.PunctuationSuggestions;
|
import com.android.inputmethod.latin.PunctuationSuggestions;
|
||||||
|
@ -68,6 +69,22 @@ public final class SpacingAndPunctuations {
|
||||||
mSuggestPuncList = PunctuationSuggestions.newPunctuationSuggestions(suggestPuncsSpec);
|
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) {
|
public boolean isWordSeparator(final int code) {
|
||||||
return Arrays.binarySearch(mSortedWordSeparators, code) >= 0;
|
return Arrays.binarySearch(mSortedWordSeparators, code) >= 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -215,18 +215,23 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
|
||||||
"abc 'def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO);
|
"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() {
|
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();
|
ExtractedText et = new ExtractedText();
|
||||||
final MockInputMethodService mockInputMethodService = new MockInputMethodService();
|
final MockInputMethodService mockInputMethodService = new MockInputMethodService();
|
||||||
final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
|
final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
|
||||||
|
@ -249,10 +254,9 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
|
||||||
|
|
||||||
// splitting on supplementary character
|
// splitting on supplementary character
|
||||||
mockInputMethodService.setInputConnection(
|
mockInputMethodService.setInputConnection(
|
||||||
new MockConnection("one word" + SUPPLEMENTARY_CHAR + "wo", "rd", et));
|
new MockConnection("one word" + SUPPLEMENTARY_CHAR_STRING + "wo", "rd", et));
|
||||||
ic.beginBatchEdit();
|
ic.beginBatchEdit();
|
||||||
r = ic.getWordRangeAtCursor(StringUtils.toSortedCodePointArray(SUPPLEMENTARY_CHAR),
|
r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_LATIN);
|
||||||
ScriptUtils.SCRIPT_LATIN);
|
|
||||||
ic.endBatchEdit();
|
ic.endBatchEdit();
|
||||||
assertTrue(TextUtils.equals("word", r.mWord));
|
assertTrue(TextUtils.equals("word", r.mWord));
|
||||||
|
|
||||||
|
@ -260,8 +264,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
|
||||||
mockInputMethodService.setInputConnection(
|
mockInputMethodService.setInputConnection(
|
||||||
new MockConnection(HIRAGANA_WORD + "wo", "rd" + GREEK_WORD, et));
|
new MockConnection(HIRAGANA_WORD + "wo", "rd" + GREEK_WORD, et));
|
||||||
ic.beginBatchEdit();
|
ic.beginBatchEdit();
|
||||||
r = ic.getWordRangeAtCursor(StringUtils.toSortedCodePointArray(SUPPLEMENTARY_CHAR),
|
r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_LATIN);
|
||||||
ScriptUtils.SCRIPT_LATIN);
|
|
||||||
ic.endBatchEdit();
|
ic.endBatchEdit();
|
||||||
assertTrue(TextUtils.equals("word", r.mWord));
|
assertTrue(TextUtils.equals("word", r.mWord));
|
||||||
|
|
||||||
|
@ -269,8 +272,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
|
||||||
mockInputMethodService.setInputConnection(
|
mockInputMethodService.setInputConnection(
|
||||||
new MockConnection("text" + GREEK_WORD, "text", et));
|
new MockConnection("text" + GREEK_WORD, "text", et));
|
||||||
ic.beginBatchEdit();
|
ic.beginBatchEdit();
|
||||||
r = ic.getWordRangeAtCursor(StringUtils.toSortedCodePointArray(SUPPLEMENTARY_CHAR),
|
r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_GREEK);
|
||||||
ScriptUtils.SCRIPT_GREEK);
|
|
||||||
ic.endBatchEdit();
|
ic.endBatchEdit();
|
||||||
assertTrue(TextUtils.equals(GREEK_WORD, r.mWord));
|
assertTrue(TextUtils.equals(GREEK_WORD, r.mWord));
|
||||||
}
|
}
|
||||||
|
@ -286,6 +288,8 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void helpTestGetSuggestionSpansAtWord(final int cursorPos) {
|
private void helpTestGetSuggestionSpansAtWord(final int cursorPos) {
|
||||||
|
final SpacingAndPunctuations SPACE = new SpacingAndPunctuations(
|
||||||
|
mSpacingAndPunctuations, new int[] { Constants.CODE_SPACE });
|
||||||
final MockInputMethodService mockInputMethodService = new MockInputMethodService();
|
final MockInputMethodService mockInputMethodService = new MockInputMethodService();
|
||||||
final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
|
final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue