diff options
Diffstat (limited to 'java/src')
4 files changed, 207 insertions, 40 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 0b3737e48..23f037fbd 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -51,6 +51,11 @@ public class Keyboard { /** Total width of the keyboard, including the padding and keys */ public final int mOccupiedWidth; + /** Base height of the keyboard, used to calculate rows' height */ + public final int mBaseHeight; + /** Base width of the keyboard, used to calculate keys' width */ + public final int mBaseWidth; + /** The padding above the keyboard */ public final int mTopPadding; /** Default gap between rows */ @@ -84,6 +89,8 @@ public class Keyboard { mThemeId = params.mThemeId; mOccupiedHeight = params.mOccupiedHeight; mOccupiedWidth = params.mOccupiedWidth; + mBaseHeight = params.mBaseHeight; + mBaseWidth = params.mBaseWidth; mMostCommonKeyHeight = params.mMostCommonKeyHeight; mMostCommonKeyWidth = params.mMostCommonKeyWidth; mMoreKeysTemplate = params.mMoreKeysTemplate; @@ -109,6 +116,8 @@ public class Keyboard { mThemeId = keyboard.mThemeId; mOccupiedHeight = keyboard.mOccupiedHeight; mOccupiedWidth = keyboard.mOccupiedWidth; + mBaseHeight = keyboard.mBaseHeight; + mBaseWidth = keyboard.mBaseWidth; mMostCommonKeyHeight = keyboard.mMostCommonKeyHeight; mMostCommonKeyWidth = keyboard.mMostCommonKeyWidth; mMoreKeysTemplate = keyboard.mMoreKeysTemplate; diff --git a/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java b/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java new file mode 100644 index 000000000..c10fdbace --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.keyboard.internal; + +import com.android.inputmethod.latin.Constants; + +/** + * The string parser of codesArray specification for <GridRows />. The attribute codesArray is an + * array of string. + * Each element of the array defines a key label by specifying a code point as a hexadecimal string. + * A key label may consist of multiple code points separated by comma. + * Each element of the array optionally can have an output text definition after vertical bar + * marker. An output text may consist of multiple code points separated by comma. + * The format of the codesArray element should be: + * <pre> + * codePointInHex[,codePoint2InHex]*(|outputTextCodePointInHex[,outputTextCodePoint2InHex]*)? + * </pre> + */ +// TODO: Write unit tests for this class. +public final class CodesArrayParser { + // Constants for parsing. + private static final char COMMA = ','; + private static final char VERTICAL_BAR = '|'; + private static final String COMMA_STRING = ","; + private static final int BASE_HEX = 16; + + private CodesArrayParser() { + // This utility class is not publicly instantiable. + } + + private static String getLabelSpec(final String codesArraySpec) { + final int pos = codesArraySpec.indexOf(VERTICAL_BAR); + return (pos < 0) ? codesArraySpec : codesArraySpec.substring(0, pos); + } + + public static String parseLabel(final String codesArraySpec) { + final String labelSpec = getLabelSpec(codesArraySpec); + final StringBuilder sb = new StringBuilder(); + for (final String codeInHex : labelSpec.split(COMMA_STRING)) { + final int codePoint = Integer.parseInt(codeInHex, BASE_HEX); + sb.appendCodePoint(codePoint); + } + return sb.toString(); + } + + private static String getCodeSpec(final String codesArraySpec) { + final int pos = codesArraySpec.indexOf(VERTICAL_BAR); + return (pos < 0) ? codesArraySpec : codesArraySpec.substring(pos + 1); + } + + public static int parseCode(final String codesArraySpec) { + final String codeSpec = getCodeSpec(codesArraySpec); + if (codeSpec.indexOf(COMMA) < 0) { + return Integer.parseInt(codeSpec, BASE_HEX); + } + return Constants.CODE_OUTPUT_TEXT; + } + + public static String parseOutputText(final String codesArraySpec) { + final String codeSpec = getCodeSpec(codesArraySpec); + if (codeSpec.indexOf(COMMA) < 0) { + return null; + } + final StringBuilder sb = new StringBuilder(); + for (final String codeInHex : codeSpec.split(COMMA_STRING)) { + final int codePoint = Integer.parseInt(codeInHex, BASE_HEX); + sb.appendCodePoint(codePoint); + } + return sb.toString(); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java index 3f0773e15..8c70389ba 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java @@ -29,6 +29,7 @@ import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.ResourceUtils; import com.android.inputmethod.latin.utils.RunInLocale; @@ -113,6 +114,7 @@ import java.util.Locale; * </pre> */ +// TODO: Write unit tests for this class. public class KeyboardBuilder<KP extends KeyboardParams> { private static final String BUILDER_TAG = "Keyboard.Builder"; private static final boolean DEBUG = false; @@ -120,6 +122,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> { // Keyboard XML Tags private static final String TAG_KEYBOARD = "Keyboard"; private static final String TAG_ROW = "Row"; + private static final String TAG_GRID_ROWS = "GridRows"; private static final String TAG_KEY = "Key"; private static final String TAG_SPACER = "Spacer"; private static final String TAG_INCLUDE = "include"; @@ -312,6 +315,9 @@ public class KeyboardBuilder<KP extends KeyboardParams> { startRow(row); } parseRowContent(parser, row, skip); + } else if (TAG_GRID_ROWS.equals(tag)) { + if (DEBUG) startTag("<%s>%s", TAG_GRID_ROWS, skip ? " skipped" : ""); + parseGridRows(parser, skip); } else if (TAG_INCLUDE.equals(tag)) { parseIncludeKeyboardContent(parser, skip); } else if (TAG_SWITCH.equals(tag)) { @@ -389,6 +395,73 @@ public class KeyboardBuilder<KP extends KeyboardParams> { } } + private void parseGridRows(final XmlPullParser parser, final boolean skip) + throws XmlPullParserException, IOException { + if (skip) { + XmlParseUtils.checkEndTag(TAG_GRID_ROWS, parser); + if (DEBUG) { + startEndTag("<%s /> skipped", TAG_GRID_ROWS); + } + return; + } + final KeyboardRow gridRows = new KeyboardRow(mResources, mParams, parser, mCurrentY); + final TypedArray gridRowAttr = mResources.obtainAttributes( + Xml.asAttributeSet(parser), R.styleable.Keyboard_GridRows); + final int codesArrayId = gridRowAttr.getResourceId( + R.styleable.Keyboard_GridRows_codesArray, 0); + final int textsArrayId = gridRowAttr.getResourceId( + R.styleable.Keyboard_GridRows_textsArray, 0); + gridRowAttr.recycle(); + if (codesArrayId == 0 && textsArrayId == 0) { + throw new XmlParseUtils.ParseException( + "Missing codesArray or textsArray attributes", parser); + } + if (codesArrayId != 0 && textsArrayId != 0) { + throw new XmlParseUtils.ParseException( + "Both codesArray and textsArray attributes specifed", parser); + } + final String[] array = mResources.getStringArray( + codesArrayId != 0 ? codesArrayId : textsArrayId); + final int counts = array.length; + final float keyWidth = gridRows.getKeyWidth(null, 0.0f); + final int numColumns = (int)(mParams.mOccupiedWidth / keyWidth); + for (int index = 0; index < counts; index += numColumns) { + final KeyboardRow row = new KeyboardRow(mResources, mParams, parser, mCurrentY); + startRow(row); + for (int c = 0; c < numColumns; c++) { + final int i = index + c; + if (i >= counts) { + break; + } + final String label; + final int code; + final String outputText; + if (codesArrayId != 0) { + final String codeArraySpec = array[i]; + label = CodesArrayParser.parseLabel(codeArraySpec); + code = CodesArrayParser.parseCode(codeArraySpec); + outputText = CodesArrayParser.parseOutputText(codeArraySpec); + } else { + final String textArraySpec = array[i]; + // TODO: Utilize KeySpecParser or write more generic TextsArrayParser. + label = textArraySpec; + code = Constants.CODE_OUTPUT_TEXT; + outputText = textArraySpec + (char)Constants.CODE_SPACE; + } + final int x = (int)row.getKeyX(null); + final int y = row.getKeyY(); + final Key key = new Key(mParams, label, null /* hintLabel */, 0 /* iconId */, + code, outputText, x, y, (int)keyWidth, (int)row.getRowHeight(), + row.getDefaultKeyLabelFlags(), row.getDefaultBackgroundType()); + endKey(key); + row.advanceXPos(keyWidth); + } + endRow(row); + } + + XmlParseUtils.checkEndTag(TAG_GRID_ROWS, parser); + } + private void parseKey(final XmlPullParser parser, final KeyboardRow row, final boolean skip) throws XmlPullParserException, IOException { if (skip) { @@ -744,7 +817,10 @@ public class KeyboardBuilder<KP extends KeyboardParams> { } private void endKeyboard() { - // nothing to do here. + // {@link #parseGridRows(XmlPullParser,boolean)} may populate keyboard rows higher than + // previously expected. + final int actualHeight = mCurrentY - mParams.mVerticalGap + mParams.mBottomPadding; + mParams.mOccupiedHeight = Math.max(mParams.mOccupiedHeight, actualHeight); } private void addEdgeSpace(final float width, final KeyboardRow row) { diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java index 507080db4..c6d652c0e 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java @@ -231,25 +231,24 @@ public final class KeyboardTextsSet { /* 126 */ "label_to_phone_symbols_key", /* 127 */ "label_time_am", /* 128 */ "label_time_pm", - /* 129 */ "label_to_symbol_key_pcqwerty", - /* 130 */ "keylabel_for_popular_domain", - /* 131 */ "more_keys_for_popular_domain", - /* 132 */ "more_keys_for_smiley", - /* 133 */ "single_laqm_raqm", - /* 134 */ "single_laqm_raqm_rtl", - /* 135 */ "single_raqm_laqm", - /* 136 */ "double_laqm_raqm", - /* 137 */ "double_laqm_raqm_rtl", - /* 138 */ "double_raqm_laqm", - /* 139 */ "single_lqm_rqm", - /* 140 */ "single_9qm_lqm", - /* 141 */ "single_9qm_rqm", - /* 142 */ "double_lqm_rqm", - /* 143 */ "double_9qm_lqm", - /* 144 */ "double_9qm_rqm", - /* 145 */ "more_keys_for_single_quote", - /* 146 */ "more_keys_for_double_quote", - /* 147 */ "more_keys_for_tablet_double_quote", + /* 129 */ "keylabel_for_popular_domain", + /* 130 */ "more_keys_for_popular_domain", + /* 131 */ "more_keys_for_smiley", + /* 132 */ "single_laqm_raqm", + /* 133 */ "single_laqm_raqm_rtl", + /* 134 */ "single_raqm_laqm", + /* 135 */ "double_laqm_raqm", + /* 136 */ "double_laqm_raqm_rtl", + /* 137 */ "double_raqm_laqm", + /* 138 */ "single_lqm_rqm", + /* 139 */ "single_9qm_lqm", + /* 140 */ "single_9qm_rqm", + /* 141 */ "double_lqm_rqm", + /* 142 */ "double_9qm_lqm", + /* 143 */ "double_9qm_rqm", + /* 144 */ "more_keys_for_single_quote", + /* 145 */ "more_keys_for_double_quote", + /* 146 */ "more_keys_for_tablet_double_quote", }; private static final String EMPTY = ""; @@ -389,12 +388,10 @@ public final class KeyboardTextsSet { /* 127 */ "AM", // Key label for "post meridiem" /* 128 */ "PM", - // Label for "switch to symbols" key on PC QWERTY layout - /* 129 */ "Sym", - /* 130 */ ".com", + /* 129 */ ".com", // popular web domains for the locale - most popular, displayed on the keyboard - /* 131 */ "!hasLabels!,.net,.org,.gov,.edu", - /* 132 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ", + /* 130 */ "!hasLabels!,.net,.org,.gov,.edu", + /* 131 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ", // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK @@ -416,24 +413,24 @@ public final class KeyboardTextsSet { // The following each quotation mark pair consist of // <opening quotation mark>, <closing quotation mark> // and is named after (single|double)_<opening quotation mark>_<closing quotation mark>. - /* 133 */ "\u2039,\u203A", - /* 134 */ "\u2039|\u203A,\u203A|\u2039", - /* 135 */ "\u203A,\u2039", - /* 136 */ "\u00AB,\u00BB", - /* 137 */ "\u00AB|\u00BB,\u00BB|\u00AB", - /* 138 */ "\u00BB,\u00AB", + /* 132 */ "\u2039,\u203A", + /* 133 */ "\u2039|\u203A,\u203A|\u2039", + /* 134 */ "\u203A,\u2039", + /* 135 */ "\u00AB,\u00BB", + /* 136 */ "\u00AB|\u00BB,\u00BB|\u00AB", + /* 137 */ "\u00BB,\u00AB", // The following each quotation mark triplet consists of // <another quotation mark>, <opening quotation mark>, <closing quotation mark> // and is named after (single|double)_<opening quotation mark>_<closing quotation mark>. - /* 139 */ "\u201A,\u2018,\u2019", - /* 140 */ "\u2019,\u201A,\u2018", - /* 141 */ "\u2018,\u201A,\u2019", - /* 142 */ "\u201E,\u201C,\u201D", - /* 143 */ "\u201D,\u201E,\u201C", - /* 144 */ "\u201C,\u201E,\u201D", - /* 145 */ "!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes", - /* 146 */ "!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes", - /* 147 */ "!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes", + /* 138 */ "\u201A,\u2018,\u2019", + /* 139 */ "\u2019,\u201A,\u2018", + /* 140 */ "\u2018,\u201A,\u2019", + /* 141 */ "\u201E,\u201C,\u201D", + /* 142 */ "\u201D,\u201E,\u201C", + /* 143 */ "\u201C,\u201E,\u201D", + /* 144 */ "!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes", + /* 145 */ "!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes", + /* 146 */ "!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes", }; /* Language af: Afrikaans */ |