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

Commit 0bae2ab4 authored by Tadashi G. Takaoka's avatar Tadashi G. Takaoka
Browse files

Refactor KeyboardTextsSet class

Change-Id: I0b48c85aa2c291e1e7ee25d61c558700fc677e29
parent d245f6c9
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