private void invalidateMathCache() {
   mRootConstraints.invalidate();
   for (int i = 0; i < getChildCount(); i++) {
     final ViewConstraints viewConstraints = mViewConstraints[i];
     viewConstraints.invalidate();
   }
 }
  private void updateChildrenSize(final int widthMeasureSpec, final int heightMeasureSpec) {
    for (int i = 0; i < getChildCount(); i++) {
      final ViewConstraints viewConstraints = mViewConstraints[i];
      final View v = viewConstraints.getView();
      final LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
      final int mL = layoutParams.leftMargin,
          mR = layoutParams.rightMargin,
          mT = layoutParams.topMargin,
          mB = layoutParams.bottomMargin;
      measureChildWithMargins(v, widthMeasureSpec, 0, heightMeasureSpec, 0);

      if (!viewConstraints.isHorizontalSpring()) {
        Value childWidth;
        if (v.getVisibility() == View.GONE) {
          childWidth = mLayoutMath.variable(0);
        } else if (layoutParams.relativeWidth > 0) {
          childWidth =
              mRootConstraints
                  .innerRight
                  .subtract(mRootConstraints.innerLeft)
                  .multiply(mLayoutMath.variable(layoutParams.relativeWidth))
                  .divide(mLayoutMath.variable(RELATIVE_SIZE_DENOMINATOR));
        } else {
          childWidth = mLayoutMath.variable(v.getMeasuredWidth());
        }

        viewConstraints.leftMargin.setValue(mL);
        viewConstraints.rightMargin.setValue(mR);

        Value outerWidth = childWidth.add(mLayoutMath.variable(mL + mR)).retain();
        viewConstraints.setWidth(outerWidth);
        outerWidth.release();
      }

      if (!viewConstraints.isVerticalSpring()) {
        Value childHeight;
        if (v.getVisibility() == View.GONE) {
          childHeight = mLayoutMath.variable(0);
        } else if (layoutParams.relativeHeight > 0) {
          childHeight =
              mRootConstraints
                  .innerBottom
                  .subtract(mRootConstraints.innerTop)
                  .multiply(mLayoutMath.variable(layoutParams.relativeHeight))
                  .divide(mLayoutMath.variable(RELATIVE_SIZE_DENOMINATOR));
        } else {
          childHeight = mLayoutMath.variable(v.getMeasuredHeight());
        }

        viewConstraints.topMargin.setValue(mT);
        viewConstraints.bottomMargin.setValue(mB);

        Value outerHeight = childHeight.add(mLayoutMath.variable(mT + mB)).retain();
        viewConstraints.setHeight(outerHeight);
        outerHeight.release();
      }
    }
  }
 private void cacheLayoutPositions() {
   for (int i = 0; i < getChildCount(); i++) {
     final ViewConstraints viewConstraints = mViewConstraints[i];
     final View v = viewConstraints.getView();
     if (viewConstraints.isHorizontalSpring() && !viewConstraints.isHorizontalSpringUsed()) {
       throw new IllegalStateException(
           "Horizontal weight defined but never used, please review your layout. Remember that the chain of views cannot divert when using springs: Problematic view (please also check other dependant views): "
               + v
               + ", problematic layout: "
               + this);
     } else if (viewConstraints.isVerticalSpring() && !viewConstraints.isVerticalSpringUsed()) {
       throw new IllegalStateException(
           "Vertical weight defined but never used, please review your layout. Remember that the chain of views cannot divert when using springs: Problematic view (please also check other dependant views): "
               + v
               + ", problematic layout: "
               + this);
     } else {
       int anchor = 0;
       try {
         LayoutParams st = (LayoutParams) v.getLayoutParams();
         anchor = LEFT;
         st.left = viewConstraints.innerLeft.getValue();
         anchor = RIGHT;
         st.right = viewConstraints.innerRight.getValue();
         anchor = TOP;
         st.top = viewConstraints.innerTop.getValue();
         anchor = BOTTOM;
         st.bottom = viewConstraints.innerBottom.getValue();
         v.measure(
             MeasureSpec.makeMeasureSpec(st.right - st.left, MeasureSpec.EXACTLY),
             MeasureSpec.makeMeasureSpec(st.bottom - st.top, MeasureSpec.EXACTLY));
       } catch (IllegalStateException e) {
         throw new IllegalStateException(
             "View "
                 + ANCHOR_NAMES[anchor]
                 + " position could not be calculated, please review your layout. Remember that A.above = B and B.below = A are not equivalent in terms of calculation order, please refer to documentation. Problematic view (please also check other dependant views): "
                 + v
                 + ", problematic layout: "
                 + this,
             e);
       } catch (StackOverflowError e) {
         throw new IllegalStateException(
             "Constraints of a view could not be resolved (circular dependency), please review your layout. Problematic view (please also check other dependant views): "
                 + v
                 + ", problematic layout: "
                 + this);
       }
     }
   }
 }
  private void handleSprings(
      final Stack<ViewConstraints> springMetrics,
      final boolean isWrapContentWidth,
      final boolean isWrapContentHeight) {
    if (!springMetrics.isEmpty()) {
      mHorizontalChains.clear();
      mVerticalChains.clear();
      while (!springMetrics.isEmpty()) {
        final ViewConstraints spring = springMetrics.pop();
        final ViewConstraints chainHeadX = getChainHorizontalHead(spring);
        final ViewConstraints chainHeadY = getChainVerticalHead(spring);
        if (chainHeadX != null) {
          if (isWrapContentWidth && mMinWidth <= 0) {
            throw new IllegalStateException(
                "Horizontal springs not supported when layout width is wrap_content");
          }
          mHorizontalChains.add(chainHeadX);
        }
        if (chainHeadY != null) {
          if (isWrapContentHeight && mMinHeight <= 0) {
            throw new IllegalStateException(
                "Vertical springs not supported when layout height is wrap_content and minHeight is not defined");
          }
          mVerticalChains.add(chainHeadY);
        }
      }

      for (int i = 0; i < mHorizontalChains.size(); i++) {
        final ViewConstraints chainHead = mHorizontalChains.get(i);
        int totalWeight = 0;
        Value contentWidth = mLayoutMath.variable(0);
        final ValueWrapper totalWeightWrapper = mLayoutMath.wrap();
        final ValueWrapper chainWidthWrapper = mLayoutMath.wrap();
        ViewConstraints chainElem = chainHead, prevElem = null;
        Value start = chainElem.left, end;
        while (chainElem != null) {
          if (chainElem.isHorizontalSpring()) {
            chainElem.markHorizontalSpringUsed();
            final int weight = ((LayoutParams) chainElem.getView().getLayoutParams()).widthWeight;
            totalWeight += weight;
            final Value width =
                chainWidthWrapper
                    .multiply(mLayoutMath.variable(weight))
                    .divide(totalWeightWrapper)
                    .max(mLayoutMath.variable(0))
                    .retain();
            chainElem.setWidth(width);
            width.release();
          } else {
            contentWidth = contentWidth.add(chainElem.getWidth());
          }
          prevElem = chainElem;
          chainElem = chainElem.nextX;
        }
        end = prevElem.right;
        totalWeightWrapper.setValueObject(mLayoutMath.variable(totalWeight));
        chainWidthWrapper.setValueObject(end.subtract(start).subtract(contentWidth));
      }

      for (int i = 0; i < mVerticalChains.size(); i++) {
        final ViewConstraints chainHead = mVerticalChains.get(i);
        int totalWeight = 0;
        Value contentHeight = mLayoutMath.variable(0);
        final ValueWrapper totalWeightWrapper = mLayoutMath.wrap();
        final ValueWrapper chainWidthWrapper = mLayoutMath.wrap();
        ViewConstraints chainElem = chainHead, prevElem = null;
        Value start = chainElem.top, end;
        while (chainElem != null) {
          if (chainElem.isVerticalSpring()) {
            chainElem.markVerticalSpringUsed();
            final int weight = ((LayoutParams) chainElem.getView().getLayoutParams()).heightWeight;
            totalWeight += weight;
            final Value height =
                chainWidthWrapper
                    .multiply(mLayoutMath.variable(weight))
                    .divide(totalWeightWrapper)
                    .max(mLayoutMath.variable(0))
                    .retain();
            chainElem.setHeight(height);
            height.release();
          } else {
            contentHeight = contentHeight.add(chainElem.getHeight());
          }
          prevElem = chainElem;
          chainElem = chainElem.nextY;
        }
        end = prevElem.bottom;
        totalWeightWrapper.setValueObject(mLayoutMath.variable(totalWeight));
        chainWidthWrapper.setValueObject(end.subtract(start).subtract(contentHeight));
      }
    }
  }
  private void createViewMetrics(Stack<ViewConstraints> springMetrics) {
    springMetrics.clear();
    mIdToViewConstraints.clear();

    if (mRootConstraints != null) {
      mRootConstraints.release();
      for (ViewConstraints mViewConstraint : mViewConstraints) {
        mViewConstraint.release();
      }

      mRootConstraints.reset(this);
      resizeViewConstraintsArray(getChildCount());
    } else {
      mRootConstraints = new ViewConstraints(this, mLayoutMath);
      mViewConstraints = new ViewConstraints[getChildCount()];
    }

    mRootConstraints.left.setValueObject(mLayoutMath.variable(0));
    mRootConstraints.top.setValueObject(mLayoutMath.variable(0));

    final int count = getChildCount();

    for (int i = 0; i < count; i++) {
      final View v = getChildAt(i);
      mIdToViewConstraints.append(v.getId(), i);
      if (mViewConstraints[i] == null) {
        mViewConstraints[i] = new ViewConstraints(v, mLayoutMath);
      } else {
        mViewConstraints[i].reset(v);
      }
    }

    for (int i = 0; i < count; i++) {
      final ViewConstraints viewConstraints = mViewConstraints[i];
      final LayoutParams layoutParams = (LayoutParams) viewConstraints.getView().getLayoutParams();

      if (layoutParams.getWidthWeight() > 0) {
        viewConstraints.markAsHorizontalSpring();
      }

      if (layoutParams.getHeightWeight() > 0) {
        viewConstraints.markAsVerticalSpring();
      }

      int[] childRules = layoutParams.getRelations();
      for (int relation : VALID_RELATIONS) {
        final ViewConstraints metrics = getViewMetrics(childRules[relation]);
        if (metrics != null) {
          metrics.updateRelation(viewConstraints, relation);
        }
      }
      if (viewConstraints.isHorizontalSpring() || viewConstraints.isVerticalSpring()) {
        springMetrics.add(viewConstraints);
      }
    }
  }