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

Commit 23bacdb6 authored by Tadashi G. Takaoka's avatar Tadashi G. Takaoka
Browse files

Fix MoreKeySpecParser to be able to handle outputText correctly

The issue was introduced by Id2320f4d.

Bug: 5887936
Change-Id: Ifec3aefb5b168f790de696ece104b84cdab46539
parent 7dde8057
Loading
Loading
Loading
Loading
+29 −18
Original line number Diff line number Diff line
@@ -53,8 +53,9 @@ public class MoreKeySpecParser {
    private static boolean hasIcon(String moreKeySpec) {
        if (moreKeySpec.startsWith(PREFIX_ICON)) {
            final int end = indexOfLabelEnd(moreKeySpec, 0);
            if (end > 0)
            if (end > 0) {
                return true;
            }
            throw new MoreKeySpecParserError("outputText or code not specified: " + moreKeySpec);
        }
        return false;
@@ -70,8 +71,9 @@ public class MoreKeySpecParser {
    }

    private static String parseEscape(String text) {
        if (text.indexOf(ESCAPE) < 0)
        if (text.indexOf(ESCAPE) < 0) {
            return text;
        }
        final int length = text.length();
        final StringBuilder sb = new StringBuilder();
        for (int pos = 0; pos < length; pos++) {
@@ -88,8 +90,9 @@ public class MoreKeySpecParser {
    private static int indexOfLabelEnd(String moreKeySpec, int start) {
        if (moreKeySpec.indexOf(ESCAPE, start) < 0) {
            final int end = moreKeySpec.indexOf(LABEL_END, start);
            if (end == 0)
            if (end == 0) {
                throw new MoreKeySpecParserError(LABEL_END + " at " + start + ": " + moreKeySpec);
            }
            return end;
        }
        final int length = moreKeySpec.length();
@@ -105,55 +108,62 @@ public class MoreKeySpecParser {
    }

    public static String getLabel(String moreKeySpec) {
        if (hasIcon(moreKeySpec))
        if (hasIcon(moreKeySpec)) {
            return null;
        }
        final int end = indexOfLabelEnd(moreKeySpec, 0);
        final String label = (end > 0) ? parseEscape(moreKeySpec.substring(0, end))
                : parseEscape(moreKeySpec);
        if (TextUtils.isEmpty(label))
        if (TextUtils.isEmpty(label)) {
            throw new MoreKeySpecParserError("Empty label: " + moreKeySpec);
        }
        return label;
    }

    public static String getOutputText(String moreKeySpec) {
        if (hasCode(moreKeySpec))
        if (hasCode(moreKeySpec)) {
            return null;
        }
        final int end = indexOfLabelEnd(moreKeySpec, 0);
        if (end > 0) {
            if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0)
            if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) {
                    throw new MoreKeySpecParserError("Multiple " + LABEL_END + ": "
                            + moreKeySpec);
            }
            final String outputText = parseEscape(moreKeySpec.substring(end + LABEL_END.length()));
            if (!TextUtils.isEmpty(outputText))
            if (!TextUtils.isEmpty(outputText)) {
                return outputText;
            }
            throw new MoreKeySpecParserError("Empty outputText: " + moreKeySpec);
        }
        final String label = getLabel(moreKeySpec);
        if (label == null)
        if (label == null) {
            throw new MoreKeySpecParserError("Empty label: " + moreKeySpec);
        }
        // Code is automatically generated for one letter label. See {@link getCode()}.
        if (label.length() == 1)
            return null;
        return label;
        return (label.length() == 1) ? null : label;
    }

    public static int getCode(Resources res, String moreKeySpec) {
        if (hasCode(moreKeySpec)) {
            final int end = indexOfLabelEnd(moreKeySpec, 0);
            if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0)
            if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) {
                throw new MoreKeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec);
            }
            final int resId = getResourceId(res,
                    moreKeySpec.substring(end + LABEL_END.length() + PREFIX_AT.length()));
            final int code = res.getInteger(resId);
            return code;
        }
        if (indexOfLabelEnd(moreKeySpec, 0) > 0)
            return Keyboard.CODE_UNSPECIFIED;
        if (indexOfLabelEnd(moreKeySpec, 0) > 0) {
            return Keyboard.CODE_OUTPUT_TEXT;
        }
        final String label = getLabel(moreKeySpec);
        // Code is automatically generated for one letter label.
        if (label != null && label.length() == 1)
        if (label != null && label.length() == 1) {
            return label.charAt(0);
        return Keyboard.CODE_UNSPECIFIED;
        }
        return Keyboard.CODE_OUTPUT_TEXT;
    }

    public static int getIconId(String moreKeySpec) {
@@ -173,8 +183,9 @@ public class MoreKeySpecParser {
    private static int getResourceId(Resources res, String name) {
        String packageName = res.getResourcePackageName(R.string.english_ime_name);
        int resId = res.getIdentifier(name, null, packageName);
        if (resId == 0)
        if (resId == 0) {
            throw new MoreKeySpecParserError("Unknown resource: " + name);
        }
        return resId;
    }

+39 −39
Original line number Diff line number Diff line
@@ -89,78 +89,78 @@ public class MoreKeySpecParserTests extends AndroidTestCase {
        assertParser("Single escaped at", "\\@",
                "@", null, ICON_UNDEFINED, '@');
        assertParser("Single letter with outputText", "a|abc",
                "a", "abc", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a", "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Single letter with escaped outputText", "a|a\\|c",
                "a", "a|c", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a", "a|c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Single letter with comma outputText", "a|a,b",
                "a", "a,b", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Single letter with escaped comma outputText", "a|a\\,b",
                "a", "a,b", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Single letter with outputText starts with at", "a|@bc",
                "a", "@bc", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Single letter with outputText contains at", "a|a@c",
                "a", "a@c", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a", "a@c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Single letter with escaped at outputText", "a|\\@bc",
                "a", "@bc", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Single escaped escape with outputText", "\\\\|\\\\",
                "\\", "\\", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "\\", "\\", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Single escaped bar with outputText", "\\||\\|",
                "|", "|", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "|", "|", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Single letter with code", "a|" + CODE_SETTINGS,
                "a", null, ICON_UNDEFINED, mCodeSettings);
    }

    public void testLabel() {
        assertParser("Simple label", "abc",
                "abc", "abc", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "abc", "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with escaped bar", "a\\|c",
                "a|c", "a|c", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a|c", "a|c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with escaped escape", "a\\\\c",
                "a\\c", "a\\c", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a\\c", "a\\c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with comma", "a,c",
                "a,c", "a,c", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a,c", "a,c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with escaped comma", "a\\,c",
                "a,c", "a,c", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a,c", "a,c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label starts with at", "@bc",
                "@bc", "@bc", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "@bc", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label contains at", "a@c",
                "a@c", "a@c", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a@c", "a@c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with escaped at", "\\@bc",
                "@bc", "@bc", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "@bc", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with escaped letter", "\\abc",
                "abc", "abc", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "abc", "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with outputText", "abc|def",
                "abc", "def", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "abc", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with comma and outputText", "a,c|def",
                "a,c", "def", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a,c", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Escaped comma label with outputText", "a\\,c|def",
                "a,c", "def", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a,c", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Escaped label with outputText", "a\\|c|def",
                "a|c", "def", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a|c", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with escaped bar outputText", "abc|d\\|f",
                "abc", "d|f", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "abc", "d|f", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Escaped escape label with outputText", "a\\\\|def",
                "a\\", "def", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a\\", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label starts with at and outputText", "@bc|def",
                "@bc", "def", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "@bc", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label contains at label and outputText", "a@c|def",
                "a@c", "def", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a@c", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Escaped at label with outputText", "\\@bc|def",
                "@bc", "def", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "@bc", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with comma outputText", "abc|a,b",
                "abc", "a,b", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "abc", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with escaped comma outputText", "abc|a\\,b",
                "abc", "a,b", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "abc", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with outputText starts with at", "abc|@bc",
                "abc", "@bc", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "abc", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with outputText contains at", "abc|a@c",
                "abc", "a@c", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "abc", "a@c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with escaped at outputText", "abc|\\@bc",
                "abc", "@bc", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "abc", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with escaped bar outputText", "abc|d\\|f",
                "abc", "d|f", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "abc", "d|f", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Escaped bar label with escaped bar outputText", "a\\|c|d\\|f",
                "a|c", "d|f", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                "a|c", "d|f", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label with code", "abc|" + CODE_SETTINGS,
                "abc", null, ICON_UNDEFINED, mCodeSettings);
        assertParser("Escaped label with code", "a\\|c|" + CODE_SETTINGS,
@@ -169,13 +169,13 @@ public class MoreKeySpecParserTests extends AndroidTestCase {

    public void testIconAndCode() {
        assertParser("Icon with outputText", ICON_SETTINGS + "|abc",
                null, "abc", ICON_SETTINGS_KEY, Keyboard.CODE_UNSPECIFIED);
                null, "abc", ICON_SETTINGS_KEY, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Icon with outputText starts with at", ICON_SETTINGS + "|@bc",
                null, "@bc", ICON_SETTINGS_KEY, Keyboard.CODE_UNSPECIFIED);
                null, "@bc", ICON_SETTINGS_KEY, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Icon with outputText contains at", ICON_SETTINGS + "|a@c",
                null, "a@c", ICON_SETTINGS_KEY, Keyboard.CODE_UNSPECIFIED);
                null, "a@c", ICON_SETTINGS_KEY, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Icon with escaped at outputText", ICON_SETTINGS + "|\\@bc",
                null, "@bc", ICON_SETTINGS_KEY, Keyboard.CODE_UNSPECIFIED);
                null, "@bc", ICON_SETTINGS_KEY, Keyboard.CODE_OUTPUT_TEXT);
        assertParser("Label starts with at and code", "@bc|" + CODE_SETTINGS,
                "@bc", null, ICON_UNDEFINED, mCodeSettings);
        assertParser("Label contains at and code", "a@c|" + CODE_SETTINGS,
@@ -202,7 +202,7 @@ public class MoreKeySpecParserTests extends AndroidTestCase {
        assertParserError("Icon without code", ICON_SETTINGS,
                null, null, ICON_SETTINGS_KEY, Keyboard.CODE_UNSPECIFIED);
        assertParser("Non existing icon", ICON_NON_EXISTING + "|abc",
                null, "abc", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
                null, "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
        assertParserError("Non existing code", "abc|" + CODE_NON_EXISTING,
                "abc", null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED);
        assertParserError("Third bar at end", "a|b|",