summaryrefslogtreecommitdiff
path: root/src/com/android/inputmethod/pinyin/XmlKeyboardLoader.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/inputmethod/pinyin/XmlKeyboardLoader.java')
-rw-r--r--src/com/android/inputmethod/pinyin/XmlKeyboardLoader.java835
1 files changed, 835 insertions, 0 deletions
diff --git a/src/com/android/inputmethod/pinyin/XmlKeyboardLoader.java b/src/com/android/inputmethod/pinyin/XmlKeyboardLoader.java
new file mode 100644
index 0000000..fd192a3
--- /dev/null
+++ b/src/com/android/inputmethod/pinyin/XmlKeyboardLoader.java
@@ -0,0 +1,835 @@
+/*
+ * Copyright (C) 2009 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.pinyin;
+
+import com.android.inputmethod.pinyin.SoftKeyboard.KeyRow;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+
+import java.io.IOException;
+import java.util.regex.Pattern;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+/**
+ * Class used to load a soft keyboard or a soft keyboard template from xml
+ * files.
+ */
+public class XmlKeyboardLoader {
+ /**
+ * The tag used to define an xml-based soft keyboard template.
+ */
+ private static final String XMLTAG_SKB_TEMPLATE = "skb_template";
+
+ /**
+ * The tag used to indicate the soft key type which is defined inside the
+ * {@link #XMLTAG_SKB_TEMPLATE} element in the xml file. file.
+ */
+ private static final String XMLTAG_KEYTYPE = "key_type";
+
+ /**
+ * The tag used to define a default key icon for enter/delete/space keys. It
+ * is defined inside the {@link #XMLTAG_SKB_TEMPLATE} element in the xml
+ * file.
+ */
+ private static final String XMLTAG_KEYICON = "key_icon";
+
+ /**
+ * Attribute tag of the left and right margin for a key. A key's width
+ * should be larger than double of this value. Defined inside
+ * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}.
+ */
+ private static final String XMLATTR_KEY_XMARGIN = "key_xmargin";
+
+ /**
+ * Attribute tag of the top and bottom margin for a key. A key's height
+ * should be larger than double of this value. Defined inside
+ * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}.
+ */
+ private static final String XMLATTR_KEY_YMARGIN = "key_ymargin";
+
+ /**
+ * Attribute tag of the keyboard background image. Defined inside
+ * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}.
+ */
+ private static final String XMLATTR_SKB_BG = "skb_bg";
+
+ /**
+ * Attribute tag of the balloon background image for key press. Defined
+ * inside {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}.
+ */
+ private static final String XMLATTR_BALLOON_BG = "balloon_bg";
+
+ /**
+ * Attribute tag of the popup balloon background image for key press or
+ * popup mini keyboard. Defined inside {@link #XMLTAG_SKB_TEMPLATE} and
+ * {@link #XMLTAG_KEYBOARD}.
+ */
+ private static final String XMLATTR_POPUP_BG = "popup_bg";
+
+ /**
+ * Attribute tag of the color to draw key label. Defined inside
+ * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYTYPE}.
+ */
+ private static final String XMLATTR_COLOR = "color";
+
+ /**
+ * Attribute tag of the color to draw key's highlighted label. Defined
+ * inside {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYTYPE}.
+ */
+ private static final String XMLATTR_COLOR_HIGHLIGHT = "color_highlight";
+
+ /**
+ * Attribute tag of the color to draw key's label in the popup balloon.
+ * Defined inside {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYTYPE}.
+ */
+ private static final String XMLATTR_COLOR_BALLOON = "color_balloon";
+
+ /**
+ * Attribute tag of the id of {@link #XMLTAG_KEYTYPE} and
+ * {@link #XMLTAG_KEY}. Key types and keys defined in a soft keyboard
+ * template should have id, because a soft keyboard needs the id to refer to
+ * these default definitions. If a key defined in {@link #XMLTAG_KEYBOARD}
+ * does not id, that means the key is newly defined; if it has id (and only
+ * has id), the id is used to find the default definition from the soft
+ * keyboard template.
+ */
+ private static final String XMLATTR_ID = "id";
+
+ /**
+ * Attribute tag of the key background for a specified key type. Defined
+ * inside {@link #XMLTAG_KEYTYPE}.
+ */
+ private static final String XMLATTR_KEYTYPE_BG = "bg";
+
+ /**
+ * Attribute tag of the key high-light background for a specified key type.
+ * Defined inside {@link #XMLTAG_KEYTYPE}.
+ */
+ private static final String XMLATTR_KEYTYPE_HLBG = "hlbg";
+
+ /**
+ * Attribute tag of the starting x-position of an element. It can be defined
+ * in {@link #XMLTAG_ROW} and {@link #XMLTAG_KEY} in {XMLTAG_SKB_TEMPLATE}.
+ * If not defined, 0 will be used. For a key defined in
+ * {@link #XMLTAG_KEYBOARD}, it always use its previous keys information to
+ * calculate its own position.
+ */
+ private static final String XMLATTR_START_POS_X = "start_pos_x";
+
+ /**
+ * Attribute tag of the starting y-position of an element. It can be defined
+ * in {@link #XMLTAG_ROW} and {@link #XMLTAG_KEY} in {XMLTAG_SKB_TEMPLATE}.
+ * If not defined, 0 will be used. For a key defined in
+ * {@link #XMLTAG_KEYBOARD}, it always use its previous keys information to
+ * calculate its own position.
+ */
+ private static final String XMLATTR_START_POS_Y = "start_pos_y";
+
+ /**
+ * Attribute tag of a row's id. Defined {@link #XMLTAG_ROW}. If not defined,
+ * -1 will be used. Rows with id -1 will be enabled always, rows with same
+ * row id will be enabled when the id is the same to the activated id of the
+ * soft keyboard.
+ */
+ private static final String XMLATTR_ROW_ID = "row_id";
+
+ /** The tag used to indicate the keyboard element in the xml file. */
+ private static final String XMLTAG_KEYBOARD = "keyboard";
+
+ /** The tag used to indicate the row element in the xml file. */
+ private static final String XMLTAG_ROW = "row";
+
+ /** The tag used to indicate key-array element in the xml file. */
+ private static final String XMLTAG_KEYS = "keys";
+
+ /**
+ * The tag used to indicate a key element in the xml file. If the element is
+ * defined in a soft keyboard template, it should have an id. If it is
+ * defined in a soft keyboard, id is not required.
+ */
+ private static final String XMLTAG_KEY = "key";
+
+ /** The tag used to indicate a key's toggle element in the xml file. */
+ private static final String XMLTAG_TOGGLE_STATE = "toggle_state";
+
+ /**
+ * Attribute tag of the toggle state id for toggle key. Defined inside
+ * {@link #XMLTAG_TOGGLE_STATE}
+ */
+ private static final String XMLATTR_TOGGLE_STATE_ID = "state_id";
+
+ /** Attribute tag of key template for the soft keyboard. */
+ private static final String XMLATTR_SKB_TEMPLATE = "skb_template";
+
+ /**
+ * Attribute tag used to indicate whether this soft keyboard needs to be
+ * cached in memory for future use. {@link #DEFAULT_SKB_CACHE_FLAG}
+ * specifies the default value.
+ */
+ private static final String XMLATTR_SKB_CACHE_FLAG = "skb_cache_flag";
+
+ /**
+ * Attribute tag used to indicate whether this soft keyboard is sticky. A
+ * sticky soft keyboard will keep the current layout unless user makes a
+ * switch explicitly. A none sticky soft keyboard will automatically goes
+ * back to the previous keyboard after click a none-function key.
+ * {@link #DEFAULT_SKB_STICKY_FLAG} specifies the default value.
+ */
+ private static final String XMLATTR_SKB_STICKY_FLAG = "skb_sticky_flag";
+
+ /** Attribute tag to indicate whether it is a QWERTY soft keyboard. */
+ private static final String XMLATTR_QWERTY = "qwerty";
+
+ /**
+ * When the soft keyboard is a QWERTY one, this attribute tag to get the
+ * information that whether it is defined in upper case.
+ */
+ private static final String XMLATTR_QWERTY_UPPERCASE = "qwerty_uppercase";
+
+ /** Attribute tag of key type. */
+ private static final String XMLATTR_KEY_TYPE = "key_type";
+
+ /** Attribute tag of key width. */
+ private static final String XMLATTR_KEY_WIDTH = "width";
+
+ /** Attribute tag of key height. */
+ private static final String XMLATTR_KEY_HEIGHT = "height";
+
+ /** Attribute tag of the key's repeating ability. */
+ private static final String XMLATTR_KEY_REPEAT = "repeat";
+
+ /** Attribute tag of the key's behavior for balloon. */
+ private static final String XMLATTR_KEY_BALLOON = "balloon";
+
+ /** Attribute tag of the key splitter in a key array. */
+ private static final String XMLATTR_KEY_SPLITTER = "splitter";
+
+ /** Attribute tag of the key labels in a key array. */
+ private static final String XMLATTR_KEY_LABELS = "labels";
+
+ /** Attribute tag of the key codes in a key array. */
+ private static final String XMLATTR_KEY_CODES = "codes";
+
+ /** Attribute tag of the key label in a key. */
+ private static final String XMLATTR_KEY_LABEL = "label";
+
+ /** Attribute tag of the key code in a key. */
+ private static final String XMLATTR_KEY_CODE = "code";
+
+ /** Attribute tag of the key icon in a key. */
+ private static final String XMLATTR_KEY_ICON = "icon";
+
+ /** Attribute tag of the key's popup icon in a key. */
+ private static final String XMLATTR_KEY_ICON_POPUP = "icon_popup";
+
+ /** The id for a mini popup soft keyboard. */
+ private static final String XMLATTR_KEY_POPUP_SKBID = "popup_skb";
+
+ private static boolean DEFAULT_SKB_CACHE_FLAG = true;
+
+ private static boolean DEFAULT_SKB_STICKY_FLAG = true;
+
+ /**
+ * The key type id for invalid key type. It is also used to generate next
+ * valid key type id by adding 1.
+ */
+ private static final int KEYTYPE_ID_LAST = -1;
+
+ private Context mContext;
+
+ private Resources mResources;
+
+ /** The event type in parsing the xml file. */
+ private int mXmlEventType;
+
+ /**
+ * The current soft keyboard template used by the current soft keyboard
+ * under loading.
+ **/
+ private SkbTemplate mSkbTemplate;
+
+ /** The x position for the next key. */
+ float mKeyXPos;
+
+ /** The y position for the next key. */
+ float mKeyYPos;
+
+ /** The width of the keyboard to load. */
+ int mSkbWidth;
+
+ /** The height of the keyboard to load. */
+ int mSkbHeight;
+
+ /** Key margin in x-way. */
+ float mKeyXMargin = 0;
+
+ /** Key margin in y-way. */
+ float mKeyYMargin = 0;
+
+ /**
+ * Used to indicate whether next event has been fetched during processing
+ * the the current event.
+ */
+ boolean mNextEventFetched = false;
+
+ String mAttrTmp;
+
+ class KeyCommonAttributes {
+ XmlResourceParser mXrp;
+ int keyType;
+ float keyWidth;
+ float keyHeight;
+ boolean repeat;
+ boolean balloon;
+
+ KeyCommonAttributes(XmlResourceParser xrp) {
+ mXrp = xrp;
+ balloon = true;
+ }
+
+ // Make sure the default object is not null.
+ boolean getAttributes(KeyCommonAttributes defAttr) {
+ keyType = getInteger(mXrp, XMLATTR_KEY_TYPE, defAttr.keyType);
+ keyWidth = getFloat(mXrp, XMLATTR_KEY_WIDTH, defAttr.keyWidth);
+ keyHeight = getFloat(mXrp, XMLATTR_KEY_HEIGHT, defAttr.keyHeight);
+ repeat = getBoolean(mXrp, XMLATTR_KEY_REPEAT, defAttr.repeat);
+ balloon = getBoolean(mXrp, XMLATTR_KEY_BALLOON, defAttr.balloon);
+ if (keyType < 0 || keyWidth <= 0 || keyHeight <= 0) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ public XmlKeyboardLoader(Context context) {
+ mContext = context;
+ mResources = mContext.getResources();
+ }
+
+ public SkbTemplate loadSkbTemplate(int resourceId) {
+ if (null == mContext || 0 == resourceId) {
+ return null;
+ }
+ Resources r = mResources;
+ XmlResourceParser xrp = r.getXml(resourceId);
+
+ KeyCommonAttributes attrDef = new KeyCommonAttributes(xrp);
+ KeyCommonAttributes attrKey = new KeyCommonAttributes(xrp);
+
+ mSkbTemplate = new SkbTemplate(resourceId);
+ int lastKeyTypeId = KEYTYPE_ID_LAST;
+ int globalColor = 0;
+ int globalColorHl = 0;
+ int globalColorBalloon = 0;
+ try {
+ mXmlEventType = xrp.next();
+ while (mXmlEventType != XmlResourceParser.END_DOCUMENT) {
+ mNextEventFetched = false;
+ if (mXmlEventType == XmlResourceParser.START_TAG) {
+ String attribute = xrp.getName();
+ if (XMLTAG_SKB_TEMPLATE.compareTo(attribute) == 0) {
+ Drawable skbBg = getDrawable(xrp, XMLATTR_SKB_BG, null);
+ Drawable balloonBg = getDrawable(xrp,
+ XMLATTR_BALLOON_BG, null);
+ Drawable popupBg = getDrawable(xrp, XMLATTR_POPUP_BG,
+ null);
+ if (null == skbBg || null == balloonBg
+ || null == popupBg) {
+ return null;
+ }
+ mSkbTemplate.setBackgrounds(skbBg, balloonBg, popupBg);
+
+ float xMargin = getFloat(xrp, XMLATTR_KEY_XMARGIN, 0);
+ float yMargin = getFloat(xrp, XMLATTR_KEY_YMARGIN, 0);
+ mSkbTemplate.setMargins(xMargin, yMargin);
+
+ // Get default global colors.
+ globalColor = getColor(xrp, XMLATTR_COLOR, 0);
+ globalColorHl = getColor(xrp, XMLATTR_COLOR_HIGHLIGHT,
+ 0xffffffff);
+ globalColorBalloon = getColor(xrp,
+ XMLATTR_COLOR_BALLOON, 0xffffffff);
+ } else if (XMLTAG_KEYTYPE.compareTo(attribute) == 0) {
+ int id = getInteger(xrp, XMLATTR_ID, KEYTYPE_ID_LAST);
+ Drawable bg = getDrawable(xrp, XMLATTR_KEYTYPE_BG, null);
+ Drawable hlBg = getDrawable(xrp, XMLATTR_KEYTYPE_HLBG,
+ null);
+ int color = getColor(xrp, XMLATTR_COLOR, globalColor);
+ int colorHl = getColor(xrp, XMLATTR_COLOR_HIGHLIGHT,
+ globalColorHl);
+ int colorBalloon = getColor(xrp, XMLATTR_COLOR_BALLOON,
+ globalColorBalloon);
+ if (id != lastKeyTypeId + 1) {
+ return null;
+ }
+ SoftKeyType keyType = mSkbTemplate.createKeyType(id,
+ bg, hlBg);
+ keyType.setColors(color, colorHl, colorBalloon);
+ if (!mSkbTemplate.addKeyType(keyType)) {
+ return null;
+ }
+ lastKeyTypeId = id;
+ } else if (XMLTAG_KEYICON.compareTo(attribute) == 0) {
+ int keyCode = getInteger(xrp, XMLATTR_KEY_CODE, 0);
+ Drawable icon = getDrawable(xrp, XMLATTR_KEY_ICON, null);
+ Drawable iconPopup = getDrawable(xrp,
+ XMLATTR_KEY_ICON_POPUP, null);
+ if (null != icon && null != iconPopup) {
+ mSkbTemplate.addDefaultKeyIcons(keyCode, icon,
+ iconPopup);
+ }
+ } else if (XMLTAG_KEY.compareTo(attribute) == 0) {
+ int keyId = this.getInteger(xrp, XMLATTR_ID, -1);
+ if (-1 == keyId) return null;
+
+ if (!attrKey.getAttributes(attrDef)) {
+ return null;
+ }
+
+ // Update the key position for the key.
+ mKeyXPos = getFloat(xrp, XMLATTR_START_POS_X, 0);
+ mKeyYPos = getFloat(xrp, XMLATTR_START_POS_Y, 0);
+
+ SoftKey softKey = getSoftKey(xrp, attrKey);
+ if (null == softKey) return null;
+ mSkbTemplate.addDefaultKey(keyId, softKey);
+ }
+ }
+ // Get the next tag.
+ if (!mNextEventFetched) mXmlEventType = xrp.next();
+ }
+ xrp.close();
+ return mSkbTemplate;
+ } catch (XmlPullParserException e) {
+ // Log.e(TAG, "Ill-formatted keyboard template resource file");
+ } catch (IOException e) {
+ // Log.e(TAG, "Unable to keyboard template resource file");
+ }
+ return null;
+ }
+
+ public SoftKeyboard loadKeyboard(int resourceId, int skbWidth, int skbHeight) {
+ if (null == mContext) return null;
+ Resources r = mResources;
+ SkbPool skbPool = SkbPool.getInstance();
+ XmlResourceParser xrp = mContext.getResources().getXml(resourceId);
+ mSkbTemplate = null;
+ SoftKeyboard softKeyboard = null;
+ Drawable skbBg;
+ Drawable popupBg;
+ Drawable balloonBg;
+ SoftKey softKey = null;
+
+ KeyCommonAttributes attrDef = new KeyCommonAttributes(xrp);
+ KeyCommonAttributes attrSkb = new KeyCommonAttributes(xrp);
+ KeyCommonAttributes attrRow = new KeyCommonAttributes(xrp);
+ KeyCommonAttributes attrKeys = new KeyCommonAttributes(xrp);
+ KeyCommonAttributes attrKey = new KeyCommonAttributes(xrp);
+
+ mKeyXPos = 0;
+ mKeyYPos = 0;
+ mSkbWidth = skbWidth;
+ mSkbHeight = skbHeight;
+
+ try {
+ mKeyXMargin = 0;
+ mKeyYMargin = 0;
+ mXmlEventType = xrp.next();
+ while (mXmlEventType != XmlResourceParser.END_DOCUMENT) {
+ mNextEventFetched = false;
+ if (mXmlEventType == XmlResourceParser.START_TAG) {
+ String attr = xrp.getName();
+ // 1. Is it the root element, "keyboard"?
+ if (XMLTAG_KEYBOARD.compareTo(attr) == 0) {
+ // 1.1 Get the keyboard template id.
+ int skbTemplateId = xrp.getAttributeResourceValue(null,
+ XMLATTR_SKB_TEMPLATE, 0);
+
+ // 1.2 Try to get the template from pool. If it is not
+ // in, the pool will try to load it.
+ mSkbTemplate = skbPool.getSkbTemplate(skbTemplateId,
+ mContext);
+
+ if (null == mSkbTemplate
+ || !attrSkb.getAttributes(attrDef)) {
+ return null;
+ }
+
+ boolean cacheFlag = getBoolean(xrp,
+ XMLATTR_SKB_CACHE_FLAG, DEFAULT_SKB_CACHE_FLAG);
+ boolean stickyFlag = getBoolean(xrp,
+ XMLATTR_SKB_STICKY_FLAG,
+ DEFAULT_SKB_STICKY_FLAG);
+ boolean isQwerty = getBoolean(xrp, XMLATTR_QWERTY,
+ false);
+ boolean isQwertyUpperCase = getBoolean(xrp,
+ XMLATTR_QWERTY_UPPERCASE, false);
+
+ softKeyboard = new SoftKeyboard(resourceId,
+ mSkbTemplate, mSkbWidth, mSkbHeight);
+ softKeyboard.setFlags(cacheFlag, stickyFlag, isQwerty,
+ isQwertyUpperCase);
+
+ mKeyXMargin = getFloat(xrp, XMLATTR_KEY_XMARGIN,
+ mSkbTemplate.getXMargin());
+ mKeyYMargin = getFloat(xrp, XMLATTR_KEY_YMARGIN,
+ mSkbTemplate.getYMargin());
+ skbBg = getDrawable(xrp, XMLATTR_SKB_BG, null);
+ popupBg = getDrawable(xrp, XMLATTR_POPUP_BG, null);
+ balloonBg = getDrawable(xrp, XMLATTR_BALLOON_BG, null);
+ if (null != skbBg) {
+ softKeyboard.setSkbBackground(skbBg);
+ }
+ if (null != popupBg) {
+ softKeyboard.setPopupBackground(popupBg);
+ }
+ if (null != balloonBg) {
+ softKeyboard.setKeyBalloonBackground(balloonBg);
+ }
+ softKeyboard.setKeyMargins(mKeyXMargin, mKeyYMargin);
+ } else if (XMLTAG_ROW.compareTo(attr) == 0) {
+ if (!attrRow.getAttributes(attrSkb)) {
+ return null;
+ }
+ // Get the starting positions for the row.
+ mKeyXPos = getFloat(xrp, XMLATTR_START_POS_X, 0);
+ mKeyYPos = getFloat(xrp, XMLATTR_START_POS_Y, mKeyYPos);
+ int rowId = getInteger(xrp, XMLATTR_ROW_ID,
+ KeyRow.ALWAYS_SHOW_ROW_ID);
+ softKeyboard.beginNewRow(rowId, mKeyYPos);
+ } else if (XMLTAG_KEYS.compareTo(attr) == 0) {
+ if (null == softKeyboard) return null;
+ if (!attrKeys.getAttributes(attrRow)) {
+ return null;
+ }
+
+ String splitter = xrp.getAttributeValue(null,
+ XMLATTR_KEY_SPLITTER);
+ splitter = Pattern.quote(splitter);
+ String labels = xrp.getAttributeValue(null,
+ XMLATTR_KEY_LABELS);
+ String codes = xrp.getAttributeValue(null,
+ XMLATTR_KEY_CODES);
+ if (null == splitter || null == labels) {
+ return null;
+ }
+ String labelArr[] = labels.split(splitter);
+ String codeArr[] = null;
+ if (null != codes) {
+ codeArr = codes.split(splitter);
+ if (labelArr.length != codeArr.length) {
+ return null;
+ }
+ }
+
+ for (int i = 0; i < labelArr.length; i++) {
+ softKey = new SoftKey();
+ int keyCode = 0;
+ if (null != codeArr) {
+ keyCode = Integer.valueOf(codeArr[i]);
+ }
+ softKey.setKeyAttribute(keyCode, labelArr[i],
+ attrKeys.repeat, attrKeys.balloon);
+
+ softKey.setKeyType(mSkbTemplate
+ .getKeyType(attrKeys.keyType), null, null);
+
+ float left, right, top, bottom;
+ left = mKeyXPos;
+
+ right = left + attrKeys.keyWidth;
+ top = mKeyYPos;
+ bottom = top + attrKeys.keyHeight;
+
+ if (right - left < 2 * mKeyXMargin) return null;
+ if (bottom - top < 2 * mKeyYMargin) return null;
+
+ softKey.setKeyDimensions(left, top, right, bottom);
+ softKeyboard.addSoftKey(softKey);
+ mKeyXPos = right;
+ if ((int) mKeyXPos * mSkbWidth > mSkbWidth) {
+ return null;
+ }
+ }
+ } else if (XMLTAG_KEY.compareTo(attr) == 0) {
+ if (null == softKeyboard) {
+ return null;
+ }
+ if (!attrKey.getAttributes(attrRow)) {
+ return null;
+ }
+
+ int keyId = this.getInteger(xrp, XMLATTR_ID, -1);
+ if (keyId >= 0) {
+ softKey = mSkbTemplate.getDefaultKey(keyId);
+ } else {
+ softKey = getSoftKey(xrp, attrKey);
+ }
+ if (null == softKey) return null;
+
+ // Update the position for next key.
+ mKeyXPos = softKey.mRightF;
+ if ((int) mKeyXPos * mSkbWidth > mSkbWidth) {
+ return null;
+ }
+ // If the current xml event type becomes a starting tag,
+ // it indicates that we have parsed too much to get
+ // toggling states, and we started a new row. In this
+ // case, the row starting position information should
+ // be updated.
+ if (mXmlEventType == XmlResourceParser.START_TAG) {
+ attr = xrp.getName();
+ if (XMLTAG_ROW.compareTo(attr) == 0) {
+ mKeyYPos += attrRow.keyHeight;
+ if ((int) mKeyYPos * mSkbHeight > mSkbHeight) {
+ return null;
+ }
+ }
+ }
+ softKeyboard.addSoftKey(softKey);
+ }
+ } else if (mXmlEventType == XmlResourceParser.END_TAG) {
+ String attr = xrp.getName();
+ if (XMLTAG_ROW.compareTo(attr) == 0) {
+ mKeyYPos += attrRow.keyHeight;
+ if ((int) mKeyYPos * mSkbHeight > mSkbHeight) {
+ return null;
+ }
+ }
+ }
+
+ // Get the next tag.
+ if (!mNextEventFetched) mXmlEventType = xrp.next();
+ }
+ xrp.close();
+ softKeyboard.setSkbCoreSize(mSkbWidth, mSkbHeight);
+ return softKeyboard;
+ } catch (XmlPullParserException e) {
+ // Log.e(TAG, "Ill-formatted keybaord resource file");
+ } catch (IOException e) {
+ // Log.e(TAG, "Unable to read keyboard resource file");
+ }
+ return null;
+ }
+
+ // Caller makes sure xrp and r are valid.
+ private SoftKey getSoftKey(XmlResourceParser xrp,
+ KeyCommonAttributes attrKey) throws XmlPullParserException,
+ IOException {
+ int keyCode = getInteger(xrp, XMLATTR_KEY_CODE, 0);
+ String keyLabel = getString(xrp, XMLATTR_KEY_LABEL, null);
+ Drawable keyIcon = getDrawable(xrp, XMLATTR_KEY_ICON, null);
+ Drawable keyIconPopup = getDrawable(xrp, XMLATTR_KEY_ICON_POPUP, null);
+ int popupSkbId = xrp.getAttributeResourceValue(null,
+ XMLATTR_KEY_POPUP_SKBID, 0);
+
+ if (null == keyLabel && null == keyIcon) {
+ keyIcon = mSkbTemplate.getDefaultKeyIcon(keyCode);
+ keyIconPopup = mSkbTemplate.getDefaultKeyIconPopup(keyCode);
+ if (null == keyIcon || null == keyIconPopup) return null;
+ }
+
+ // Dimension information must been initialized before
+ // getting toggle state, because mKeyYPos may be changed
+ // to next row when trying to get toggle state.
+ float left, right, top, bottom;
+ left = mKeyXPos;
+ right = left + attrKey.keyWidth;
+ top = mKeyYPos;
+ bottom = top + attrKey.keyHeight;
+
+ if (right - left < 2 * mKeyXMargin) return null;
+ if (bottom - top < 2 * mKeyYMargin) return null;
+
+ // Try to find if the next tag is
+ // {@link #XMLTAG_TOGGLE_STATE_OF_KEY}, if yes, try to
+ // create a toggle key.
+ boolean toggleKey = false;
+ mXmlEventType = xrp.next();
+ mNextEventFetched = true;
+
+ SoftKey softKey;
+ if (mXmlEventType == XmlResourceParser.START_TAG) {
+ mAttrTmp = xrp.getName();
+ if (mAttrTmp.compareTo(XMLTAG_TOGGLE_STATE) == 0) {
+ toggleKey = true;
+ }
+ }
+ if (toggleKey) {
+ softKey = new SoftKeyToggle();
+ if (!((SoftKeyToggle) softKey).setToggleStates(getToggleStates(
+ attrKey, (SoftKeyToggle) softKey, keyCode))) {
+ return null;
+ }
+ } else {
+ softKey = new SoftKey();
+ }
+
+ // Set the normal state
+ softKey.setKeyAttribute(keyCode, keyLabel, attrKey.repeat,
+ attrKey.balloon);
+ softKey.setPopupSkbId(popupSkbId);
+ softKey.setKeyType(mSkbTemplate.getKeyType(attrKey.keyType), keyIcon,
+ keyIconPopup);
+
+ softKey.setKeyDimensions(left, top, right, bottom);
+ return softKey;
+ }
+
+ private SoftKeyToggle.ToggleState getToggleStates(
+ KeyCommonAttributes attrKey, SoftKeyToggle softKey, int defKeyCode)
+ throws XmlPullParserException, IOException {
+ XmlResourceParser xrp = attrKey.mXrp;
+ int stateId = getInteger(xrp, XMLATTR_TOGGLE_STATE_ID, 0);
+ if (0 == stateId) return null;
+
+ String keyLabel = getString(xrp, XMLATTR_KEY_LABEL, null);
+ int keyTypeId = getInteger(xrp, XMLATTR_KEY_TYPE, KEYTYPE_ID_LAST);
+ int keyCode;
+ if (null == keyLabel) {
+ keyCode = getInteger(xrp, XMLATTR_KEY_CODE, defKeyCode);
+ } else {
+ keyCode = getInteger(xrp, XMLATTR_KEY_CODE, 0);
+ }
+ Drawable icon = getDrawable(xrp, XMLATTR_KEY_ICON, null);
+ Drawable iconPopup = getDrawable(xrp, XMLATTR_KEY_ICON_POPUP, null);
+ if (null == icon && null == keyLabel) {
+ return null;
+ }
+ SoftKeyToggle.ToggleState rootState = softKey.createToggleState();
+ rootState.setStateId(stateId);
+ rootState.mKeyType = null;
+ if (KEYTYPE_ID_LAST != keyTypeId) {
+ rootState.mKeyType = mSkbTemplate.getKeyType(keyTypeId);
+ }
+ rootState.mKeyCode = keyCode;
+ rootState.mKeyIcon = icon;
+ rootState.mKeyIconPopup = iconPopup;
+ rootState.mKeyLabel = keyLabel;
+
+ boolean repeat = getBoolean(xrp, XMLATTR_KEY_REPEAT, attrKey.repeat);
+ boolean balloon = getBoolean(xrp, XMLATTR_KEY_BALLOON, attrKey.balloon);
+ rootState.setStateFlags(repeat, balloon);
+
+ rootState.mNextState = null;
+
+ // If there is another toggle state.
+ mXmlEventType = xrp.next();
+ while (mXmlEventType != XmlResourceParser.START_TAG
+ && mXmlEventType != XmlResourceParser.END_DOCUMENT) {
+ mXmlEventType = xrp.next();
+ }
+ if (mXmlEventType == XmlResourceParser.START_TAG) {
+ String attr = xrp.getName();
+ if (attr.compareTo(XMLTAG_TOGGLE_STATE) == 0) {
+ SoftKeyToggle.ToggleState nextState = getToggleStates(attrKey,
+ softKey, defKeyCode);
+ if (null == nextState) return null;
+ rootState.mNextState = nextState;
+ }
+ }
+
+ return rootState;
+ }
+
+ private int getInteger(XmlResourceParser xrp, String name, int defValue) {
+ int resId = xrp.getAttributeResourceValue(null, name, 0);
+ String s;
+ if (resId == 0) {
+ s = xrp.getAttributeValue(null, name);
+ if (null == s) return defValue;
+ try {
+ int ret = Integer.valueOf(s);
+ return ret;
+ } catch (NumberFormatException e) {
+ return defValue;
+ }
+ } else {
+ return Integer.parseInt(mContext.getResources().getString(resId));
+ }
+ }
+
+ private int getColor(XmlResourceParser xrp, String name, int defValue) {
+ int resId = xrp.getAttributeResourceValue(null, name, 0);
+ String s;
+ if (resId == 0) {
+ s = xrp.getAttributeValue(null, name);
+ if (null == s) return defValue;
+ try {
+ int ret = Integer.valueOf(s);
+ return ret;
+ } catch (NumberFormatException e) {
+ return defValue;
+ }
+ } else {
+ return mContext.getResources().getColor(resId);
+ }
+ }
+
+ private String getString(XmlResourceParser xrp, String name, String defValue) {
+ int resId = xrp.getAttributeResourceValue(null, name, 0);
+ if (resId == 0) {
+ return xrp.getAttributeValue(null, name);
+ } else {
+ return mContext.getResources().getString(resId);
+ }
+ }
+
+ private float getFloat(XmlResourceParser xrp, String name, float defValue) {
+ int resId = xrp.getAttributeResourceValue(null, name, 0);
+ if (resId == 0) {
+ String s = xrp.getAttributeValue(null, name);
+ if (null == s) return defValue;
+ try {
+ float ret;
+ if (s.endsWith("%p")) {
+ ret = Float.parseFloat(s.substring(0, s.length() - 2)) / 100;
+ } else {
+ ret = Float.parseFloat(s);
+ }
+ return ret;
+ } catch (NumberFormatException e) {
+ return defValue;
+ }
+ } else {
+ return mContext.getResources().getDimension(resId);
+ }
+ }
+
+ private boolean getBoolean(XmlResourceParser xrp, String name,
+ boolean defValue) {
+ String s = xrp.getAttributeValue(null, name);
+ if (null == s) return defValue;
+ try {
+ boolean ret = Boolean.parseBoolean(s);
+ return ret;
+ } catch (NumberFormatException e) {
+ return defValue;
+ }
+ }
+
+ private Drawable getDrawable(XmlResourceParser xrp, String name,
+ Drawable defValue) {
+ int resId = xrp.getAttributeResourceValue(null, name, 0);
+ if (0 == resId) return defValue;
+ return mResources.getDrawable(resId);
+ }
+}