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

Commit 1e40af5e authored by Tadashi G. Takaoka's avatar Tadashi G. Takaoka Committed by Android (Google) Code Review
Browse files

Merge "Refactor KeyboardTextsSet class"

parents be0d05c5 0bae2ab4
Loading
Loading
Loading
Loading
+0 −65
Original line number Diff line number Diff line
@@ -48,13 +48,10 @@ import java.util.Arrays;
public final class KeySpecParser {
    private static final boolean DEBUG = LatinImeLogger.sDBG;

    private static final int MAX_STRING_REFERENCE_INDIRECTION = 10;

    // Constants for parsing.
    private static final char COMMA = ',';
    private static final char BACKSLASH = '\\';
    private static final char VERTICAL_BAR = '|';
    private static final String PREFIX_TEXT = "!text/";
    static final String PREFIX_ICON = "!icon/";
    private static final String PREFIX_CODE = "!code/";
    private static final String PREFIX_HEX = "0x";
@@ -361,68 +358,6 @@ public final class KeySpecParser {
        }
    }

    public static String resolveTextReference(final String rawText,
            final KeyboardTextsSet textsSet) {
        if (TextUtils.isEmpty(rawText)) {
            return null;
        }
        int level = 0;
        String text = rawText;
        StringBuilder sb;
        do {
            level++;
            if (level >= MAX_STRING_REFERENCE_INDIRECTION) {
                throw new RuntimeException("too many @string/resource indirection: " + text);
            }

            final int prefixLen = PREFIX_TEXT.length();
            final int size = text.length();
            if (size < prefixLen) {
                return TextUtils.isEmpty(text) ? null : text;
            }

            sb = null;
            for (int pos = 0; pos < size; pos++) {
                final char c = text.charAt(pos);
                if (text.startsWith(PREFIX_TEXT, pos) && textsSet != null) {
                    if (sb == null) {
                        sb = new StringBuilder(text.substring(0, pos));
                    }
                    final int end = searchTextNameEnd(text, pos + prefixLen);
                    final String name = text.substring(pos + prefixLen, end);
                    sb.append(textsSet.getText(name));
                    pos = end - 1;
                } else if (c == BACKSLASH) {
                    if (sb != null) {
                        // Append both escape character and escaped character.
                        sb.append(text.substring(pos, Math.min(pos + 2, size)));
                    }
                    pos++;
                } else if (sb != null) {
                    sb.append(c);
                }
            }

            if (sb != null) {
                text = sb.toString();
            }
        } while (sb != null);
        return TextUtils.isEmpty(text) ? null : text;
    }

    private static int searchTextNameEnd(final String text, final int start) {
        final int size = text.length();
        for (int pos = start; pos < size; pos++) {
            final char c = text.charAt(pos);
            // Label name should be consisted of [a-zA-Z_0-9].
            if ((c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9')) {
                continue;
            }
            return pos;
        }
        return size;
    }

    public static int getIntValue(final String[] moreKeys, final String key,
            final int defaultValue) {
        if (moreKeys == null) {
+2 −2
Original line number Diff line number Diff line
@@ -32,14 +32,14 @@ public abstract class KeyStyle {

    protected String parseString(final TypedArray a, final int index) {
        if (a.hasValue(index)) {
            return KeySpecParser.resolveTextReference(a.getString(index), mTextsSet);
            return mTextsSet.resolveTextReference(a.getString(index));
        }
        return null;
    }

    protected String[] parseStringArray(final TypedArray a, final int index) {
        if (a.hasValue(index)) {
            final String text = KeySpecParser.resolveTextReference(a.getString(index), mTextsSet);
            final String text = mTextsSet.resolveTextReference(a.getString(index));
            return KeySpecParser.splitKeySpecs(text);
        }
        return null;
+66 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.inputmethod.keyboard.internal;

import android.content.Context;
import android.content.res.Resources;
import android.text.TextUtils;

import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.utils.CollectionUtils;
@@ -45,6 +46,10 @@ import java.util.HashMap;
 *   KeyboardTextsSet.java
 */
public final class KeyboardTextsSet {
    private static final String PREFIX_TEXT = "!text/";
    private static final char BACKSLASH = '\\';
    private static final int MAX_STRING_REFERENCE_INDIRECTION = 10;

    // Language to texts map.
    private static final HashMap<String, String[]> sLocaleToTextsMap = CollectionUtils.newHashMap();
    private static final HashMap<String, Integer> sNameToIdsMap = CollectionUtils.newHashMap();
@@ -87,6 +92,67 @@ public final class KeyboardTextsSet {
        return (text == null) ? LANGUAGE_DEFAULT[id] : text;
    }

    private static int searchTextNameEnd(final String text, final int start) {
        final int size = text.length();
        for (int pos = start; pos < size; pos++) {
            final char c = text.charAt(pos);
            // Label name should be consisted of [a-zA-Z_0-9].
            if ((c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9')) {
                continue;
            }
            return pos;
        }
        return size;
    }

    public String resolveTextReference(final String rawText) {
        if (TextUtils.isEmpty(rawText)) {
            return null;
        }
        int level = 0;
        String text = rawText;
        StringBuilder sb;
        do {
            level++;
            if (level >= MAX_STRING_REFERENCE_INDIRECTION) {
                throw new RuntimeException("too many @string/resource indirection: " + text);
            }

            final int prefixLen = PREFIX_TEXT.length();
            final int size = text.length();
            if (size < prefixLen) {
                return TextUtils.isEmpty(text) ? null : text;
            }

            sb = null;
            for (int pos = 0; pos < size; pos++) {
                final char c = text.charAt(pos);
                if (text.startsWith(PREFIX_TEXT, pos)) {
                    if (sb == null) {
                        sb = new StringBuilder(text.substring(0, pos));
                    }
                    final int end = searchTextNameEnd(text, pos + prefixLen);
                    final String name = text.substring(pos + prefixLen, end);
                    sb.append(getText(name));
                    pos = end - 1;
                } else if (c == BACKSLASH) {
                    if (sb != null) {
                        // Append both escape character and escaped character.
                        sb.append(text.substring(pos, Math.min(pos + 2, size)));
                    }
                    pos++;
                } else if (sb != null) {
                    sb.append(c);
                }
            }

            if (sb != null) {
                text = sb.toString();
            }
        } while (sb != null);
        return TextUtils.isEmpty(text) ? null : text;
    }

    // These texts' name should be aligned with the @string/<name> in
    // values*/strings-action-keys.xml.
    private static final String[] RESOURCE_NAMES = {
+3 −5
Original line number Diff line number Diff line
@@ -92,7 +92,7 @@ public class KeySpecParserSplitTests extends InstrumentationTestCase {

    private void assertTextArray(final String message, final String value,
            final String ... expectedArray) {
        final String resolvedActual = KeySpecParser.resolveTextReference(value, mTextsSet);
        final String resolvedActual = mTextsSet.resolveTextReference(value);
        final String[] actual = KeySpecParser.splitKeySpecs(resolvedActual);
        final String[] expected = (expectedArray.length == 0) ? null : expectedArray;
        assertArrayEquals(message, expected, actual);
@@ -117,13 +117,11 @@ public class KeySpecParserSplitTests extends InstrumentationTestCase {
    private static final String SURROGATE2 = PAIR1 + PAIR2 + PAIR3;

    public void testResolveNullText() {
        assertNull("resolve null", KeySpecParser.resolveTextReference(
                null, mTextsSet));
        assertNull("resolve null", mTextsSet.resolveTextReference(null));
    }

    public void testResolveEmptyText() {
        assertNull("resolve empty text", KeySpecParser.resolveTextReference(
                "!text/empty_string", mTextsSet));
        assertNull("resolve empty text", mTextsSet.resolveTextReference("!text/empty_string"));
    }

    public void testSplitZero() {
+1 −1
Original line number Diff line number Diff line
@@ -73,7 +73,7 @@ public class KeySpecParserTests extends AndroidTestCase {

    private void assertParser(String message, String moreKeySpec, String expectedLabel,
            String expectedOutputText, int expectedIcon, int expectedCode) {
        final String labelResolved = KeySpecParser.resolveTextReference(moreKeySpec, mTextsSet);
        final String labelResolved = mTextsSet.resolveTextReference(moreKeySpec);
        final MoreKeySpec spec = new MoreKeySpec(labelResolved, false /* needsToUpperCase */,
                Locale.US, mCodesSet);
        assertEquals(message + " [label]", expectedLabel, spec.mLabel);
Loading