diff options
author | 2010-11-19 14:57:24 -0800 | |
---|---|---|
committer | 2010-11-22 18:33:47 -0800 | |
commit | 0b60f831922b9341a7ef5d2eba87aa91580d371f (patch) | |
tree | 45c842b5b73be735a2e5ea8499c81bfcddf2c630 /java/src | |
parent | 409220583333bdf06290dd9fd42f91b5c0d1b11a (diff) | |
download | latinime-0b60f831922b9341a7ef5d2eba87aa91580d371f.tar.gz latinime-0b60f831922b9341a7ef5d2eba87aa91580d371f.tar.xz latinime-0b60f831922b9341a7ef5d2eba87aa91580d371f.zip |
Support <key-style/> and keyStyle attribute for Keyboard XML
Change-Id: Ie052e989d0180eecfc8c244ba6c60594a46103d1
Diffstat (limited to 'java/src')
4 files changed, 322 insertions, 72 deletions
diff --git a/java/src/com/android/inputmethod/latin/BaseKeyboard.java b/java/src/com/android/inputmethod/latin/BaseKeyboard.java index cb0ac216c..485cc3153 100644 --- a/java/src/com/android/inputmethod/latin/BaseKeyboard.java +++ b/java/src/com/android/inputmethod/latin/BaseKeyboard.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin; +import com.android.inputmethod.latin.BaseKeyboardParser.ParseException; +import com.android.inputmethod.latin.KeyStyles.KeyStyle; import com.android.inputmethod.latin.KeyboardSwitcher.KeyboardId; import org.xmlpull.v1.XmlPullParserException; @@ -26,14 +28,11 @@ import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; import android.text.TextUtils; -import android.util.Log; -import android.util.TypedValue; import android.util.Xml; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.StringTokenizer; /** * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard @@ -284,7 +283,8 @@ public class BaseKeyboard { * @param y the y coordinate of the top-left * @param parser the XML parser containing the attributes for this key */ - public Key(Resources res, Row parent, int x, int y, XmlResourceParser parser) { + public Key(Resources res, Row parent, int x, int y, XmlResourceParser parser, + KeyStyles keyStyles) { this(parent); TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), @@ -299,44 +299,47 @@ public class BaseKeyboard { R.styleable.BaseKeyboard_keyWidth, keyboard.mDisplayWidth, parent.defaultWidth) - gap; a.recycle(); + a = res.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.BaseKeyboard_Key); + final KeyStyle style; + if (a.hasValue(R.styleable.BaseKeyboard_Key_keyStyle)) { + String styleName = a.getString(R.styleable.BaseKeyboard_Key_keyStyle); + style = keyStyles.getKeyStyle(styleName); + if (style == null) + throw new ParseException("Unknown key style: " + styleName, parser); + } else { + style = keyStyles.getEmptyKeyStyle(); + } + // Horizontal gap is divided equally to both sides of the key. this.x = x + gap / 2; this.y = y; - TypedValue codesValue = new TypedValue(); - a.getValue(R.styleable.BaseKeyboard_Key_codes, codesValue); - if (codesValue.type == TypedValue.TYPE_INT_DEC - || codesValue.type == TypedValue.TYPE_INT_HEX) { - codes = new int[] { codesValue.data }; - } else if (codesValue.type == TypedValue.TYPE_STRING) { - codes = parseCSV(codesValue.string.toString()); - } - - iconPreview = a.getDrawable(R.styleable.BaseKeyboard_Key_iconPreview); + codes = style.getIntArray(a, R.styleable.BaseKeyboard_Key_codes); + iconPreview = style.getDrawable(a, R.styleable.BaseKeyboard_Key_iconPreview); setDefaultBounds(iconPreview); - popupCharacters = a.getText(R.styleable.BaseKeyboard_Key_popupCharacters); - popupResId = a.getResourceId(R.styleable.BaseKeyboard_Key_popupKeyboard, 0); - repeatable = a.getBoolean(R.styleable.BaseKeyboard_Key_isRepeatable, false); - modifier = a.getBoolean(R.styleable.BaseKeyboard_Key_isModifier, false); - sticky = a.getBoolean(R.styleable.BaseKeyboard_Key_isSticky, false); - edgeFlags = a.getInt(R.styleable.BaseKeyboard_Key_keyEdgeFlags, 0); + popupCharacters = style.getText(a, R.styleable.BaseKeyboard_Key_popupCharacters); + popupResId = style.getResourceId(a, R.styleable.BaseKeyboard_Key_popupKeyboard, 0); + repeatable = style.getBoolean(a, R.styleable.BaseKeyboard_Key_isRepeatable, false); + modifier = style.getBoolean(a, R.styleable.BaseKeyboard_Key_isModifier, false); + sticky = style.getBoolean(a, R.styleable.BaseKeyboard_Key_isSticky, false); + edgeFlags = style.getFlag(a, R.styleable.BaseKeyboard_Key_keyEdgeFlags, 0); edgeFlags |= parent.rowEdgeFlags; - icon = a.getDrawable(R.styleable.BaseKeyboard_Key_keyIcon); + icon = style.getDrawable(a, R.styleable.BaseKeyboard_Key_keyIcon); setDefaultBounds(icon); - hintIcon = a.getDrawable(R.styleable.BaseKeyboard_Key_keyHintIcon); + hintIcon = style.getDrawable(a, R.styleable.BaseKeyboard_Key_keyHintIcon); setDefaultBounds(hintIcon); - manualTemporaryUpperCaseHintIcon = a.getDrawable( + manualTemporaryUpperCaseHintIcon = style.getDrawable(a, R.styleable.BaseKeyboard_Key_manualTemporaryUpperCaseHintIcon); setDefaultBounds(manualTemporaryUpperCaseHintIcon); - label = a.getText(R.styleable.BaseKeyboard_Key_keyLabel); - labelOption = a.getInt(R.styleable.BaseKeyboard_Key_keyLabelOption, 0); - manualTemporaryUpperCaseCode = a.getInt( + label = style.getText(a, R.styleable.BaseKeyboard_Key_keyLabel); + labelOption = style.getFlag(a, R.styleable.BaseKeyboard_Key_keyLabelOption, 0); + manualTemporaryUpperCaseCode = style.getInt(a, R.styleable.BaseKeyboard_Key_manualTemporaryUpperCaseCode, 0); - text = a.getText(R.styleable.BaseKeyboard_Key_keyOutputText); + text = style.getText(a, R.styleable.BaseKeyboard_Key_keyOutputText); if (codes == null && !TextUtils.isEmpty(label)) { codes = new int[] { label.charAt(0) }; @@ -366,28 +369,6 @@ public class BaseKeyboard { } } - private int[] parseCSV(String value) { - int count = 0; - int lastIndex = 0; - if (value.length() > 0) { - count++; - while ((lastIndex = value.indexOf(",", lastIndex + 1)) > 0) { - count++; - } - } - int[] values = new int[count]; - count = 0; - StringTokenizer st = new StringTokenizer(value, ","); - while (st.hasMoreTokens()) { - try { - values[count++] = Integer.parseInt(st.nextToken()); - } catch (NumberFormatException nfe) { - Log.e(TAG, "Error parsing keycodes " + value); - } - } - return values; - } - /** * Detects if a point falls inside this key. * @param x the x-coordinate of the point @@ -560,6 +541,10 @@ public class BaseKeyboard { mTotalHeight = y + mDefaultHeight; } + public KeyboardId getKeyboardId() { + return mId; + } + public List<Key> getKeys() { return mKeys; } @@ -688,14 +673,15 @@ public class BaseKeyboard { // TODO should be private protected BaseKeyboard.Key createKeyFromXml(Resources res, Row parent, int x, int y, - XmlResourceParser parser) { - return new BaseKeyboard.Key(res, parent, x, y, parser); + XmlResourceParser parser, KeyStyles keyStyles) { + return new BaseKeyboard.Key(res, parent, x, y, parser, keyStyles); } private void loadKeyboard(Context context, int xmlLayoutResId) { try { - BaseKeyboardParser parser = new BaseKeyboardParser(this, context.getResources()); - parser.parseKeyboard(context.getResources().getXml(xmlLayoutResId)); + final Resources res = context.getResources(); + BaseKeyboardParser parser = new BaseKeyboardParser(this, res); + parser.parseKeyboard(res.getXml(xmlLayoutResId)); // mTotalWidth is the width of this keyboard which is maximum width of row. mTotalWidth = parser.getMaxRowWidth(); mTotalHeight = parser.getTotalHeight(); diff --git a/java/src/com/android/inputmethod/latin/BaseKeyboardParser.java b/java/src/com/android/inputmethod/latin/BaseKeyboardParser.java index 1aee2fcef..ea209c515 100644 --- a/java/src/com/android/inputmethod/latin/BaseKeyboardParser.java +++ b/java/src/com/android/inputmethod/latin/BaseKeyboardParser.java @@ -83,27 +83,25 @@ import java.util.List; * >/default< * >/switch< * </pre> - * - * TODO: These are some random ideas to improve this parser. - * - can specify keyWidth attribute by multiplication of default keyWidth - * for example: keyWidth="200%b" ("b" stands for "base") - * - can declare style and specify styles within tags. - * for example: + * You can declare Key style and specify styles within Key tags. + * <pre> * >switch< * >case colorScheme="white"< - * >declare-style name="shift-key" parentStyle="modifier-key"< - * >item name="keyIcon"<@drawable/sym_keyboard_shift">/item< - * >/declare-style< + * >key-style styleName="shift-key" parentStyle="modifier-key" + * keyIcon="@drawable/sym_keyboard_shift" + * /< * >/case< * >case colorScheme="black"< - * >declare-style name="shift-key" parentStyle="modifier-key"< - * >item name="keyIcon"<@drawable/sym_bkeyboard_shift">/item< - * >/declare-style< + * >key-style styleName="shift-key" parentStyle="modifier-key" + * keyIcon="@drawable/sym_bkeyboard_shift" + * /< * >/case< * >/switch< * ... - * >Key include-style="shift-key" ... /< + * >Key keyStyle="shift-key" ... /< + * </pre> */ + public class BaseKeyboardParser { private static final String TAG = "BaseKeyboardParser"; private static final boolean DEBUG_TAG = false; @@ -118,6 +116,7 @@ public class BaseKeyboardParser { private static final String TAG_SWITCH = "switch"; private static final String TAG_CASE = "case"; private static final String TAG_DEFAULT = "default"; + private static final String TAG_KEY_STYLE = "key-style"; private final BaseKeyboard mKeyboard; private final Resources mResources; @@ -127,6 +126,7 @@ public class BaseKeyboardParser { private int mMaxRowWidth = 0; private int mTotalHeight = 0; private Row mCurrentRow = null; + private final KeyStyles mKeyStyles = new KeyStyles(); public BaseKeyboardParser(BaseKeyboard keyboard, Resources res) { mKeyboard = keyboard; @@ -192,6 +192,8 @@ public class BaseKeyboardParser { parseIncludeKeyboardContent(parser, keys); } else if (TAG_SWITCH.equals(tag)) { parseSwitchKeyboardContent(parser, keys); + } else if (TAG_KEY_STYLE.equals(tag)) { + parseKeyStyle(parser, keys); } else { throw new IllegalStartTag(parser, TAG_ROW); } @@ -205,6 +207,8 @@ public class BaseKeyboardParser { break; } else if (TAG_MERGE.equals(tag)) { break; + } else if (TAG_KEY_STYLE.equals(tag)) { + continue; } else { throw new IllegalEndTag(parser, TAG_ROW); } @@ -227,6 +231,8 @@ public class BaseKeyboardParser { parseIncludeRowContent(parser, row, keys); } else if (TAG_SWITCH.equals(tag)) { parseSwitchRowContent(parser, row, keys); + } else if (TAG_KEY_STYLE.equals(tag)) { + parseKeyStyle(parser, keys); } else { throw new IllegalStartTag(parser, TAG_KEY); } @@ -241,6 +247,8 @@ public class BaseKeyboardParser { break; } else if (TAG_MERGE.equals(tag)) { break; + } else if (TAG_KEY_STYLE.equals(tag)) { + continue; } else { throw new IllegalEndTag(parser, TAG_KEY); } @@ -253,7 +261,8 @@ public class BaseKeyboardParser { if (keys == null) { checkEndTag(TAG_KEY, parser); } else { - Key key = mKeyboard.createKeyFromXml(mResources, row, mCurrentX, mCurrentY, parser); + Key key = mKeyboard.createKeyFromXml(mResources, row, mCurrentX, mCurrentY, parser, + mKeyStyles); checkEndTag(TAG_KEY, parser); keys.add(key); if (key.codes[0] == BaseKeyboard.KEYCODE_SHIFT) @@ -439,6 +448,24 @@ public class BaseKeyboardParser { return true; } + private void parseKeyStyle(XmlResourceParser parser, List<Key> keys) + throws XmlPullParserException, IOException { + TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.BaseKeyboard_KeyStyle); + TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.BaseKeyboard_Key); + try { + if (!a.hasValue(R.styleable.BaseKeyboard_KeyStyle_styleName)) + throw new ParseException("<" + TAG_KEY_STYLE + + "/> needs styleName attribute", parser); + if (keys != null) + mKeyStyles.parseKeyStyleAttributes(a, keyAttrs, parser); + } finally { + a.recycle(); + keyAttrs.recycle(); + } + } + private static void checkEndTag(String tag, XmlResourceParser parser) throws XmlPullParserException, IOException { if (parser.next() == XmlResourceParser.END_TAG && tag.equals(parser.getName())) @@ -486,7 +513,7 @@ public class BaseKeyboardParser { } @SuppressWarnings("serial") - private static class ParseException extends InflateException { + public static class ParseException extends InflateException { public ParseException(String msg, XmlResourceParser parser) { super(msg + " at line " + parser.getLineNumber()); } diff --git a/java/src/com/android/inputmethod/latin/KeyStyles.java b/java/src/com/android/inputmethod/latin/KeyStyles.java new file mode 100644 index 000000000..e53e351a3 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/KeyStyles.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * 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.latin; + +import com.android.inputmethod.latin.BaseKeyboardParser.ParseException; + +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.graphics.drawable.Drawable; +import android.util.Log; +import android.util.TypedValue; + +import java.util.HashMap; +import java.util.StringTokenizer; + +public class KeyStyles { + private static final String TAG = "KeyStyles"; + + private final HashMap<String, DeclaredKeyStyle> mStyles = + new HashMap<String, DeclaredKeyStyle>(); + private static final KeyStyle EMPTY_KEY_STYLE = new EmptyKeyStyle(); + + public interface KeyStyle { + public int[] getIntArray(TypedArray a, int index); + public Drawable getDrawable(TypedArray a, int index); + public CharSequence getText(TypedArray a, int index); + public int getResourceId(TypedArray a, int index, int defaultValue); + public int getInt(TypedArray a, int index, int defaultValue); + public int getFlag(TypedArray a, int index, int defaultValue); + public boolean getBoolean(TypedArray a, int index, boolean defaultValue); + } + + public static class EmptyKeyStyle implements KeyStyle { + private EmptyKeyStyle() { + } + + public int[] getIntArray(TypedArray a, int index) { + return parseIntArray(a, index); + } + + public Drawable getDrawable(TypedArray a, int index) { + return a.getDrawable(index); + } + + public CharSequence getText(TypedArray a, int index) { + return a.getText(index); + } + + public int getResourceId(TypedArray a, int index, int defaultValue) { + return a.getResourceId(index, defaultValue); + } + + public int getInt(TypedArray a, int index, int defaultValue) { + return a.getInt(index, defaultValue); + } + + public int getFlag(TypedArray a, int index, int defaultValue) { + return a.getInt(index, defaultValue); + } + + public boolean getBoolean(TypedArray a, int index, boolean defaultValue) { + return a.getBoolean(index, defaultValue); + } + + protected static int[] parseIntArray(TypedArray a, int index) { + TypedValue v = new TypedValue(); + a.getValue(index, v); + if (v.type == TypedValue.TYPE_INT_DEC || v.type == TypedValue.TYPE_INT_HEX) { + return new int[] { v.data }; + } else if (v.type == TypedValue.TYPE_STRING) { + return parseCSV(v.string.toString()); + } else { + return null; + } + } + + private static int[] parseCSV(String value) { + int count = 0; + int lastIndex = 0; + if (value.length() > 0) { + count++; + while ((lastIndex = value.indexOf(",", lastIndex + 1)) > 0) { + count++; + } + } + int[] values = new int[count]; + count = 0; + StringTokenizer st = new StringTokenizer(value, ","); + while (st.hasMoreTokens()) { + try { + values[count++] = Integer.parseInt(st.nextToken()); + } catch (NumberFormatException nfe) { + Log.e(TAG, "Error parsing integer CSV " + value); + } + } + return values; + } + } + + public static class DeclaredKeyStyle extends EmptyKeyStyle { + private final HashMap<Integer, Object> mAttributes = new HashMap<Integer, Object>(); + + @Override + public int[] getIntArray(TypedArray a, int index) { + return a.hasValue(index) + ? super.getIntArray(a, index) : (int[])mAttributes.get(index); + } + + @Override + public Drawable getDrawable(TypedArray a, int index) { + return a.hasValue(index) + ? super.getDrawable(a, index) : (Drawable)mAttributes.get(index); + } + + @Override + public CharSequence getText(TypedArray a, int index) { + return a.hasValue(index) + ? super.getText(a, index) : (CharSequence)mAttributes.get(index); + } + + @Override + public int getResourceId(TypedArray a, int index, int defaultValue) { + final Integer value = (Integer)mAttributes.get(index); + return super.getResourceId(a, index, (value != null) ? value : defaultValue); + } + + @Override + public int getFlag(TypedArray a, int index, int defaultValue) { + final Integer value = (Integer)mAttributes.get(index); + return super.getFlag(a, index, defaultValue) | (value != null ? value : 0); + } + + @Override + public boolean getBoolean(TypedArray a, int index, boolean defaultValue) { + final Boolean value = (Boolean)mAttributes.get(index); + return super.getBoolean(a, index, (value != null) ? value : defaultValue); + } + + private DeclaredKeyStyle() { + super(); + } + + private void parseKeyStyleAttributes(TypedArray a) { + // TODO: Currently not all Key attributes can be declared as style. + readIntArray(a, R.styleable.BaseKeyboard_Key_codes); + readText(a, R.styleable.BaseKeyboard_Key_keyLabel); + readFlag(a, R.styleable.BaseKeyboard_Key_keyLabelOption); + readText(a, R.styleable.BaseKeyboard_Key_keyOutputText); + readDrawable(a, R.styleable.BaseKeyboard_Key_keyIcon); + readDrawable(a, R.styleable.BaseKeyboard_Key_iconPreview); + readDrawable(a, R.styleable.BaseKeyboard_Key_keyHintIcon); + readResourceId(a, R.styleable.BaseKeyboard_Key_popupKeyboard); + readBoolean(a, R.styleable.BaseKeyboard_Key_isModifier); + readBoolean(a, R.styleable.BaseKeyboard_Key_isSticky); + readBoolean(a, R.styleable.BaseKeyboard_Key_isRepeatable); + } + + private void readDrawable(TypedArray a, int index) { + if (a.hasValue(index)) + mAttributes.put(index, a.getDrawable(index)); + } + + private void readText(TypedArray a, int index) { + if (a.hasValue(index)) + mAttributes.put(index, a.getText(index)); + } + + private void readResourceId(TypedArray a, int index) { + if (a.hasValue(index)) + mAttributes.put(index, a.getResourceId(index, 0)); + } + + private void readFlag(TypedArray a, int index) { + final Integer value = (Integer)mAttributes.get(index); + if (a.hasValue(index)) + mAttributes.put(index, a.getInt(index, 0) | (value != null ? value : 0)); + } + + private void readBoolean(TypedArray a, int index) { + if (a.hasValue(index)) + mAttributes.put(index, a.getBoolean(index, false)); + } + + private void readIntArray(TypedArray a, int index) { + if (a.hasValue(index)) { + final int[] value = parseIntArray(a, index); + if (value != null) + mAttributes.put(index, value); + } + } + + private void addParent(DeclaredKeyStyle parentStyle) { + mAttributes.putAll(parentStyle.mAttributes); + } + } + + public void parseKeyStyleAttributes(TypedArray a, TypedArray keyAttrs, + XmlResourceParser parser) { + String styleName = a.getString(R.styleable.BaseKeyboard_KeyStyle_styleName); + if (mStyles.containsKey(styleName)) + throw new ParseException("duplicate key style declared: " + styleName, parser); + + final DeclaredKeyStyle style = new DeclaredKeyStyle(); + if (a.hasValue(R.styleable.BaseKeyboard_KeyStyle_parentStyle)) { + String parentStyle = a.getString( + R.styleable.BaseKeyboard_KeyStyle_parentStyle); + final DeclaredKeyStyle parent = mStyles.get(parentStyle); + if (parent == null) + throw new ParseException("Unknown parentStyle " + parent, parser); + style.addParent(parent); + } + style.parseKeyStyleAttributes(keyAttrs); + mStyles.put(styleName, style); + } + + public KeyStyle getKeyStyle(String styleName) { + return mStyles.get(styleName); + } + + public KeyStyle getEmptyKeyStyle() { + return EMPTY_KEY_STYLE; + } +} diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboard.java b/java/src/com/android/inputmethod/latin/LatinKeyboard.java index 1242818d8..fc62053fe 100644 --- a/java/src/com/android/inputmethod/latin/LatinKeyboard.java +++ b/java/src/com/android/inputmethod/latin/LatinKeyboard.java @@ -127,8 +127,8 @@ public class LatinKeyboard extends BaseKeyboard { @Override protected Key createKeyFromXml(Resources res, Row parent, int x, int y, - XmlResourceParser parser) { - Key key = new LatinKey(res, parent, x, y, parser); + XmlResourceParser parser, KeyStyles keyStyles) { + Key key = new LatinKey(res, parent, x, y, parser, keyStyles); switch (key.codes[0]) { case LatinIME.KEYCODE_ENTER: mEnterKey = key; @@ -619,8 +619,8 @@ public class LatinKeyboard extends BaseKeyboard { private boolean mShiftLockEnabled; public LatinKey(Resources res, BaseKeyboard.Row parent, int x, int y, - XmlResourceParser parser) { - super(res, parent, x, y, parser); + XmlResourceParser parser, KeyStyles keyStyles) { + super(res, parent, x, y, parser, keyStyles); if (popupCharacters != null && popupCharacters.length() == 0) { // If there is a keyboard with no keys specified in popupCharacters popupResId = 0; |