From 10581e68af1de7d0b5d2c88927ad7bbad7dad600 Mon Sep 17 00:00:00 2001
From: Jean Chalard <jchalard@google.com>
Date: Tue, 8 Oct 2013 13:06:16 +0900
Subject: [PATCH] Make the sentence separator a resource.

This will help handing correctly the armenian full stop.

Bug: 10082781
Change-Id: Id7bb219ebd89daba203216eab362d1cc26a65a36
---
 java/res/values-hy/donottranslate.xml         |  3 +
 java/res/values/donottranslate.xml            |  3 +
 .../android/inputmethod/latin/LatinIME.java   | 15 ++--
 .../latin/RichInputConnection.java            |  8 +-
 .../latin/settings/SettingsValues.java        |  4 +
 .../latin/utils/CapsModeUtils.java            | 20 ++---
 .../latin/utils/CapsModeUtilsTests.java       | 82 ++++++++++---------
 7 files changed, 73 insertions(+), 62 deletions(-)

diff --git a/java/res/values-hy/donottranslate.xml b/java/res/values-hy/donottranslate.xml
index 4a6d188fbe..7b0c56655a 100644
--- a/java/res/values-hy/donottranslate.xml
+++ b/java/res/values-hy/donottranslate.xml
@@ -26,4 +26,7 @@
     <!-- Symbols that separate words. Adding armenian period and comma. -->
     <!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
     <string name="symbols_word_separators">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"&#x0589;&#x055D;</string>
+    <!-- The sentence separator code point, for capitalization -->
+    <!-- U+0589: "Ö‰" ARMENIAN FULL STOP   ; 589h = 1417d -->
+    <integer name="sentence_separator">1417</integer>
 </resources>
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml
index 42e692d2f3..4733aa257f 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -31,6 +31,9 @@
     <string name="symbols_word_separators">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
     <!-- Word connectors -->
     <string name="symbols_word_connectors">\'-</string>
+    <!-- The sentence separator code point, for capitalization -->
+    <!-- U+002E: "." FULL STOP   ; 2Eh = 46d -->
+    <integer name="sentence_separator">46</integer>
     <!-- Whether this language uses spaces between words -->
     <bool name="current_language_has_spaces">true</bool>
 
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 0e93590a3a..4d7e43e17f 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1411,14 +1411,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     // Called from the KeyboardSwitcher which needs to know auto caps state to display
     // the right layout.
     public int getCurrentAutoCapsState() {
-        if (!mSettings.getCurrent().mAutoCap) return Constants.TextUtils.CAP_MODE_OFF;
+        final SettingsValues currentSettingsValues = mSettings.getCurrent();
+        if (!currentSettingsValues.mAutoCap) return Constants.TextUtils.CAP_MODE_OFF;
 
         final EditorInfo ei = getCurrentInputEditorInfo();
         if (ei == null) return Constants.TextUtils.CAP_MODE_OFF;
         final int inputType = ei.inputType;
         // Warning: this depends on mSpaceState, which may not be the most current value. If
         // mSpaceState gets updated later, whoever called this may need to be told about it.
-        return mConnection.getCursorCapsMode(inputType, mSubtypeSwitcher.getCurrentSubtypeLocale(),
+        return mConnection.getCursorCapsMode(inputType, currentSettingsValues,
                 SPACE_STATE_PHANTOM == mSpaceState);
     }
 
@@ -1459,9 +1460,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     }
 
     private boolean maybeDoubleSpacePeriod() {
-        final SettingsValues settingsValues = mSettings.getCurrent();
-        if (!settingsValues.mCorrectionEnabled) return false;
-        if (!settingsValues.mUseDoubleSpacePeriod) return false;
+        final SettingsValues currentSettingsValues = mSettings.getCurrent();
+        if (!currentSettingsValues.mCorrectionEnabled) return false;
+        if (!currentSettingsValues.mUseDoubleSpacePeriod) return false;
         if (!mHandler.isAcceptingDoubleSpacePeriod()) return false;
         // We only do this when we see two spaces and an accepted code point before the cursor.
         // The code point may be a surrogate pair but the two spaces may not, so we need 4 chars.
@@ -1480,7 +1481,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         if (canBeFollowedByDoubleSpacePeriod(firstCodePoint)) {
             mHandler.cancelDoubleSpacePeriodTimer();
             mConnection.deleteSurroundingText(2, 0);
-            final String textToInsert = ". ";
+            final String textToInsert = new String(
+                    new int[] { currentSettingsValues.mSentenceSeparator, Constants.CODE_SPACE },
+                    0, 2);
             mConnection.commitText(textToInsert, 1);
             if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
                 ResearchLogger.latinIME_maybeDoubleSpacePeriod(textToInsert,
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 8580a6e546..e43cab5ca0 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -245,11 +245,11 @@ public final class RichInputConnection {
      * American English, it's just the most common set of rules for English).
      *
      * @param inputType a mask of the caps modes to test for.
-     * @param locale what language should be considered.
+     * @param settingsValues the values of the settings to use for locale and separators.
      * @param hasSpaceBefore if we should consider there should be a space after the string.
      * @return the caps modes that should be on as a set of bits
      */
-    public int getCursorCapsMode(final int inputType, final Locale locale,
+    public int getCursorCapsMode(final int inputType, final SettingsValues settingsValues,
             final boolean hasSpaceBefore) {
         mIC = mParent.getCurrentInputConnection();
         if (null == mIC) return Constants.TextUtils.CAP_MODE_OFF;
@@ -277,8 +277,8 @@ public final class RichInputConnection {
         }
         // This never calls InputConnection#getCapsMode - in fact, it's a static method that
         // never blocks or initiates IPC.
-        return CapsModeUtils.getCapsMode(mCommittedTextBeforeComposingText, inputType, locale,
-                hasSpaceBefore);
+        return CapsModeUtils.getCapsMode(mCommittedTextBeforeComposingText, inputType,
+                settingsValues, hasSpaceBefore);
     }
 
     public int getCodePointBeforeCursor() {
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index 2abcdc7fa6..f331c78e54 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -24,6 +24,7 @@ import android.view.inputmethod.EditorInfo;
 
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.keyboard.internal.KeySpecParser;
+import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.Dictionary;
 import com.android.inputmethod.latin.InputAttributes;
 import com.android.inputmethod.latin.R;
@@ -57,6 +58,7 @@ public final class SettingsValues {
     public final int[] mWordConnectors;
     public final SuggestedWords mSuggestPuncList;
     public final String mWordSeparators;
+    public final int mSentenceSeparator;
     public final CharSequence mHintToSaveText;
     public final boolean mCurrentLanguageHasSpaces;
 
@@ -120,6 +122,7 @@ public final class SettingsValues {
                 R.string.suggested_punctuations));
         mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
         mWordSeparators = res.getString(R.string.symbols_word_separators);
+        mSentenceSeparator = res.getInteger(R.integer.sentence_separator);
         mHintToSaveText = res.getText(R.string.hint_add_to_dictionary);
         mCurrentLanguageHasSpaces = res.getBoolean(R.bool.current_language_has_spaces);
 
@@ -187,6 +190,7 @@ public final class SettingsValues {
         Arrays.sort(mSymbolsFollowedBySpace);
         mWordConnectors = new int[] { '\'', '-' };
         Arrays.sort(mWordConnectors);
+        mSentenceSeparator = Constants.CODE_PERIOD;
         final String[] suggestPuncsSpec = new String[] { "!", "?", ",", ":", ";" };
         mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
         mWordSeparators = "&\t \n()[]{}*&<>+=|.,;:!?/_\"";
diff --git a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
index 60b24d5d52..3d4404a985 100644
--- a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
@@ -21,6 +21,7 @@ import android.text.TextUtils;
 
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.WordComposer;
+import com.android.inputmethod.latin.settings.SettingsValues;
 
 import java.util.Locale;
 
@@ -60,11 +61,6 @@ public final class CapsModeUtils {
                 || WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED == mode;
     }
 
-    private static boolean isPeriod(final int codePoint) {
-        // TODO: make this a resource.
-        return codePoint == Constants.CODE_PERIOD || codePoint == Constants.CODE_ARMENIAN_PERIOD;
-    }
-
     /**
      * Determine what caps mode should be in effect at the current offset in
      * the text. Only the mode bits set in <var>reqModes</var> will be
@@ -78,7 +74,7 @@ public final class CapsModeUtils {
      * @param reqModes The modes to be checked: may be any combination of
      * {@link TextUtils#CAP_MODE_CHARACTERS}, {@link TextUtils#CAP_MODE_WORDS}, and
      * {@link TextUtils#CAP_MODE_SENTENCES}.
-     * @param locale The locale to consider for capitalization rules
+     * @param settingsValues The current settings values.
      * @param hasSpaceBefore Whether we should consider there is a space inserted at the end of cs
      *
      * @return Returns the actual capitalization modes that can be in effect
@@ -86,8 +82,8 @@ public final class CapsModeUtils {
      * {@link TextUtils#CAP_MODE_CHARACTERS}, {@link TextUtils#CAP_MODE_WORDS}, and
      * {@link TextUtils#CAP_MODE_SENTENCES}.
      */
-    public static int getCapsMode(final CharSequence cs, final int reqModes, final Locale locale,
-            final boolean hasSpaceBefore) {
+    public static int getCapsMode(final CharSequence cs, final int reqModes,
+            final SettingsValues settingsValues, final boolean hasSpaceBefore) {
         // Quick description of what we want to do:
         // CAP_MODE_CHARACTERS is always on.
         // CAP_MODE_WORDS is on if there is some whitespace before the cursor.
@@ -172,7 +168,7 @@ public final class CapsModeUtils {
         // mark as the exact thing quoted and handling the surrounding punctuation independently,
         // e.g. <<Did he say, "let's go home"?>>
         // Hence, specifically for English, we treat this special case here.
-        if (Locale.ENGLISH.getLanguage().equals(locale.getLanguage())) {
+        if (Locale.ENGLISH.getLanguage().equals(settingsValues.mLocale.getLanguage())) {
             for (; j > 0; j--) {
                 // Here we look to go over any closing punctuation. This is because in dominant
                 // variants of English, the final period is placed within double quotes and maybe
@@ -195,7 +191,7 @@ public final class CapsModeUtils {
         if (c == Constants.CODE_QUESTION_MARK || c == Constants.CODE_EXCLAMATION_MARK) {
             return (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_SENTENCES) & reqModes;
         }
-        if (!isPeriod(c) || j <= 0) {
+        if (settingsValues.mSentenceSeparator != c || j <= 0) {
             return (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_WORDS) & reqModes;
         }
 
@@ -245,7 +241,7 @@ public final class CapsModeUtils {
             case WORD:
                 if (Character.isLetter(c)) {
                     state = WORD;
-                } else if (isPeriod(c)) {
+                } else if (settingsValues.mSentenceSeparator == c) {
                     state = PERIOD;
                 } else {
                     return caps;
@@ -261,7 +257,7 @@ public final class CapsModeUtils {
             case LETTER:
                 if (Character.isLetter(c)) {
                     state = LETTER;
-                } else if (isPeriod(c)) {
+                } else if (settingsValues.mSentenceSeparator == c) {
                     state = PERIOD;
                 } else {
                     return noCaps;
diff --git a/tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java
index cf3bdd6801..1fd5c989a5 100644
--- a/tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.latin.utils;
 
+import com.android.inputmethod.latin.settings.SettingsValues;
+
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.TextUtils;
@@ -25,64 +27,64 @@ import java.util.Locale;
 @SmallTest
 public class CapsModeUtilsTests extends AndroidTestCase {
     private static void onePathForCaps(final CharSequence cs, final int expectedResult,
-            final int mask, final Locale l, final boolean hasSpaceBefore) {
+            final int mask, final SettingsValues sv, final boolean hasSpaceBefore) {
         int oneTimeResult = expectedResult & mask;
         assertEquals("After >" + cs + "<", oneTimeResult,
-                CapsModeUtils.getCapsMode(cs, mask, l, hasSpaceBefore));
+                CapsModeUtils.getCapsMode(cs, mask, sv, hasSpaceBefore));
     }
 
     private static void allPathsForCaps(final CharSequence cs, final int expectedResult,
-            final Locale l, final boolean hasSpaceBefore) {
+            final SettingsValues sv, final boolean hasSpaceBefore) {
         final int c = TextUtils.CAP_MODE_CHARACTERS;
         final int w = TextUtils.CAP_MODE_WORDS;
         final int s = TextUtils.CAP_MODE_SENTENCES;
-        onePathForCaps(cs, expectedResult, c | w | s, l, hasSpaceBefore);
-        onePathForCaps(cs, expectedResult, w | s, l, hasSpaceBefore);
-        onePathForCaps(cs, expectedResult, c | s, l, hasSpaceBefore);
-        onePathForCaps(cs, expectedResult, c | w, l, hasSpaceBefore);
-        onePathForCaps(cs, expectedResult, c, l, hasSpaceBefore);
-        onePathForCaps(cs, expectedResult, w, l, hasSpaceBefore);
-        onePathForCaps(cs, expectedResult, s, l, hasSpaceBefore);
+        onePathForCaps(cs, expectedResult, c | w | s, sv, hasSpaceBefore);
+        onePathForCaps(cs, expectedResult, w | s, sv, hasSpaceBefore);
+        onePathForCaps(cs, expectedResult, c | s, sv, hasSpaceBefore);
+        onePathForCaps(cs, expectedResult, c | w, sv, hasSpaceBefore);
+        onePathForCaps(cs, expectedResult, c, sv, hasSpaceBefore);
+        onePathForCaps(cs, expectedResult, w, sv, hasSpaceBefore);
+        onePathForCaps(cs, expectedResult, s, sv, hasSpaceBefore);
     }
 
     public void testGetCapsMode() {
         final int c = TextUtils.CAP_MODE_CHARACTERS;
         final int w = TextUtils.CAP_MODE_WORDS;
         final int s = TextUtils.CAP_MODE_SENTENCES;
-        Locale l = Locale.ENGLISH;
-        allPathsForCaps("", c | w | s, l, false);
-        allPathsForCaps("Word", c, l, false);
-        allPathsForCaps("Word.", c, l, false);
-        allPathsForCaps("Word ", c | w, l, false);
-        allPathsForCaps("Word. ", c | w | s, l, false);
-        allPathsForCaps("Word..", c, l, false);
-        allPathsForCaps("Word.. ", c | w | s, l, false);
-        allPathsForCaps("Word... ", c | w | s, l, false);
-        allPathsForCaps("Word ... ", c | w | s, l, false);
-        allPathsForCaps("Word . ", c | w, l, false);
-        allPathsForCaps("In the U.S ", c | w, l, false);
-        allPathsForCaps("In the U.S. ", c | w, l, false);
-        allPathsForCaps("Some stuff (e.g. ", c | w, l, false);
-        allPathsForCaps("In the U.S.. ", c | w | s, l, false);
-        allPathsForCaps("\"Word.\" ", c | w | s, l, false);
-        allPathsForCaps("\"Word\". ", c | w | s, l, false);
-        allPathsForCaps("\"Word\" ", c | w, l, false);
+        SettingsValues sv = SettingsValues.makeDummySettingsValuesForTest(Locale.ENGLISH);
+        allPathsForCaps("", c | w | s, sv, false);
+        allPathsForCaps("Word", c, sv, false);
+        allPathsForCaps("Word.", c, sv, false);
+        allPathsForCaps("Word ", c | w, sv, false);
+        allPathsForCaps("Word. ", c | w | s, sv, false);
+        allPathsForCaps("Word..", c, sv, false);
+        allPathsForCaps("Word.. ", c | w | s, sv, false);
+        allPathsForCaps("Word... ", c | w | s, sv, false);
+        allPathsForCaps("Word ... ", c | w | s, sv, false);
+        allPathsForCaps("Word . ", c | w, sv, false);
+        allPathsForCaps("In the U.S ", c | w, sv, false);
+        allPathsForCaps("In the U.S. ", c | w, sv, false);
+        allPathsForCaps("Some stuff (e.g. ", c | w, sv, false);
+        allPathsForCaps("In the U.S.. ", c | w | s, sv, false);
+        allPathsForCaps("\"Word.\" ", c | w | s, sv, false);
+        allPathsForCaps("\"Word\". ", c | w | s, sv, false);
+        allPathsForCaps("\"Word\" ", c | w, sv, false);
 
         // Test for phantom space
-        allPathsForCaps("Word", c | w, l, true);
-        allPathsForCaps("Word.", c | w | s, l, true);
+        allPathsForCaps("Word", c | w, sv, true);
+        allPathsForCaps("Word.", c | w | s, sv, true);
 
         // Tests after some whitespace
-        allPathsForCaps("Word\n", c | w | s, l, false);
-        allPathsForCaps("Word\n", c | w | s, l, true);
-        allPathsForCaps("Word\n ", c | w | s, l, true);
-        allPathsForCaps("Word.\n", c | w | s, l, false);
-        allPathsForCaps("Word.\n", c | w | s, l, true);
-        allPathsForCaps("Word.\n ", c | w | s, l, true);
+        allPathsForCaps("Word\n", c | w | s, sv, false);
+        allPathsForCaps("Word\n", c | w | s, sv, true);
+        allPathsForCaps("Word\n ", c | w | s, sv, true);
+        allPathsForCaps("Word.\n", c | w | s, sv, false);
+        allPathsForCaps("Word.\n", c | w | s, sv, true);
+        allPathsForCaps("Word.\n ", c | w | s, sv, true);
 
-        l = Locale.FRENCH;
-        allPathsForCaps("\"Word.\" ", c | w, l, false);
-        allPathsForCaps("\"Word\". ", c | w | s, l, false);
-        allPathsForCaps("\"Word\" ", c | w, l, false);
+        sv = SettingsValues.makeDummySettingsValuesForTest(Locale.FRENCH);
+        allPathsForCaps("\"Word.\" ", c | w, sv, false);
+        allPathsForCaps("\"Word\". ", c | w | s, sv, false);
+        allPathsForCaps("\"Word\" ", c | w, sv, false);
     }
 }
-- 
GitLab