/**
   * Places a single view on the current row, and updates the view's layout parameters to remember
   * its position. mStart, mEnd, and mBottom are updated to reflect the space taken by the view.
   */
  private void placeChild(View child, int gravity) {
    LayoutParams lp = (LayoutParams) child.getLayoutParams();

    int availableWidth = Math.max(0, mEnd - mStart - lp.startMargin - lp.endMargin);
    if (child.getMeasuredWidth() > availableWidth || gravity == Gravity.FILL_HORIZONTAL) {
      measureChildWithFixedWidth(child, availableWidth);
    }

    if (gravity == Gravity.START || gravity == Gravity.FILL_HORIZONTAL) {
      lp.start = mStart + lp.startMargin;
      mStart = lp.start + child.getMeasuredWidth() + lp.endMargin;
    } else { // gravity == Gravity.END
      lp.start = mEnd - lp.endMargin - child.getMeasuredWidth();
      mEnd = lp.start - lp.startMargin;
    }

    lp.top = mTop + lp.topMargin;
    mBottom = Math.max(mBottom, lp.top + child.getMeasuredHeight() + lp.bottomMargin);
  }
  /**
   * Assigns positions to all of the views in the infobar. The icon, text, and close button are
   * placed on the main row. The custom content and finally the buttons are placed on the main row
   * if they fit. Otherwise, they go on their own rows.
   */
  private void placeGroups() {
    startRow();
    placeChild(mCloseButton, Gravity.END);
    placeGroup(mMainGroup);

    int customGroupWidth = 0;
    if (mCustomGroup != null) {
      updateCustomGroupForRow(ROW_MAIN);
      customGroupWidth = getWidthWithMargins(mCustomGroup);
    }

    int buttonGroupWidth = 0;
    if (mButtonGroup != null) {
      updateButtonGroupForRow(ROW_MAIN);
      buttonGroupWidth = getWidthWithMargins(mButtonGroup);
    }

    boolean customGroupOnMainRow = customGroupWidth <= availableWidth();
    boolean buttonGroupOnMainRow = customGroupWidth + buttonGroupWidth <= availableWidth();

    if (mCustomGroup != null) {
      if (customGroupOnMainRow) {
        mCustomGroup.gravity =
            (mButtonGroup != null && buttonGroupOnMainRow) ? Gravity.START : Gravity.END;
      } else {
        startRow();
        updateCustomGroupForRow(ROW_OTHER);
      }
      placeGroup(mCustomGroup);
    }

    if (mButtonGroup != null) {
      if (!buttonGroupOnMainRow) {
        startRow();
        updateButtonGroupForRow(ROW_OTHER);

        // If the infobar consists of just a main row and a buttons row, the buttons must be
        // at least 32dp below the bottom of the message text.
        if (mCustomGroup == null && mMessageTextView != null) {
          LayoutParams lp = (LayoutParams) mMessageTextView.getLayoutParams();
          int messageBottom = lp.top + mMessageTextView.getMeasuredHeight();
          mTop = Math.max(mTop, messageBottom + 2 * mMargin);
        }
      }
      placeGroup(mButtonGroup);

      if (mCustomButton != null && !buttonGroupOnMainRow) {
        // The custom button is start-aligned with the message view (unless that causes it
        // to overlap the primary button).
        LayoutParams primaryButtonLP = (LayoutParams) mPrimaryButton.getLayoutParams();
        LayoutParams customButtonLP = (LayoutParams) mCustomButton.getLayoutParams();
        LayoutParams messageLP = (LayoutParams) mMessageView.getLayoutParams();
        if (customButtonLP.start >= messageLP.start) {
          customButtonLP.start = messageLP.start;
        } else {
          customButtonLP.start = mMargin;
        }
        if (!mButtonGroup.isStacked) {
          // Center the custom button vertically relative to the primary button.
          customButtonLP.top =
              primaryButtonLP.top
                  + (mPrimaryButton.getMeasuredHeight() - mCustomButton.getMeasuredHeight()) / 2;
        }
      }
    }

    startRow();

    // If everything fits on a single row, center everything vertically.
    if (buttonGroupOnMainRow) {
      int layoutHeight = mBottom;
      for (int i = 0; i < getChildCount(); i++) {
        View child = getChildAt(i);
        int extraSpace = layoutHeight - child.getMeasuredHeight();
        LayoutParams lp = (LayoutParams) child.getLayoutParams();
        lp.top = extraSpace / 2;
      }
    }
  }