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<
*
- *
- * 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.
+ *
* >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" ... /<
+ *
*/
+
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 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 mStyles =
+ new HashMap();
+ 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 mAttributes = new HashMap();
+
+ @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;