private boolean parseCaseCondition(final XmlPullParser parser) {
    final KeyboardId id = mParams.mId;
    if (id == null) {
      return true;
    }
    final AttributeSet attr = Xml.asAttributeSet(parser);
    final TypedArray caseAttr = mResources.obtainAttributes(attr, R.styleable.Keyboard_Case);
    try {
      final boolean keyboardLayoutSetMatched =
          matchString(
              caseAttr,
              R.styleable.Keyboard_Case_keyboardLayoutSet,
              SubtypeLocaleUtils.getKeyboardLayoutSetName(id.mSubtype));
      final boolean keyboardLayoutSetElementMatched =
          matchTypedValue(
              caseAttr,
              R.styleable.Keyboard_Case_keyboardLayoutSetElement,
              id.mElementId,
              KeyboardId.elementIdToName(id.mElementId));
      final boolean modeMatched =
          matchTypedValue(
              caseAttr, R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode));
      final boolean navigateNextMatched =
          matchBoolean(caseAttr, R.styleable.Keyboard_Case_navigateNext, id.navigateNext());
      final boolean navigatePreviousMatched =
          matchBoolean(caseAttr, R.styleable.Keyboard_Case_navigatePrevious, id.navigatePrevious());
      final boolean passwordInputMatched =
          matchBoolean(caseAttr, R.styleable.Keyboard_Case_passwordInput, id.passwordInput());
      final boolean clobberSettingsKeyMatched =
          matchBoolean(
              caseAttr, R.styleable.Keyboard_Case_clobberSettingsKey, id.mClobberSettingsKey);
      final boolean shortcutKeyEnabledMatched =
          matchBoolean(
              caseAttr, R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled);
      final boolean shortcutKeyOnSymbolsMatched =
          matchBoolean(
              caseAttr, R.styleable.Keyboard_Case_shortcutKeyOnSymbols, id.mShortcutKeyOnSymbols);
      final boolean hasShortcutKeyMatched =
          matchBoolean(caseAttr, R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey);
      final boolean languageSwitchKeyEnabledMatched =
          matchBoolean(
              caseAttr,
              R.styleable.Keyboard_Case_languageSwitchKeyEnabled,
              id.mLanguageSwitchKeyEnabled);
      final boolean isMultiLineMatched =
          matchBoolean(caseAttr, R.styleable.Keyboard_Case_isMultiLine, id.isMultiLine());
      final boolean imeActionMatched =
          matchInteger(caseAttr, R.styleable.Keyboard_Case_imeAction, id.imeAction());
      final boolean localeCodeMatched =
          matchString(caseAttr, R.styleable.Keyboard_Case_localeCode, id.mLocale.toString());
      final boolean languageCodeMatched =
          matchString(caseAttr, R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage());
      final boolean countryCodeMatched =
          matchString(caseAttr, R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry());
      final boolean selected =
          keyboardLayoutSetMatched
              && keyboardLayoutSetElementMatched
              && modeMatched
              && navigateNextMatched
              && navigatePreviousMatched
              && passwordInputMatched
              && clobberSettingsKeyMatched
              && shortcutKeyEnabledMatched
              && shortcutKeyOnSymbolsMatched
              && hasShortcutKeyMatched
              && languageSwitchKeyEnabledMatched
              && isMultiLineMatched
              && imeActionMatched
              && localeCodeMatched
              && languageCodeMatched
              && countryCodeMatched;

      if (DEBUG) {
        startTag(
            "<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s",
            TAG_CASE,
            textAttr(
                caseAttr.getString(R.styleable.Keyboard_Case_keyboardLayoutSet),
                "keyboardLayoutSet"),
            textAttr(
                caseAttr.getString(R.styleable.Keyboard_Case_keyboardLayoutSetElement),
                "keyboardLayoutSetElement"),
            textAttr(caseAttr.getString(R.styleable.Keyboard_Case_mode), "mode"),
            textAttr(caseAttr.getString(R.styleable.Keyboard_Case_imeAction), "imeAction"),
            booleanAttr(caseAttr, R.styleable.Keyboard_Case_navigateNext, "navigateNext"),
            booleanAttr(caseAttr, R.styleable.Keyboard_Case_navigatePrevious, "navigatePrevious"),
            booleanAttr(
                caseAttr, R.styleable.Keyboard_Case_clobberSettingsKey, "clobberSettingsKey"),
            booleanAttr(caseAttr, R.styleable.Keyboard_Case_passwordInput, "passwordInput"),
            booleanAttr(
                caseAttr, R.styleable.Keyboard_Case_shortcutKeyEnabled, "shortcutKeyEnabled"),
            booleanAttr(
                caseAttr, R.styleable.Keyboard_Case_shortcutKeyOnSymbols, "shortcutKeyOnSymbols"),
            booleanAttr(caseAttr, R.styleable.Keyboard_Case_hasShortcutKey, "hasShortcutKey"),
            booleanAttr(
                caseAttr,
                R.styleable.Keyboard_Case_languageSwitchKeyEnabled,
                "languageSwitchKeyEnabled"),
            booleanAttr(caseAttr, R.styleable.Keyboard_Case_isMultiLine, "isMultiLine"),
            textAttr(caseAttr.getString(R.styleable.Keyboard_Case_localeCode), "localeCode"),
            textAttr(caseAttr.getString(R.styleable.Keyboard_Case_languageCode), "languageCode"),
            textAttr(caseAttr.getString(R.styleable.Keyboard_Case_countryCode), "countryCode"),
            selected ? "" : " skipped");
      }

      return selected;
    } finally {
      caseAttr.recycle();
    }
  }
  private void parseKeyboardAttributes(final XmlPullParser parser) {
    final AttributeSet attr = Xml.asAttributeSet(parser);
    final TypedArray keyboardAttr =
        mContext.obtainStyledAttributes(
            attr, R.styleable.Keyboard, R.attr.keyboardStyle, R.style.Keyboard);
    final TypedArray keyAttr = mResources.obtainAttributes(attr, R.styleable.Keyboard_Key);
    try {
      final KeyboardParams params = mParams;
      final int height = params.mId.mHeight;
      final int width = params.mId.mWidth;
      params.mOccupiedHeight = height;
      params.mOccupiedWidth = width;
      params.mTopPadding =
          (int)
              keyboardAttr.getFraction(R.styleable.Keyboard_keyboardTopPadding, height, height, 0);
      params.mBottomPadding =
          (int)
              keyboardAttr.getFraction(
                  R.styleable.Keyboard_keyboardBottomPadding, height, height, 0);
      params.mLeftPadding =
          (int) keyboardAttr.getFraction(R.styleable.Keyboard_keyboardLeftPadding, width, width, 0);
      params.mRightPadding =
          (int)
              keyboardAttr.getFraction(R.styleable.Keyboard_keyboardRightPadding, width, width, 0);

      final int baseWidth = params.mOccupiedWidth - params.mLeftPadding - params.mRightPadding;
      params.mBaseWidth = baseWidth;
      params.mDefaultKeyWidth =
          (int)
              keyAttr.getFraction(
                  R.styleable.Keyboard_Key_keyWidth,
                  baseWidth,
                  baseWidth,
                  baseWidth / DEFAULT_KEYBOARD_COLUMNS);
      params.mHorizontalGap =
          (int)
              keyboardAttr.getFraction(R.styleable.Keyboard_horizontalGap, baseWidth, baseWidth, 0);
      // TODO: Fix keyboard geometry calculation clearer. Historically vertical gap between
      // rows are determined based on the entire keyboard height including top and bottom
      // paddings.
      params.mVerticalGap =
          (int) keyboardAttr.getFraction(R.styleable.Keyboard_verticalGap, height, height, 0);
      final int baseHeight =
          params.mOccupiedHeight - params.mTopPadding - params.mBottomPadding + params.mVerticalGap;
      params.mBaseHeight = baseHeight;
      params.mDefaultRowHeight =
          (int)
              ResourceUtils.getDimensionOrFraction(
                  keyboardAttr,
                  R.styleable.Keyboard_rowHeight,
                  baseHeight,
                  baseHeight / DEFAULT_KEYBOARD_ROWS);

      params.mKeyVisualAttributes = KeyVisualAttributes.newInstance(keyAttr);

      params.mMoreKeysTemplate =
          keyboardAttr.getResourceId(R.styleable.Keyboard_moreKeysTemplate, 0);
      params.mMaxMoreKeysKeyboardColumn =
          keyAttr.getInt(R.styleable.Keyboard_Key_maxMoreKeysColumn, 5);

      params.mThemeId = keyboardAttr.getInt(R.styleable.Keyboard_themeId, 0);
      params.mIconsSet.loadIcons(keyboardAttr);
      final String language = params.mId.mLocale.getLanguage();
      params.mCodesSet.setLanguage(language);
      params.mTextsSet.setLanguage(language);
      final RunInLocale<Void> job =
          new RunInLocale<Void>() {
            @Override
            protected Void job(final Resources res) {
              params.mTextsSet.loadStringResources(mContext);
              return null;
            }
          };
      // Null means the current system locale.
      final Locale locale =
          SubtypeLocaleUtils.isNoLanguage(params.mId.mSubtype) ? null : params.mId.mLocale;
      job.runInLocale(mResources, locale);

      final int resourceId =
          keyboardAttr.getResourceId(R.styleable.Keyboard_touchPositionCorrectionData, 0);
      if (resourceId != 0) {
        final String[] data = mResources.getStringArray(resourceId);
        params.mTouchPositionCorrection.load(data);
      }
    } finally {
      keyAttr.recycle();
      keyboardAttr.recycle();
    }
  }