am 0eaa25e0: am 914078fd: Fix a bug where recorrection would stop on connectors

* commit '0eaa25e0b344e458873bb5626130d366ac395ef3':
  Fix a bug where recorrection would stop on connectors
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 6b6384c..b5d42dd 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -623,14 +623,24 @@
         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 @@
         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 @@
         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)) {
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 89aea43..5ab3571 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -1478,8 +1478,7 @@
             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.
diff --git a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
index b8d2a22..49d8110 100644
--- a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
+++ b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
@@ -18,6 +18,7 @@
 
 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 @@
         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;
     }
diff --git a/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java b/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java
index 1999224..f9d7226 100644
--- a/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java
+++ b/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java
@@ -215,18 +215,23 @@
                 "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 @@
 
         // 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 @@
         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 @@
         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 @@
     }
 
     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);