@@ -140,6 +140,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
140140 private float mCurrentY = 0 ;
141141 private KeyboardRow mCurrentRow = null ;
142142 private Key mPreviousKeyInRow = null ;
143+ private boolean mKeyboardDefined = false ;
143144
144145 public KeyboardBuilder (final Context context , final KP params ) {
145146 mContext = context ;
@@ -160,7 +161,10 @@ public KeyboardBuilder<KP> load(final int xmlId, final KeyboardId id) {
160161 mParams .mId = id ;
161162 final XmlResourceParser parser = mResources .getXml (xmlId );
162163 try {
163- parseKeyboard (parser );
164+ parseKeyboard (parser , false );
165+ if (!mKeyboardDefined ) {
166+ throw new XmlParseUtils .ParseException ("No " + TAG_KEYBOARD + " tag was found" );
167+ }
164168 } catch (XmlPullParserException e ) {
165169 Log .w (BUILDER_TAG , "keyboard XML parse error" , e );
166170 throw new IllegalArgumentException (e .getMessage (), e );
@@ -197,20 +201,37 @@ private void startEndTag(final String format, final Object ... args) {
197201 mIndent --;
198202 }
199203
200- private void parseKeyboard (final XmlPullParser parser )
204+ private void parseKeyboard (final XmlPullParser parser , final boolean skip )
201205 throws XmlPullParserException , IOException {
202- if (DEBUG ) startTag ("<%s> %s" , TAG_KEYBOARD , mParams .mId );
203206 while (parser .getEventType () != XmlPullParser .END_DOCUMENT ) {
204207 final int event = parser .next ();
205208 if (event == XmlPullParser .START_TAG ) {
206209 final String tag = parser .getName ();
207210 if (TAG_KEYBOARD .equals (tag )) {
208- parseKeyboardAttributes (parser );
209- startKeyboard ();
210- parseKeyboardContent (parser , false );
211+ if (DEBUG ) startTag ("<%s> %s%s" , TAG_KEYBOARD , mParams .mId ,
212+ skip ? " skipped" : "" );
213+ if (!skip ) {
214+ if (mKeyboardDefined ) {
215+ throw new XmlParseUtils .ParseException ("Only one " + TAG_KEYBOARD
216+ + " tag can be defined" , parser );
217+ }
218+ mKeyboardDefined = true ;
219+ parseKeyboardAttributes (parser );
220+ startKeyboard ();
221+ }
222+ parseKeyboardContent (parser , skip );
223+ } else if (TAG_SWITCH .equals (tag )) {
224+ parseSwitchKeyboard (parser , skip );
225+ } else {
226+ throw new XmlParseUtils .IllegalStartTag (parser , tag , TAG_KEYBOARD );
227+ }
228+ } else if (event == XmlPullParser .END_TAG ) {
229+ final String tag = parser .getName ();
230+ if (DEBUG ) endTag ("</%s>" , tag );
231+ if (TAG_CASE .equals (tag ) || TAG_DEFAULT .equals (tag )) {
211232 return ;
212233 }
213- throw new XmlParseUtils .IllegalStartTag (parser , tag , TAG_KEYBOARD );
234+ throw new XmlParseUtils .IllegalEndTag (parser , tag , TAG_ROW );
214235 }
215236 }
216237 }
@@ -224,7 +245,11 @@ private void parseKeyboardAttributes(final XmlPullParser parser) {
224245 final KeyboardParams params = mParams ;
225246 final int height = params .mId .mHeight ;
226247 final int width = params .mId .mWidth ;
227- params .mOccupiedHeight = height ;
248+ // The bonus height isn't used to determine the other dimensions (gap/padding) to allow
249+ // those to stay consistent between layouts with and without the bonus height added.
250+ final int bonusHeight = mParams .mId .mShowNumberRow ? Math .round (mResources .getFraction (
251+ R .fraction .config_key_bonus_height_5row , height , height )) : 0 ;
252+ params .mOccupiedHeight = height + bonusHeight ;
228253 params .mOccupiedWidth = width ;
229254 params .mTopPadding = ResourceUtils .getDimensionOrFraction (keyboardAttr ,
230255 R .styleable .Keyboard_keyboardTopPadding , height , 0 );
@@ -261,7 +286,6 @@ private void parseKeyboardAttributes(final XmlPullParser parser) {
261286 params .mMaxMoreKeysKeyboardColumn = keyAttr .getInt (
262287 R .styleable .Keyboard_Key_maxMoreKeysColumn , 5 );
263288
264- params .mThemeId = keyboardAttr .getInt (R .styleable .Keyboard_themeId , 0 );
265289 params .mIconsSet .loadIcons (keyboardAttr );
266290 params .mTextsSet .setLocale (params .mId .getLocale (), mContext );
267291 } finally {
@@ -484,28 +508,33 @@ private void parseMerge(final XmlPullParser parser, final KeyboardRow row, final
484508 }
485509 }
486510
511+ private void parseSwitchKeyboard (final XmlPullParser parser , final boolean skip )
512+ throws XmlPullParserException , IOException {
513+ parseSwitchInternal (parser , true , null , skip );
514+ }
515+
487516 private void parseSwitchKeyboardContent (final XmlPullParser parser , final boolean skip )
488517 throws XmlPullParserException , IOException {
489- parseSwitchInternal (parser , null , skip );
518+ parseSwitchInternal (parser , false , null , skip );
490519 }
491520
492521 private void parseSwitchRowContent (final XmlPullParser parser , final KeyboardRow row ,
493522 final boolean skip ) throws XmlPullParserException , IOException {
494- parseSwitchInternal (parser , row , skip );
523+ parseSwitchInternal (parser , false , row , skip );
495524 }
496525
497- private void parseSwitchInternal (final XmlPullParser parser , final KeyboardRow row ,
498- final boolean skip ) throws XmlPullParserException , IOException {
526+ private void parseSwitchInternal (final XmlPullParser parser , final boolean parseKeyboard ,
527+ final KeyboardRow row , final boolean skip ) throws XmlPullParserException , IOException {
499528 if (DEBUG ) startTag ("<%s> %s" , TAG_SWITCH , mParams .mId );
500529 boolean selected = false ;
501530 while (parser .getEventType () != XmlPullParser .END_DOCUMENT ) {
502531 final int event = parser .next ();
503532 if (event == XmlPullParser .START_TAG ) {
504533 final String tag = parser .getName ();
505534 if (TAG_CASE .equals (tag )) {
506- selected |= parseCase (parser , row , selected || skip );
535+ selected |= parseCase (parser , parseKeyboard , row , selected || skip );
507536 } else if (TAG_DEFAULT .equals (tag )) {
508- selected |= parseDefault (parser , row , selected || skip );
537+ selected |= parseDefault (parser , parseKeyboard , row , selected || skip );
509538 } else {
510539 throw new XmlParseUtils .IllegalStartTag (parser , tag , TAG_SWITCH );
511540 }
@@ -520,10 +549,13 @@ private void parseSwitchInternal(final XmlPullParser parser, final KeyboardRow r
520549 }
521550 }
522551
523- private boolean parseCase (final XmlPullParser parser , final KeyboardRow row , final boolean skip )
524- throws XmlPullParserException , IOException {
552+ private boolean parseCase (final XmlPullParser parser , final boolean parseKeyboard ,
553+ final KeyboardRow row , final boolean skip ) throws XmlPullParserException , IOException {
525554 final boolean selected = parseCaseCondition (parser );
526- if (row == null ) {
555+ if (parseKeyboard ) {
556+ // Processing Keyboard root.
557+ parseKeyboard (parser , !selected || skip );
558+ } else if (row == null ) {
527559 // Processing Rows.
528560 parseKeyboardContent (parser , !selected || skip );
529561 } else {
@@ -540,6 +572,7 @@ private boolean parseCaseCondition(final XmlPullParser parser) {
540572 }
541573 final AttributeSet attr = Xml .asAttributeSet (parser );
542574 final TypedArray caseAttr = mResources .obtainAttributes (attr , R .styleable .Keyboard_Case );
575+ if (DEBUG ) startTag ("<%s>" , TAG_CASE );
543576 try {
544577 final boolean keyboardLayoutSetMatched = matchString (caseAttr ,
545578 R .styleable .Keyboard_Case_keyboardLayoutSet ,
@@ -548,8 +581,8 @@ private boolean parseCaseCondition(final XmlPullParser parser) {
548581 R .styleable .Keyboard_Case_keyboardLayoutSetElement , id .mElementId ,
549582 KeyboardId .elementIdToName (id .mElementId ));
550583 final boolean keyboardThemeMatched = matchTypedValue (caseAttr ,
551- R .styleable .Keyboard_Case_keyboardTheme , mParams .mThemeId ,
552- KeyboardTheme .getKeyboardThemeName (mParams .mThemeId ));
584+ R .styleable .Keyboard_Case_keyboardTheme , id .mThemeId ,
585+ KeyboardTheme .getKeyboardThemeName (id .mThemeId ));
553586 final boolean modeMatched = matchTypedValue (caseAttr ,
554587 R .styleable .Keyboard_Case_mode , id .mMode , KeyboardId .modeName (id .mMode ));
555588 final boolean navigateNextMatched = matchBoolean (caseAttr ,
@@ -647,10 +680,12 @@ private static boolean isIconDefined(final TypedArray a, final int index,
647680 return iconsSet .getIconDrawable (iconId ) != null ;
648681 }
649682
650- private boolean parseDefault (final XmlPullParser parser , final KeyboardRow row ,
651- final boolean skip ) throws XmlPullParserException , IOException {
683+ private boolean parseDefault (final XmlPullParser parser , final boolean parseKeyboard ,
684+ final KeyboardRow row , final boolean skip ) throws XmlPullParserException , IOException {
652685 if (DEBUG ) startTag ("<%s>" , TAG_DEFAULT );
653- if (row == null ) {
686+ if (parseKeyboard ) {
687+ parseKeyboard (parser , skip );
688+ } else if (row == null ) {
654689 parseKeyboardContent (parser , skip );
655690 } else {
656691 parseRowContent (parser , row , skip );
0 commit comments