Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 252da38f authored by Jean Chalard's avatar Jean Chalard
Browse files

Take locale into account for caps (A10)

Bug: 4967874
Change-Id: Ic7ce7b2de088308fa00865c81246c84c605db1e5
parent da8aca60
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1118,7 +1118,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
        // Note: getCursorCapsMode() returns the current capitalization mode that is any
        // combination of CAP_MODE_CHARACTERS, CAP_MODE_WORDS, and CAP_MODE_SENTENCES. 0 means none
        // of them.
        return mConnection.getCursorCapsMode(inputType);
        return mConnection.getCursorCapsMode(inputType, mSubtypeSwitcher.getCurrentSubtypeLocale());
    }

    // Factor in auto-caps and manual caps and compute the current caps mode.
+3 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.research.ResearchLogger;

import java.util.Locale;
import java.util.regex.Pattern;

/**
@@ -189,7 +190,7 @@ public class RichInputConnection {
        }
    }

    public int getCursorCapsMode(final int inputType) {
    public int getCursorCapsMode(final int inputType, final Locale locale) {
        mIC = mParent.getCurrentInputConnection();
        if (null == mIC) return Constants.TextUtils.CAP_MODE_OFF;
        if (!TextUtils.isEmpty(mComposingText)) return Constants.TextUtils.CAP_MODE_OFF;
@@ -204,7 +205,7 @@ public class RichInputConnection {
        }
        // This never calls InputConnection#getCapsMode - in fact, it's a static method that
        // never blocks or initiates IPC.
        return StringUtils.getCapsMode(mCommittedTextBeforeComposingText, inputType);
        return StringUtils.getCapsMode(mCommittedTextBeforeComposingText, inputType, locale);
    }

    public CharSequence getTextBeforeCursor(final int i, final int j) {
+20 −14
Original line number Diff line number Diff line
@@ -196,13 +196,14 @@ public final class StringUtils {
     * @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
     *
     * @return Returns the actual capitalization modes that can be in effect
     * at the current position, which is any combination of
     * {@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) {
    public static int getCapsMode(final CharSequence cs, final int reqModes, final Locale locale) {
        // 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.
@@ -270,21 +271,26 @@ public final class StringUtils {
        // we know that MODE_SENTENCES is being requested.

        // Step 4 : Search for MODE_SENTENCES.
        // English is a special case in that "American typography" rules, which are the most common
        // in English, state that a sentence terminator immediately following a quotation mark
        // should be swapped with it and de-duplicated (included in the quotation mark),
        // e.g. <<Did he say, "let's go home?">>
        // No other language has such a rule as far as I know, instead putting inside the quotation
        // 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())) {
            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 other closing
            // punctuation signs.
            // TODO: this is wrong for almost everything except American typography rules for
            // English. It's wrong for British typography rules for English, it's wrong for French,
            // it's wrong for German, it's wrong for Spanish, and possibly everything else.
            // (note that American rules and British rules have nothing to do with en_US and en_GB,
            // as both rules are used in both countries - it's merely a name for the set of rules)
                // 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
                // other closing punctuation signs. This is generally not true in other languages.
                final char c = cs.charAt(j - 1);
                if (c != Keyboard.CODE_DOUBLE_QUOTE && c != Keyboard.CODE_SINGLE_QUOTE
                        && Character.getType(c) != Character.END_PUNCTUATION) {
                    break;
                }
            }
        }

        if (j <= 0) return TextUtils.CAP_MODE_CHARACTERS & reqModes;
        char c = cs.charAt(--j);
+35 −26
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.inputmethod.latin;
import android.test.AndroidTestCase;
import android.text.TextUtils;

import java.util.Locale;

public class StringUtilsTests extends AndroidTestCase {
    public void testContainsInArray() {
        assertFalse("empty array", StringUtils.containsInArray("key", new String[0]));
@@ -90,43 +92,50 @@ public class StringUtilsTests extends AndroidTestCase {
                StringUtils.removeFromCsvIfExists("key", "key1,key,key3,key,key5"));
    }

    private void onePathForCaps(final CharSequence cs, final int expectedResult, final int mask) {
    private void onePathForCaps(final CharSequence cs, final int expectedResult, final int mask,
            final Locale l) {
        int oneTimeResult = expectedResult & mask;
        assertEquals("After >" + cs + "<", oneTimeResult, StringUtils.getCapsMode(cs, mask));
        assertEquals("After >" + cs + "<", oneTimeResult, StringUtils.getCapsMode(cs, mask, l));
    }

    private void allPathsForCaps(final CharSequence cs, final int expectedResult) {
    private void allPathsForCaps(final CharSequence cs, final int expectedResult, final Locale l) {
        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);
        onePathForCaps(cs, expectedResult, w | s);
        onePathForCaps(cs, expectedResult, c | s);
        onePathForCaps(cs, expectedResult, c | w);
        onePathForCaps(cs, expectedResult, c);
        onePathForCaps(cs, expectedResult, w);
        onePathForCaps(cs, expectedResult, s);
        onePathForCaps(cs, expectedResult, c | w | s, l);
        onePathForCaps(cs, expectedResult, w | s, l);
        onePathForCaps(cs, expectedResult, c | s, l);
        onePathForCaps(cs, expectedResult, c | w, l);
        onePathForCaps(cs, expectedResult, c, l);
        onePathForCaps(cs, expectedResult, w, l);
        onePathForCaps(cs, expectedResult, s, l);
    }

    public void testGetCapsMode() {
        final int c = TextUtils.CAP_MODE_CHARACTERS;
        final int w = TextUtils.CAP_MODE_WORDS;
        final int s = TextUtils.CAP_MODE_SENTENCES;
        allPathsForCaps("", c | w | s);
        allPathsForCaps("Word", c);
        allPathsForCaps("Word.", c);
        allPathsForCaps("Word ", c | w);
        allPathsForCaps("Word. ", c | w | s);
        allPathsForCaps("Word..", c);
        allPathsForCaps("Word.. ", c | w | s);
        allPathsForCaps("Word... ", c | w | s);
        allPathsForCaps("Word ... ", c | w | s);
        allPathsForCaps("Word . ", c | w);
        allPathsForCaps("In the U.S ", c | w);
        allPathsForCaps("In the U.S. ", c | w);
        allPathsForCaps("Some stuff (e.g. ", c | w);
        allPathsForCaps("In the U.S.. ", c | w | s);
        allPathsForCaps("\"Word.\" ", c | w | s);
        allPathsForCaps("\"Word\" ", c | w);
        Locale l = Locale.ENGLISH;
        allPathsForCaps("", c | w | s, l);
        allPathsForCaps("Word", c, l);
        allPathsForCaps("Word.", c, l);
        allPathsForCaps("Word ", c | w, l);
        allPathsForCaps("Word. ", c | w | s, l);
        allPathsForCaps("Word..", c, l);
        allPathsForCaps("Word.. ", c | w | s, l);
        allPathsForCaps("Word... ", c | w | s, l);
        allPathsForCaps("Word ... ", c | w | s, l);
        allPathsForCaps("Word . ", c | w, l);
        allPathsForCaps("In the U.S ", c | w, l);
        allPathsForCaps("In the U.S. ", c | w, l);
        allPathsForCaps("Some stuff (e.g. ", c | w, l);
        allPathsForCaps("In the U.S.. ", c | w | s, l);
        allPathsForCaps("\"Word.\" ", c | w | s, l);
        allPathsForCaps("\"Word\". ", c | w | s, l);
        allPathsForCaps("\"Word\" ", c | w, l);
        l = Locale.FRENCH;
        allPathsForCaps("\"Word.\" ", c | w, l);
        allPathsForCaps("\"Word\". ", c | w | s, l);
        allPathsForCaps("\"Word\" ", c | w, l);
    }
}