/**
     * Create a key with the given top-left coordinate and extract its attributes from the XML
     * parser.
     *
     * @param res resources associated with the caller's context
     * @param parent the row that this key belongs to. The row must already be attached to a {@link
     *     Keyboard}.
     * @param x the x coordinate of the top-left
     * @param y the y coordinate of the top-left
     * @param parser the XML parser containing the attributes for this key
     */
    public Key(
        Context askContext,
        Resources res,
        Row parent,
        KeyboardDimens keyboardDimens,
        int x,
        int y,
        XmlResourceParser parser) {
      this(parent, keyboardDimens);
      final Resources askResources = askContext.getResources();
      SparseIntArray attributeIdMap = parent.parent.attributeIdMap;
      this.x = x;
      this.y = y;

      // setting up some defaults
      width = Math.min(keyboardDimens.getKeyMaxWidth(), parent.defaultWidth);
      height =
          KeyboardSupport.getKeyHeightFromHeightCode(
              keyboardDimens,
              parent.defaultHeightCode,
              askResources.getConfiguration().orientation);
      gap = parent.defaultHorizontalGap;
      codes = null;
      iconPreview = null;
      popupCharacters = null;
      popupResId = 0;
      repeatable = false;
      showPreview = true;
      dynamicEmblem = KEY_EMBLEM_NONE;
      modifier = false;
      sticky = false;

      // loading data from XML
      int[] remoteKeyboardLayoutStyleable = parent.parent.remoteKeyboardLayoutStyleable;
      TypedArray a =
          res.obtainAttributes(Xml.asAttributeSet(parser), remoteKeyboardLayoutStyleable);
      int n = a.getIndexCount();
      for (int i = 0; i < n; i++) {
        final int remoteIndex = a.getIndex(i);
        final int localAttrId = attributeIdMap.get(remoteKeyboardLayoutStyleable[remoteIndex]);
        setDataFromTypedArray(parent, keyboardDimens, askResources, a, remoteIndex, localAttrId);
      }
      a.recycle();
      this.x += gap;

      int[] remoteKeyboardKeyLayoutStyleable = parent.parent.remoteKeyboardKeyLayoutStyleable;
      a = res.obtainAttributes(Xml.asAttributeSet(parser), remoteKeyboardKeyLayoutStyleable);
      n = a.getIndexCount();
      for (int i = 0; i < n; i++) {
        final int remoteIndex = a.getIndex(i);
        final int localAttrId = attributeIdMap.get(remoteKeyboardKeyLayoutStyleable[remoteIndex]);
        setDataFromTypedArray(parent, keyboardDimens, askResources, a, remoteIndex, localAttrId);
      }
      externalResourcePopupLayout = popupResId != 0;
      if (codes == null && !TextUtils.isEmpty(label)) {
        codes = new int[] {label.charAt(0)};
      }
      a.recycle();
    }
 /** Create an empty key with no attributes. */
 public Key(Row parent, KeyboardDimens keyboardDimens) {
   row = parent;
   keyboard = parent.parent;
   height =
       KeyboardSupport.getKeyHeightFromHeightCode(
           keyboardDimens,
           parent.defaultHeightCode,
           row.parent.mASKContext.getResources().getConfiguration().orientation);
   width = Math.min(keyboardDimens.getKeyMaxWidth(), parent.defaultWidth);
   gap = parent.defaultHorizontalGap;
   edgeFlags = parent.rowEdgeFlags;
 }
  public static int getKeyHeightFromHeightCode(
      KeyboardDimens keyboardDimens, int heightCode, int orientation) {
    int height;
    switch (heightCode) {
      case 0:
        height = 0;
        break;
      case -2:
        height = keyboardDimens.getSmallKeyHeight();
        break;
      case -3:
        height = keyboardDimens.getLargeKeyHeight();
        break;
      default: // -1
        height = keyboardDimens.getNormalKeyHeight();
        break;
    }
    if (orientation == Configuration.ORIENTATION_LANDSCAPE)
      height = (int) (height * AnyApplication.getConfig().getKeysHeightFactorInLandscape());
    else height = (int) (height * AnyApplication.getConfig().getKeysHeightFactorInPortrait());

    return height;
  }
  public void loadKeyboard(final KeyboardDimens keyboardDimens) {
    mDisplayWidth = keyboardDimens.getKeyboardMaxWidth();
    final float rowVerticalGap = keyboardDimens.getRowVerticalGap();
    final float keyHorizontalGap = keyboardDimens.getKeyHorizontalGap();

    mDefaultHorizontalGap = 0;
    mDefaultWidth = mDisplayWidth / 10;
    mDefaultHeightCode = -1;

    XmlResourceParser parser = mKeyboardContext.getResources().getXml(mLayoutResId);
    boolean inKey = false;
    boolean inRow = false;
    boolean inUnknown = false;
    int row = 0;
    float x = 0;
    float y = rowVerticalGap; // starts with a gap
    int rowHeight = 0;
    Key key = null;
    Row currentRow = null;
    Resources res = mKeyboardContext.getResources();
    boolean skipRow = false;
    int lastVerticalGap = 0;

    try {
      int event;
      while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
        if (event == XmlResourceParser.START_TAG) {
          String tag = parser.getName();
          if (TAG_ROW.equals(tag)) {
            inRow = true;
            x = 0;
            rowHeight = 0;
            currentRow = createRowFromXml(mASKContext, res, parser);
            skipRow = currentRow.mode != 0 && currentRow.mode != mKeyboardMode;
            if (skipRow) {
              skipToEndOfRow(parser);
              inRow = false;
            }
          } else if (TAG_KEY.equals(tag)) {
            inKey = true;
            x += (keyHorizontalGap / 2);
            key =
                createKeyFromXml(
                    mASKContext, res, currentRow, keyboardDimens, (int) x, (int) y, parser);
            rowHeight = Math.max(rowHeight, key.height);
            key.width -= keyHorizontalGap; // the gap is on both
            // sides
            mKeys.add(key);
            if (key.codes[0] == KeyCodes.SHIFT) {
              mShiftKey = key;
              mShiftKeyIndex = mKeys.size() - 1;
              mModifierKeys.add(key);
            } else if (key.codes[0] == KeyCodes.ALT) {
              mModifierKeys.add(key);
            }
          } else if (TAG_KEYBOARD.equals(tag)) {
            parseKeyboardAttributes(mASKContext, res, parser);
          } else {
            inUnknown = true;
            onUnknownTagStart(mKeyboardContext, res, tag, parser);
          }
        } else if (event == XmlResourceParser.END_TAG) {
          if (inKey) {
            inKey = false;
            x += key.gap + key.width;
            x += (keyHorizontalGap / 2);
            if (x > mTotalWidth) {
              mTotalWidth = (int) x;
            }
          } else if (inRow) {
            inRow = false;
            lastVerticalGap = currentRow.verticalGap;
            y += currentRow.verticalGap;
            y += rowHeight;
            y += rowVerticalGap;
            row++;
          } else if (inUnknown) {
            inUnknown = false;
            onUnknownTagEnd();
          }
        }
      }
    } catch (Exception e) {
      Log.e(TAG, "Parse error:" + e);
      e.printStackTrace();
    }
    mTotalHeight = (int) (y - lastVerticalGap);
  }
 private void setDataFromTypedArray(
     Row parent,
     KeyboardDimens keyboardDimens,
     Resources askResources,
     TypedArray a,
     int remoteIndex,
     int localAttrId) {
   try {
     switch (localAttrId) {
       case android.R.attr.keyWidth:
         width =
             getDimensionOrFraction(a, remoteIndex, keyboard.mDisplayWidth, parent.defaultWidth);
         width = Math.min(keyboardDimens.getKeyMaxWidth(), width);
         break;
       case android.R.attr.keyHeight:
         int heightCode = getKeyHeightCode(a, remoteIndex, parent.defaultHeightCode);
         height =
             KeyboardSupport.getKeyHeightFromHeightCode(
                 keyboardDimens, heightCode, askResources.getConfiguration().orientation);
         break;
       case android.R.attr.horizontalGap:
         gap =
             getDimensionOrFraction(
                 a, remoteIndex, keyboard.mDisplayWidth, parent.defaultHorizontalGap);
         break;
       case android.R.attr.codes:
         codes = KeyboardSupport.getKeyCodesFromTypedArray(a, remoteIndex);
         break;
       case android.R.attr.iconPreview:
         iconPreview = a.getDrawable(remoteIndex);
         KeyboardSupport.updateDrawableBounds(iconPreview);
         break;
       case android.R.attr.popupCharacters:
         popupCharacters = a.getText(remoteIndex);
         break;
       case android.R.attr.popupKeyboard:
         popupResId = a.getResourceId(remoteIndex, 0);
         break;
       case android.R.attr.isRepeatable:
         repeatable = a.getBoolean(remoteIndex, false);
         break;
       case R.attr.showPreview:
         showPreview = a.getBoolean(remoteIndex, true);
         break;
       case R.attr.keyDynamicEmblem:
         dynamicEmblem = a.getInt(remoteIndex, KEY_EMBLEM_NONE);
         break;
       case android.R.attr.isModifier:
         modifier = a.getBoolean(remoteIndex, false);
         break;
       case android.R.attr.isSticky:
         sticky = a.getBoolean(remoteIndex, false);
         break;
       case android.R.attr.keyEdgeFlags:
         edgeFlags = a.getInt(remoteIndex, 0);
         edgeFlags |= parent.rowEdgeFlags;
         break;
       case android.R.attr.keyIcon:
         icon = a.getDrawable(remoteIndex);
         KeyboardSupport.updateDrawableBounds(icon);
         break;
       case android.R.attr.keyLabel:
         label = a.getText(remoteIndex);
         break;
       case android.R.attr.keyOutputText:
         text = a.getText(remoteIndex);
         break;
     }
   } catch (Exception e) {
     Log.w(TAG, "Failed to load keyboard layout! ", e);
   }
 }