1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.inputmethod.pinyin; 18 19 import com.android.inputmethod.pinyin.SoftKeyboard.KeyRow; 20 21 import android.content.Context; 22 import android.content.res.Resources; 23 import android.content.res.XmlResourceParser; 24 import android.graphics.drawable.Drawable; 25 26 import java.io.IOException; 27 import java.util.regex.Pattern; 28 29 import org.xmlpull.v1.XmlPullParserException; 30 31 /** 32 * Class used to load a soft keyboard or a soft keyboard template from xml 33 * files. 34 */ 35 public class XmlKeyboardLoader { 36 /** 37 * The tag used to define an xml-based soft keyboard template. 38 */ 39 private static final String XMLTAG_SKB_TEMPLATE = "skb_template"; 40 41 /** 42 * The tag used to indicate the soft key type which is defined inside the 43 * {@link #XMLTAG_SKB_TEMPLATE} element in the xml file. file. 44 */ 45 private static final String XMLTAG_KEYTYPE = "key_type"; 46 47 /** 48 * The tag used to define a default key icon for enter/delete/space keys. It 49 * is defined inside the {@link #XMLTAG_SKB_TEMPLATE} element in the xml 50 * file. 51 */ 52 private static final String XMLTAG_KEYICON = "key_icon"; 53 54 /** 55 * Attribute tag of the left and right margin for a key. A key's width 56 * should be larger than double of this value. Defined inside 57 * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}. 58 */ 59 private static final String XMLATTR_KEY_XMARGIN = "key_xmargin"; 60 61 /** 62 * Attribute tag of the top and bottom margin for a key. A key's height 63 * should be larger than double of this value. Defined inside 64 * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}. 65 */ 66 private static final String XMLATTR_KEY_YMARGIN = "key_ymargin"; 67 68 /** 69 * Attribute tag of the keyboard background image. Defined inside 70 * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}. 71 */ 72 private static final String XMLATTR_SKB_BG = "skb_bg"; 73 74 /** 75 * Attribute tag of the balloon background image for key press. Defined 76 * inside {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYBOARD}. 77 */ 78 private static final String XMLATTR_BALLOON_BG = "balloon_bg"; 79 80 /** 81 * Attribute tag of the popup balloon background image for key press or 82 * popup mini keyboard. Defined inside {@link #XMLTAG_SKB_TEMPLATE} and 83 * {@link #XMLTAG_KEYBOARD}. 84 */ 85 private static final String XMLATTR_POPUP_BG = "popup_bg"; 86 87 /** 88 * Attribute tag of the color to draw key label. Defined inside 89 * {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYTYPE}. 90 */ 91 private static final String XMLATTR_COLOR = "color"; 92 93 /** 94 * Attribute tag of the color to draw key's highlighted label. Defined 95 * inside {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYTYPE}. 96 */ 97 private static final String XMLATTR_COLOR_HIGHLIGHT = "color_highlight"; 98 99 /** 100 * Attribute tag of the color to draw key's label in the popup balloon. 101 * Defined inside {@link #XMLTAG_SKB_TEMPLATE} and {@link #XMLTAG_KEYTYPE}. 102 */ 103 private static final String XMLATTR_COLOR_BALLOON = "color_balloon"; 104 105 /** 106 * Attribute tag of the id of {@link #XMLTAG_KEYTYPE} and 107 * {@link #XMLTAG_KEY}. Key types and keys defined in a soft keyboard 108 * template should have id, because a soft keyboard needs the id to refer to 109 * these default definitions. If a key defined in {@link #XMLTAG_KEYBOARD} 110 * does not id, that means the key is newly defined; if it has id (and only 111 * has id), the id is used to find the default definition from the soft 112 * keyboard template. 113 */ 114 private static final String XMLATTR_ID = "id"; 115 116 /** 117 * Attribute tag of the key background for a specified key type. Defined 118 * inside {@link #XMLTAG_KEYTYPE}. 119 */ 120 private static final String XMLATTR_KEYTYPE_BG = "bg"; 121 122 /** 123 * Attribute tag of the key high-light background for a specified key type. 124 * Defined inside {@link #XMLTAG_KEYTYPE}. 125 */ 126 private static final String XMLATTR_KEYTYPE_HLBG = "hlbg"; 127 128 /** 129 * Attribute tag of the starting x-position of an element. It can be defined 130 * in {@link #XMLTAG_ROW} and {@link #XMLTAG_KEY} in {XMLTAG_SKB_TEMPLATE}. 131 * If not defined, 0 will be used. For a key defined in 132 * {@link #XMLTAG_KEYBOARD}, it always use its previous keys information to 133 * calculate its own position. 134 */ 135 private static final String XMLATTR_START_POS_X = "start_pos_x"; 136 137 /** 138 * Attribute tag of the starting y-position of an element. It can be defined 139 * in {@link #XMLTAG_ROW} and {@link #XMLTAG_KEY} in {XMLTAG_SKB_TEMPLATE}. 140 * If not defined, 0 will be used. For a key defined in 141 * {@link #XMLTAG_KEYBOARD}, it always use its previous keys information to 142 * calculate its own position. 143 */ 144 private static final String XMLATTR_START_POS_Y = "start_pos_y"; 145 146 /** 147 * Attribute tag of a row's id. Defined {@link #XMLTAG_ROW}. If not defined, 148 * -1 will be used. Rows with id -1 will be enabled always, rows with same 149 * row id will be enabled when the id is the same to the activated id of the 150 * soft keyboard. 151 */ 152 private static final String XMLATTR_ROW_ID = "row_id"; 153 154 /** The tag used to indicate the keyboard element in the xml file. */ 155 private static final String XMLTAG_KEYBOARD = "keyboard"; 156 157 /** The tag used to indicate the row element in the xml file. */ 158 private static final String XMLTAG_ROW = "row"; 159 160 /** The tag used to indicate key-array element in the xml file. */ 161 private static final String XMLTAG_KEYS = "keys"; 162 163 /** 164 * The tag used to indicate a key element in the xml file. If the element is 165 * defined in a soft keyboard template, it should have an id. If it is 166 * defined in a soft keyboard, id is not required. 167 */ 168 private static final String XMLTAG_KEY = "key"; 169 170 /** The tag used to indicate a key's toggle element in the xml file. */ 171 private static final String XMLTAG_TOGGLE_STATE = "toggle_state"; 172 173 /** 174 * Attribute tag of the toggle state id for toggle key. Defined inside 175 * {@link #XMLTAG_TOGGLE_STATE} 176 */ 177 private static final String XMLATTR_TOGGLE_STATE_ID = "state_id"; 178 179 /** Attribute tag of key template for the soft keyboard. */ 180 private static final String XMLATTR_SKB_TEMPLATE = "skb_template"; 181 182 /** 183 * Attribute tag used to indicate whether this soft keyboard needs to be 184 * cached in memory for future use. {@link #DEFAULT_SKB_CACHE_FLAG} 185 * specifies the default value. 186 */ 187 private static final String XMLATTR_SKB_CACHE_FLAG = "skb_cache_flag"; 188 189 /** 190 * Attribute tag used to indicate whether this soft keyboard is sticky. A 191 * sticky soft keyboard will keep the current layout unless user makes a 192 * switch explicitly. A none sticky soft keyboard will automatically goes 193 * back to the previous keyboard after click a none-function key. 194 * {@link #DEFAULT_SKB_STICKY_FLAG} specifies the default value. 195 */ 196 private static final String XMLATTR_SKB_STICKY_FLAG = "skb_sticky_flag"; 197 198 /** Attribute tag to indicate whether it is a QWERTY soft keyboard. */ 199 private static final String XMLATTR_QWERTY = "qwerty"; 200 201 /** 202 * When the soft keyboard is a QWERTY one, this attribute tag to get the 203 * information that whether it is defined in upper case. 204 */ 205 private static final String XMLATTR_QWERTY_UPPERCASE = "qwerty_uppercase"; 206 207 /** Attribute tag of key type. */ 208 private static final String XMLATTR_KEY_TYPE = "key_type"; 209 210 /** Attribute tag of key width. */ 211 private static final String XMLATTR_KEY_WIDTH = "width"; 212 213 /** Attribute tag of key height. */ 214 private static final String XMLATTR_KEY_HEIGHT = "height"; 215 216 /** Attribute tag of the key's repeating ability. */ 217 private static final String XMLATTR_KEY_REPEAT = "repeat"; 218 219 /** Attribute tag of the key's behavior for balloon. */ 220 private static final String XMLATTR_KEY_BALLOON = "balloon"; 221 222 /** Attribute tag of the key splitter in a key array. */ 223 private static final String XMLATTR_KEY_SPLITTER = "splitter"; 224 225 /** Attribute tag of the key labels in a key array. */ 226 private static final String XMLATTR_KEY_LABELS = "labels"; 227 228 /** Attribute tag of the key codes in a key array. */ 229 private static final String XMLATTR_KEY_CODES = "codes"; 230 231 /** Attribute tag of the key label in a key. */ 232 private static final String XMLATTR_KEY_LABEL = "label"; 233 234 /** Attribute tag of the key code in a key. */ 235 private static final String XMLATTR_KEY_CODE = "code"; 236 237 /** Attribute tag of the key icon in a key. */ 238 private static final String XMLATTR_KEY_ICON = "icon"; 239 240 /** Attribute tag of the key's popup icon in a key. */ 241 private static final String XMLATTR_KEY_ICON_POPUP = "icon_popup"; 242 243 /** The id for a mini popup soft keyboard. */ 244 private static final String XMLATTR_KEY_POPUP_SKBID = "popup_skb"; 245 246 private static boolean DEFAULT_SKB_CACHE_FLAG = true; 247 248 private static boolean DEFAULT_SKB_STICKY_FLAG = true; 249 250 /** 251 * The key type id for invalid key type. It is also used to generate next 252 * valid key type id by adding 1. 253 */ 254 private static final int KEYTYPE_ID_LAST = -1; 255 256 private Context mContext; 257 258 private Resources mResources; 259 260 /** The event type in parsing the xml file. */ 261 private int mXmlEventType; 262 263 /** 264 * The current soft keyboard template used by the current soft keyboard 265 * under loading. 266 **/ 267 private SkbTemplate mSkbTemplate; 268 269 /** The x position for the next key. */ 270 float mKeyXPos; 271 272 /** The y position for the next key. */ 273 float mKeyYPos; 274 275 /** The width of the keyboard to load. */ 276 int mSkbWidth; 277 278 /** The height of the keyboard to load. */ 279 int mSkbHeight; 280 281 /** Key margin in x-way. */ 282 float mKeyXMargin = 0; 283 284 /** Key margin in y-way. */ 285 float mKeyYMargin = 0; 286 287 /** 288 * Used to indicate whether next event has been fetched during processing 289 * the the current event. 290 */ 291 boolean mNextEventFetched = false; 292 293 String mAttrTmp; 294 295 class KeyCommonAttributes { 296 XmlResourceParser mXrp; 297 int keyType; 298 float keyWidth; 299 float keyHeight; 300 boolean repeat; 301 boolean balloon; 302 KeyCommonAttributes(XmlResourceParser xrp)303 KeyCommonAttributes(XmlResourceParser xrp) { 304 mXrp = xrp; 305 balloon = true; 306 } 307 308 // Make sure the default object is not null. getAttributes(KeyCommonAttributes defAttr)309 boolean getAttributes(KeyCommonAttributes defAttr) { 310 keyType = getInteger(mXrp, XMLATTR_KEY_TYPE, defAttr.keyType); 311 keyWidth = getFloat(mXrp, XMLATTR_KEY_WIDTH, defAttr.keyWidth); 312 keyHeight = getFloat(mXrp, XMLATTR_KEY_HEIGHT, defAttr.keyHeight); 313 repeat = getBoolean(mXrp, XMLATTR_KEY_REPEAT, defAttr.repeat); 314 balloon = getBoolean(mXrp, XMLATTR_KEY_BALLOON, defAttr.balloon); 315 if (keyType < 0 || keyWidth <= 0 || keyHeight <= 0) { 316 return false; 317 } 318 return true; 319 } 320 } 321 XmlKeyboardLoader(Context context)322 public XmlKeyboardLoader(Context context) { 323 mContext = context; 324 mResources = mContext.getResources(); 325 } 326 loadSkbTemplate(int resourceId)327 public SkbTemplate loadSkbTemplate(int resourceId) { 328 if (null == mContext || 0 == resourceId) { 329 return null; 330 } 331 Resources r = mResources; 332 XmlResourceParser xrp = r.getXml(resourceId); 333 334 KeyCommonAttributes attrDef = new KeyCommonAttributes(xrp); 335 KeyCommonAttributes attrKey = new KeyCommonAttributes(xrp); 336 337 mSkbTemplate = new SkbTemplate(resourceId); 338 int lastKeyTypeId = KEYTYPE_ID_LAST; 339 int globalColor = 0; 340 int globalColorHl = 0; 341 int globalColorBalloon = 0; 342 try { 343 mXmlEventType = xrp.next(); 344 while (mXmlEventType != XmlResourceParser.END_DOCUMENT) { 345 mNextEventFetched = false; 346 if (mXmlEventType == XmlResourceParser.START_TAG) { 347 String attribute = xrp.getName(); 348 if (XMLTAG_SKB_TEMPLATE.compareTo(attribute) == 0) { 349 Drawable skbBg = getDrawable(xrp, XMLATTR_SKB_BG, null); 350 Drawable balloonBg = getDrawable(xrp, 351 XMLATTR_BALLOON_BG, null); 352 Drawable popupBg = getDrawable(xrp, XMLATTR_POPUP_BG, 353 null); 354 if (null == skbBg || null == balloonBg 355 || null == popupBg) { 356 return null; 357 } 358 mSkbTemplate.setBackgrounds(skbBg, balloonBg, popupBg); 359 360 float xMargin = getFloat(xrp, XMLATTR_KEY_XMARGIN, 0); 361 float yMargin = getFloat(xrp, XMLATTR_KEY_YMARGIN, 0); 362 mSkbTemplate.setMargins(xMargin, yMargin); 363 364 // Get default global colors. 365 globalColor = getColor(xrp, XMLATTR_COLOR, 0); 366 globalColorHl = getColor(xrp, XMLATTR_COLOR_HIGHLIGHT, 367 0xffffffff); 368 globalColorBalloon = getColor(xrp, 369 XMLATTR_COLOR_BALLOON, 0xffffffff); 370 } else if (XMLTAG_KEYTYPE.compareTo(attribute) == 0) { 371 int id = getInteger(xrp, XMLATTR_ID, KEYTYPE_ID_LAST); 372 Drawable bg = getDrawable(xrp, XMLATTR_KEYTYPE_BG, null); 373 Drawable hlBg = getDrawable(xrp, XMLATTR_KEYTYPE_HLBG, 374 null); 375 int color = getColor(xrp, XMLATTR_COLOR, globalColor); 376 int colorHl = getColor(xrp, XMLATTR_COLOR_HIGHLIGHT, 377 globalColorHl); 378 int colorBalloon = getColor(xrp, XMLATTR_COLOR_BALLOON, 379 globalColorBalloon); 380 if (id != lastKeyTypeId + 1) { 381 return null; 382 } 383 SoftKeyType keyType = mSkbTemplate.createKeyType(id, 384 bg, hlBg); 385 keyType.setColors(color, colorHl, colorBalloon); 386 if (!mSkbTemplate.addKeyType(keyType)) { 387 return null; 388 } 389 lastKeyTypeId = id; 390 } else if (XMLTAG_KEYICON.compareTo(attribute) == 0) { 391 int keyCode = getInteger(xrp, XMLATTR_KEY_CODE, 0); 392 Drawable icon = getDrawable(xrp, XMLATTR_KEY_ICON, null); 393 Drawable iconPopup = getDrawable(xrp, 394 XMLATTR_KEY_ICON_POPUP, null); 395 if (null != icon && null != iconPopup) { 396 mSkbTemplate.addDefaultKeyIcons(keyCode, icon, 397 iconPopup); 398 } 399 } else if (XMLTAG_KEY.compareTo(attribute) == 0) { 400 int keyId = this.getInteger(xrp, XMLATTR_ID, -1); 401 if (-1 == keyId) return null; 402 403 if (!attrKey.getAttributes(attrDef)) { 404 return null; 405 } 406 407 // Update the key position for the key. 408 mKeyXPos = getFloat(xrp, XMLATTR_START_POS_X, 0); 409 mKeyYPos = getFloat(xrp, XMLATTR_START_POS_Y, 0); 410 411 SoftKey softKey = getSoftKey(xrp, attrKey); 412 if (null == softKey) return null; 413 mSkbTemplate.addDefaultKey(keyId, softKey); 414 } 415 } 416 // Get the next tag. 417 if (!mNextEventFetched) mXmlEventType = xrp.next(); 418 } 419 xrp.close(); 420 return mSkbTemplate; 421 } catch (XmlPullParserException e) { 422 // Log.e(TAG, "Ill-formatted keyboard template resource file"); 423 } catch (IOException e) { 424 // Log.e(TAG, "Unable to keyboard template resource file"); 425 } 426 return null; 427 } 428 loadKeyboard(int resourceId, int skbWidth, int skbHeight)429 public SoftKeyboard loadKeyboard(int resourceId, int skbWidth, int skbHeight) { 430 if (null == mContext) return null; 431 Resources r = mResources; 432 SkbPool skbPool = SkbPool.getInstance(); 433 XmlResourceParser xrp = mContext.getResources().getXml(resourceId); 434 mSkbTemplate = null; 435 SoftKeyboard softKeyboard = null; 436 Drawable skbBg; 437 Drawable popupBg; 438 Drawable balloonBg; 439 SoftKey softKey = null; 440 441 KeyCommonAttributes attrDef = new KeyCommonAttributes(xrp); 442 KeyCommonAttributes attrSkb = new KeyCommonAttributes(xrp); 443 KeyCommonAttributes attrRow = new KeyCommonAttributes(xrp); 444 KeyCommonAttributes attrKeys = new KeyCommonAttributes(xrp); 445 KeyCommonAttributes attrKey = new KeyCommonAttributes(xrp); 446 447 mKeyXPos = 0; 448 mKeyYPos = 0; 449 mSkbWidth = skbWidth; 450 mSkbHeight = skbHeight; 451 452 try { 453 mKeyXMargin = 0; 454 mKeyYMargin = 0; 455 mXmlEventType = xrp.next(); 456 while (mXmlEventType != XmlResourceParser.END_DOCUMENT) { 457 mNextEventFetched = false; 458 if (mXmlEventType == XmlResourceParser.START_TAG) { 459 String attr = xrp.getName(); 460 // 1. Is it the root element, "keyboard"? 461 if (XMLTAG_KEYBOARD.compareTo(attr) == 0) { 462 // 1.1 Get the keyboard template id. 463 int skbTemplateId = xrp.getAttributeResourceValue(null, 464 XMLATTR_SKB_TEMPLATE, 0); 465 466 // 1.2 Try to get the template from pool. If it is not 467 // in, the pool will try to load it. 468 mSkbTemplate = skbPool.getSkbTemplate(skbTemplateId, 469 mContext); 470 471 if (null == mSkbTemplate 472 || !attrSkb.getAttributes(attrDef)) { 473 return null; 474 } 475 476 boolean cacheFlag = getBoolean(xrp, 477 XMLATTR_SKB_CACHE_FLAG, DEFAULT_SKB_CACHE_FLAG); 478 boolean stickyFlag = getBoolean(xrp, 479 XMLATTR_SKB_STICKY_FLAG, 480 DEFAULT_SKB_STICKY_FLAG); 481 boolean isQwerty = getBoolean(xrp, XMLATTR_QWERTY, 482 false); 483 boolean isQwertyUpperCase = getBoolean(xrp, 484 XMLATTR_QWERTY_UPPERCASE, false); 485 486 softKeyboard = new SoftKeyboard(resourceId, 487 mSkbTemplate, mSkbWidth, mSkbHeight); 488 softKeyboard.setFlags(cacheFlag, stickyFlag, isQwerty, 489 isQwertyUpperCase); 490 491 mKeyXMargin = getFloat(xrp, XMLATTR_KEY_XMARGIN, 492 mSkbTemplate.getXMargin()); 493 mKeyYMargin = getFloat(xrp, XMLATTR_KEY_YMARGIN, 494 mSkbTemplate.getYMargin()); 495 skbBg = getDrawable(xrp, XMLATTR_SKB_BG, null); 496 popupBg = getDrawable(xrp, XMLATTR_POPUP_BG, null); 497 balloonBg = getDrawable(xrp, XMLATTR_BALLOON_BG, null); 498 if (null != skbBg) { 499 softKeyboard.setSkbBackground(skbBg); 500 } 501 if (null != popupBg) { 502 softKeyboard.setPopupBackground(popupBg); 503 } 504 if (null != balloonBg) { 505 softKeyboard.setKeyBalloonBackground(balloonBg); 506 } 507 softKeyboard.setKeyMargins(mKeyXMargin, mKeyYMargin); 508 } else if (XMLTAG_ROW.compareTo(attr) == 0) { 509 if (!attrRow.getAttributes(attrSkb)) { 510 return null; 511 } 512 // Get the starting positions for the row. 513 mKeyXPos = getFloat(xrp, XMLATTR_START_POS_X, 0); 514 mKeyYPos = getFloat(xrp, XMLATTR_START_POS_Y, mKeyYPos); 515 int rowId = getInteger(xrp, XMLATTR_ROW_ID, 516 KeyRow.ALWAYS_SHOW_ROW_ID); 517 softKeyboard.beginNewRow(rowId, mKeyYPos); 518 } else if (XMLTAG_KEYS.compareTo(attr) == 0) { 519 if (null == softKeyboard) return null; 520 if (!attrKeys.getAttributes(attrRow)) { 521 return null; 522 } 523 524 String splitter = xrp.getAttributeValue(null, 525 XMLATTR_KEY_SPLITTER); 526 splitter = Pattern.quote(splitter); 527 String labels = xrp.getAttributeValue(null, 528 XMLATTR_KEY_LABELS); 529 String codes = xrp.getAttributeValue(null, 530 XMLATTR_KEY_CODES); 531 if (null == splitter || null == labels) { 532 return null; 533 } 534 String labelArr[] = labels.split(splitter); 535 String codeArr[] = null; 536 if (null != codes) { 537 codeArr = codes.split(splitter); 538 if (labelArr.length != codeArr.length) { 539 return null; 540 } 541 } 542 543 for (int i = 0; i < labelArr.length; i++) { 544 softKey = new SoftKey(); 545 int keyCode = 0; 546 if (null != codeArr) { 547 keyCode = Integer.valueOf(codeArr[i]); 548 } 549 softKey.setKeyAttribute(keyCode, labelArr[i], 550 attrKeys.repeat, attrKeys.balloon); 551 552 softKey.setKeyType(mSkbTemplate 553 .getKeyType(attrKeys.keyType), null, null); 554 555 float left, right, top, bottom; 556 left = mKeyXPos; 557 558 right = left + attrKeys.keyWidth; 559 top = mKeyYPos; 560 bottom = top + attrKeys.keyHeight; 561 562 if (right - left < 2 * mKeyXMargin) return null; 563 if (bottom - top < 2 * mKeyYMargin) return null; 564 565 softKey.setKeyDimensions(left, top, right, bottom); 566 softKeyboard.addSoftKey(softKey); 567 mKeyXPos = right; 568 if ((int) mKeyXPos * mSkbWidth > mSkbWidth) { 569 return null; 570 } 571 } 572 } else if (XMLTAG_KEY.compareTo(attr) == 0) { 573 if (null == softKeyboard) { 574 return null; 575 } 576 if (!attrKey.getAttributes(attrRow)) { 577 return null; 578 } 579 580 int keyId = this.getInteger(xrp, XMLATTR_ID, -1); 581 if (keyId >= 0) { 582 softKey = mSkbTemplate.getDefaultKey(keyId); 583 } else { 584 softKey = getSoftKey(xrp, attrKey); 585 } 586 if (null == softKey) return null; 587 588 // Update the position for next key. 589 mKeyXPos = softKey.mRightF; 590 if ((int) mKeyXPos * mSkbWidth > mSkbWidth) { 591 return null; 592 } 593 // If the current xml event type becomes a starting tag, 594 // it indicates that we have parsed too much to get 595 // toggling states, and we started a new row. In this 596 // case, the row starting position information should 597 // be updated. 598 if (mXmlEventType == XmlResourceParser.START_TAG) { 599 attr = xrp.getName(); 600 if (XMLTAG_ROW.compareTo(attr) == 0) { 601 mKeyYPos += attrRow.keyHeight; 602 if ((int) mKeyYPos * mSkbHeight > mSkbHeight) { 603 return null; 604 } 605 } 606 } 607 softKeyboard.addSoftKey(softKey); 608 } 609 } else if (mXmlEventType == XmlResourceParser.END_TAG) { 610 String attr = xrp.getName(); 611 if (XMLTAG_ROW.compareTo(attr) == 0) { 612 mKeyYPos += attrRow.keyHeight; 613 if ((int) mKeyYPos * mSkbHeight > mSkbHeight) { 614 return null; 615 } 616 } 617 } 618 619 // Get the next tag. 620 if (!mNextEventFetched) mXmlEventType = xrp.next(); 621 } 622 xrp.close(); 623 softKeyboard.setSkbCoreSize(mSkbWidth, mSkbHeight); 624 return softKeyboard; 625 } catch (XmlPullParserException e) { 626 // Log.e(TAG, "Ill-formatted keybaord resource file"); 627 } catch (IOException e) { 628 // Log.e(TAG, "Unable to read keyboard resource file"); 629 } 630 return null; 631 } 632 633 // Caller makes sure xrp and r are valid. getSoftKey(XmlResourceParser xrp, KeyCommonAttributes attrKey)634 private SoftKey getSoftKey(XmlResourceParser xrp, 635 KeyCommonAttributes attrKey) throws XmlPullParserException, 636 IOException { 637 int keyCode = getInteger(xrp, XMLATTR_KEY_CODE, 0); 638 String keyLabel = getString(xrp, XMLATTR_KEY_LABEL, null); 639 Drawable keyIcon = getDrawable(xrp, XMLATTR_KEY_ICON, null); 640 Drawable keyIconPopup = getDrawable(xrp, XMLATTR_KEY_ICON_POPUP, null); 641 int popupSkbId = xrp.getAttributeResourceValue(null, 642 XMLATTR_KEY_POPUP_SKBID, 0); 643 644 if (null == keyLabel && null == keyIcon) { 645 keyIcon = mSkbTemplate.getDefaultKeyIcon(keyCode); 646 keyIconPopup = mSkbTemplate.getDefaultKeyIconPopup(keyCode); 647 if (null == keyIcon || null == keyIconPopup) return null; 648 } 649 650 // Dimension information must been initialized before 651 // getting toggle state, because mKeyYPos may be changed 652 // to next row when trying to get toggle state. 653 float left, right, top, bottom; 654 left = mKeyXPos; 655 right = left + attrKey.keyWidth; 656 top = mKeyYPos; 657 bottom = top + attrKey.keyHeight; 658 659 if (right - left < 2 * mKeyXMargin) return null; 660 if (bottom - top < 2 * mKeyYMargin) return null; 661 662 // Try to find if the next tag is 663 // {@link #XMLTAG_TOGGLE_STATE_OF_KEY}, if yes, try to 664 // create a toggle key. 665 boolean toggleKey = false; 666 mXmlEventType = xrp.next(); 667 mNextEventFetched = true; 668 669 SoftKey softKey; 670 if (mXmlEventType == XmlResourceParser.START_TAG) { 671 mAttrTmp = xrp.getName(); 672 if (mAttrTmp.compareTo(XMLTAG_TOGGLE_STATE) == 0) { 673 toggleKey = true; 674 } 675 } 676 if (toggleKey) { 677 softKey = new SoftKeyToggle(); 678 if (!((SoftKeyToggle) softKey).setToggleStates(getToggleStates( 679 attrKey, (SoftKeyToggle) softKey, keyCode))) { 680 return null; 681 } 682 } else { 683 softKey = new SoftKey(); 684 } 685 686 // Set the normal state 687 softKey.setKeyAttribute(keyCode, keyLabel, attrKey.repeat, 688 attrKey.balloon); 689 softKey.setPopupSkbId(popupSkbId); 690 softKey.setKeyType(mSkbTemplate.getKeyType(attrKey.keyType), keyIcon, 691 keyIconPopup); 692 693 softKey.setKeyDimensions(left, top, right, bottom); 694 return softKey; 695 } 696 getToggleStates( KeyCommonAttributes attrKey, SoftKeyToggle softKey, int defKeyCode)697 private SoftKeyToggle.ToggleState getToggleStates( 698 KeyCommonAttributes attrKey, SoftKeyToggle softKey, int defKeyCode) 699 throws XmlPullParserException, IOException { 700 XmlResourceParser xrp = attrKey.mXrp; 701 int stateId = getInteger(xrp, XMLATTR_TOGGLE_STATE_ID, 0); 702 if (0 == stateId) return null; 703 704 String keyLabel = getString(xrp, XMLATTR_KEY_LABEL, null); 705 int keyTypeId = getInteger(xrp, XMLATTR_KEY_TYPE, KEYTYPE_ID_LAST); 706 int keyCode; 707 if (null == keyLabel) { 708 keyCode = getInteger(xrp, XMLATTR_KEY_CODE, defKeyCode); 709 } else { 710 keyCode = getInteger(xrp, XMLATTR_KEY_CODE, 0); 711 } 712 Drawable icon = getDrawable(xrp, XMLATTR_KEY_ICON, null); 713 Drawable iconPopup = getDrawable(xrp, XMLATTR_KEY_ICON_POPUP, null); 714 if (null == icon && null == keyLabel) { 715 return null; 716 } 717 SoftKeyToggle.ToggleState rootState = softKey.createToggleState(); 718 rootState.setStateId(stateId); 719 rootState.mKeyType = null; 720 if (KEYTYPE_ID_LAST != keyTypeId) { 721 rootState.mKeyType = mSkbTemplate.getKeyType(keyTypeId); 722 } 723 rootState.mKeyCode = keyCode; 724 rootState.mKeyIcon = icon; 725 rootState.mKeyIconPopup = iconPopup; 726 rootState.mKeyLabel = keyLabel; 727 728 boolean repeat = getBoolean(xrp, XMLATTR_KEY_REPEAT, attrKey.repeat); 729 boolean balloon = getBoolean(xrp, XMLATTR_KEY_BALLOON, attrKey.balloon); 730 rootState.setStateFlags(repeat, balloon); 731 732 rootState.mNextState = null; 733 734 // If there is another toggle state. 735 mXmlEventType = xrp.next(); 736 while (mXmlEventType != XmlResourceParser.START_TAG 737 && mXmlEventType != XmlResourceParser.END_DOCUMENT) { 738 mXmlEventType = xrp.next(); 739 } 740 if (mXmlEventType == XmlResourceParser.START_TAG) { 741 String attr = xrp.getName(); 742 if (attr.compareTo(XMLTAG_TOGGLE_STATE) == 0) { 743 SoftKeyToggle.ToggleState nextState = getToggleStates(attrKey, 744 softKey, defKeyCode); 745 if (null == nextState) return null; 746 rootState.mNextState = nextState; 747 } 748 } 749 750 return rootState; 751 } 752 getInteger(XmlResourceParser xrp, String name, int defValue)753 private int getInteger(XmlResourceParser xrp, String name, int defValue) { 754 int resId = xrp.getAttributeResourceValue(null, name, 0); 755 String s; 756 if (resId == 0) { 757 s = xrp.getAttributeValue(null, name); 758 if (null == s) return defValue; 759 try { 760 int ret = Integer.valueOf(s); 761 return ret; 762 } catch (NumberFormatException e) { 763 return defValue; 764 } 765 } else { 766 return Integer.parseInt(mContext.getResources().getString(resId)); 767 } 768 } 769 getColor(XmlResourceParser xrp, String name, int defValue)770 private int getColor(XmlResourceParser xrp, String name, int defValue) { 771 int resId = xrp.getAttributeResourceValue(null, name, 0); 772 String s; 773 if (resId == 0) { 774 s = xrp.getAttributeValue(null, name); 775 if (null == s) return defValue; 776 try { 777 int ret = Integer.valueOf(s); 778 return ret; 779 } catch (NumberFormatException e) { 780 return defValue; 781 } 782 } else { 783 return mContext.getResources().getColor(resId); 784 } 785 } 786 getString(XmlResourceParser xrp, String name, String defValue)787 private String getString(XmlResourceParser xrp, String name, String defValue) { 788 int resId = xrp.getAttributeResourceValue(null, name, 0); 789 if (resId == 0) { 790 return xrp.getAttributeValue(null, name); 791 } else { 792 return mContext.getResources().getString(resId); 793 } 794 } 795 getFloat(XmlResourceParser xrp, String name, float defValue)796 private float getFloat(XmlResourceParser xrp, String name, float defValue) { 797 int resId = xrp.getAttributeResourceValue(null, name, 0); 798 if (resId == 0) { 799 String s = xrp.getAttributeValue(null, name); 800 if (null == s) return defValue; 801 try { 802 float ret; 803 if (s.endsWith("%p")) { 804 ret = Float.parseFloat(s.substring(0, s.length() - 2)) / 100; 805 } else { 806 ret = Float.parseFloat(s); 807 } 808 return ret; 809 } catch (NumberFormatException e) { 810 return defValue; 811 } 812 } else { 813 return mContext.getResources().getDimension(resId); 814 } 815 } 816 getBoolean(XmlResourceParser xrp, String name, boolean defValue)817 private boolean getBoolean(XmlResourceParser xrp, String name, 818 boolean defValue) { 819 String s = xrp.getAttributeValue(null, name); 820 if (null == s) return defValue; 821 try { 822 boolean ret = Boolean.parseBoolean(s); 823 return ret; 824 } catch (NumberFormatException e) { 825 return defValue; 826 } 827 } 828 getDrawable(XmlResourceParser xrp, String name, Drawable defValue)829 private Drawable getDrawable(XmlResourceParser xrp, String name, 830 Drawable defValue) { 831 int resId = xrp.getAttributeResourceValue(null, name, 0); 832 if (0 == resId) return defValue; 833 return mResources.getDrawable(resId); 834 } 835 } 836