| /* |
| * 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); |
| } |
| } |