From cfdb1b8d2604e1d7d54ff36e8b5d1607ec2e0fb7 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 23 May 2014 16:46:48 +0900 Subject: [PATCH] Fix some auto-caps problems: - (mainly for Spanish) auto-caps after inverted bang and what - (German only) don't auto-cap after digits-period-space Bug: 15177663 Bug: 12206753 Change-Id: Ia214bc067319469d9debbbfbdcb1dcff980847f0 --- .../android/inputmethod/latin/Constants.java | 3 +- .../latin/utils/CapsModeUtils.java | 43 +++++++++++++++++-- .../inputmethod/latin/ShiftModeTests.java | 31 +++++++++++++ 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java index 67ca59540..efc5a618b 100644 --- a/java/src/com/android/inputmethod/latin/Constants.java +++ b/java/src/com/android/inputmethod/latin/Constants.java @@ -192,7 +192,6 @@ public final class Constants { public static final int CODE_SPACE = ' '; public static final int CODE_PERIOD = '.'; public static final int CODE_COMMA = ','; - public static final int CODE_ARMENIAN_PERIOD = 0x0589; public static final int CODE_DASH = '-'; public static final int CODE_SINGLE_QUOTE = '\''; public static final int CODE_DOUBLE_QUOTE = '"'; @@ -208,6 +207,8 @@ public final class Constants { public static final int CODE_CLOSING_SQUARE_BRACKET = ']'; public static final int CODE_CLOSING_CURLY_BRACKET = '}'; public static final int CODE_CLOSING_ANGLE_BRACKET = '>'; + public static final int CODE_INVERTED_QUESTION_MARK = 0xBF; // ¿ + public static final int CODE_INVERTED_EXCLAMATION_MARK = 0xA1; // ¡ /** * Special keys code. Must be negative. diff --git a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java index 702688f93..936219332 100644 --- a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java @@ -61,6 +61,22 @@ public final class CapsModeUtils { || WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED == mode; } + /** + * Helper method to find out if a code point is starting punctuation. + * + * This include the Unicode START_PUNCTUATION category, but also some other symbols that are + * starting, like the inverted question mark or the double quote. + * + * @param codePoint the code point + * @return true if it's starting punctuation, false otherwise. + */ + private static boolean isStartPunctuation(final int codePoint) { + return (codePoint == Constants.CODE_DOUBLE_QUOTE || codePoint == Constants.CODE_SINGLE_QUOTE + || codePoint == Constants.CODE_INVERTED_QUESTION_MARK + || codePoint == Constants.CODE_INVERTED_EXCLAMATION_MARK + || Character.getType(codePoint) == Character.START_PUNCTUATION); + } + /** * Determine what caps mode should be in effect at the current offset in * the text. Only the mode bits set in reqModes will be @@ -115,8 +131,7 @@ public final class CapsModeUtils { } else { for (i = cs.length(); i > 0; i--) { final char c = cs.charAt(i - 1); - if (c != Constants.CODE_DOUBLE_QUOTE && c != Constants.CODE_SINGLE_QUOTE - && Character.getType(c) != Character.START_PUNCTUATION) { + if (!isStartPunctuation(c)) { break; } } @@ -210,11 +225,14 @@ public final class CapsModeUtils { // We found out that we have a period. We need to determine if this is a full stop or // otherwise sentence-ending period, or an abbreviation like "e.g.". An abbreviation - // looks like (\w\.){2,} + // looks like (\w\.){2,}. Moreover, in German, you put periods after digits for dates + // and some other things, and in German specifically we need to not go into autocaps after + // a whitespace-digits-period sequence. // To find out, we will have a simple state machine with the following states : - // START, WORD, PERIOD, ABBREVIATION + // START, WORD, PERIOD, ABBREVIATION, NUMBER // On START : (just before the first period) // letter => WORD + // digit => NUMBER if German; end with caps otherwise // whitespace => end with no caps (it was a stand-alone period) // otherwise => end with caps (several periods/symbols in a row) // On WORD : (within the word just before the first period) @@ -228,6 +246,11 @@ public final class CapsModeUtils { // letter => LETTER // period => PERIOD // otherwise => end with no caps (it was an abbreviation) + // On NUMBER : (period immediately preceded by one or more digits) + // digit => NUMBER + // letter => LETTER (promote to word) + // otherwise => end with no caps (it was a whitespace-digits-period sequence, + // or a punctuation-digits-period sequence like "11.11.") // "Not an abbreviation" in the above chart essentially covers cases like "...yes.". This // should capitalize. @@ -235,6 +258,7 @@ public final class CapsModeUtils { final int WORD = 1; final int PERIOD = 2; final int LETTER = 3; + final int NUMBER = 4; final int caps = (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_WORDS | TextUtils.CAP_MODE_SENTENCES) & reqModes; final int noCaps = (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_WORDS) & reqModes; @@ -247,6 +271,8 @@ public final class CapsModeUtils { state = WORD; } else if (Character.isWhitespace(c)) { return noCaps; + } else if (Character.isDigit(c) && spacingAndPunctuations.mUsesGermanRules) { + state = NUMBER; } else { return caps; } @@ -275,6 +301,15 @@ public final class CapsModeUtils { } else { return noCaps; } + break; + case NUMBER: + if (Character.isLetter(c)) { + state = WORD; + } else if (Character.isDigit(c)) { + state = NUMBER; + } else { + return noCaps; + } } } // Here we arrived at the start of the line. This should behave exactly like whitespace. diff --git a/tests/src/com/android/inputmethod/latin/ShiftModeTests.java b/tests/src/com/android/inputmethod/latin/ShiftModeTests.java index 6fc9df793..de5538ed6 100644 --- a/tests/src/com/android/inputmethod/latin/ShiftModeTests.java +++ b/tests/src/com/android/inputmethod/latin/ShiftModeTests.java @@ -78,4 +78,35 @@ public class ShiftModeTests extends InputTestsBase { runMessages(); assertTrue("Caps after a while after repeating Backspace a lot", isCapsModeAutoShifted()); } + + public void testAutoCapsAfterDigitsPeriod() { + changeLanguage("en"); + type("On 22.11."); + assertFalse("(English) Auto caps after digits-period", isCapsModeAutoShifted()); + type(" "); + assertTrue("(English) Auto caps after digits-period-whitespace", isCapsModeAutoShifted()); + mEditText.setText(""); + changeLanguage("fr"); + type("Le 22."); + assertFalse("(French) Auto caps after digits-period", isCapsModeAutoShifted()); + type(" "); + assertTrue("(French) Auto caps after digits-period-whitespace", isCapsModeAutoShifted()); + mEditText.setText(""); + changeLanguage("de"); + type("Am 22."); + assertFalse("(German) Auto caps after digits-period", isCapsModeAutoShifted()); + type(" "); + // For German, no auto-caps in this case + assertFalse("(German) Auto caps after digits-period-whitespace", isCapsModeAutoShifted()); + } + + public void testAutoCapsAfterInvertedMarks() { + changeLanguage("es"); + assertTrue("(Spanish) Auto caps at start", isCapsModeAutoShifted()); + type("Hey. ¿"); + assertTrue("(Spanish) Auto caps after inverted what", isCapsModeAutoShifted()); + mEditText.setText(""); + type("¡"); + assertTrue("(Spanish) Auto caps after inverted bang", isCapsModeAutoShifted()); + } }