/**
   * Sets the location of pin according by the supplied value.
   *
   * @param pinValue Float specifying the value of the pin
   */
  public void setSeekPinByValue(float pinValue) {
    if (pinValue > mTickEnd || pinValue < mTickStart) {
      L.e(
          TAG,
          "Pin value "
              + pinValue
              + " is out of bounds. Check that it is greater than the minimum ("
              + mTickStart
              + ") and less than the maximum value ("
              + mTickEnd
              + ")");
      throw new IllegalArgumentException(
          "Pin value "
              + pinValue
              + " is out of bounds. Check that it is greater than the minimum ("
              + mTickStart
              + ") and less than the maximum value ("
              + mTickEnd
              + ")");

    } else {
      if (mFirstSetTickCount) {
        mFirstSetTickCount = false;
      }
      mRightIndex = (int) ((pinValue - mTickStart) / mTickInterval);
      createPins();

      if (mListener != null) {
        mListener.onRangeChangeListener(
            this, mLeftIndex, mRightIndex, getPinValue(mLeftIndex), getPinValue(mRightIndex));
      }
    }
    invalidate();
    requestLayout();
  }
  /**
   * Sets the end tick in the RangeBar.
   *
   * @param tickEnd Integer specifying the number of ticks.
   */
  public void setTickEnd(float tickEnd) {
    int tickCount = (int) ((tickEnd - mTickStart) / mTickInterval) + 1;
    if (isValidTickCount(tickCount)) {
      mTickCount = tickCount;
      mTickEnd = tickEnd;

      // Prevents resetting the indices when creating new activity, but
      // allows it on the first setting.
      if (mFirstSetTickCount) {
        mLeftIndex = 0;
        mRightIndex = mTickCount - 1;

        if (mListener != null) {
          mListener.onRangeChangeListener(
              this, mLeftIndex, mRightIndex, getPinValue(mLeftIndex), getPinValue(mRightIndex));
        }
      }
      if (indexOutOfRange(mLeftIndex, mRightIndex)) {
        mLeftIndex = 0;
        mRightIndex = mTickCount - 1;

        if (mListener != null) {
          mListener.onRangeChangeListener(
              this, mLeftIndex, mRightIndex, getPinValue(mLeftIndex), getPinValue(mRightIndex));
        }
      }

      createBar();
      createPins();
    } else {
      L.e(TAG, "tickCount less than 2; invalid tickCount.");
      throw new IllegalArgumentException("tickCount less than 2; invalid tickCount.");
    }
  }
  /**
   * Sets the location of the pins according by the supplied index. Numbered from 0 to mTickCount -
   * 1 from the left.
   *
   * @param leftPinIndex Integer specifying the index of the left pin
   * @param rightPinIndex Integer specifying the index of the right pin
   */
  public void setRangePinsByIndices(int leftPinIndex, int rightPinIndex) {
    if (indexOutOfRange(leftPinIndex, rightPinIndex)) {
      L.e(
          TAG,
          "Pin index left "
              + leftPinIndex
              + ", or right "
              + rightPinIndex
              + " is out of bounds. Check that it is greater than the minimum ("
              + mTickStart
              + ") and less than the maximum value ("
              + mTickEnd
              + ")");

      throw new IllegalArgumentException(
          "Pin index left "
              + leftPinIndex
              + ", or right "
              + rightPinIndex
              + " is out of bounds. Check that it is greater than the minimum ("
              + mTickStart
              + ") and less than the maximum value ("
              + mTickEnd
              + ")");
    } else {
      if (mFirstSetTickCount) {
        mFirstSetTickCount = false;
      }

      mLeftIndex = leftPinIndex;
      mRightIndex = rightPinIndex;
      createPins();

      if (mListener != null) {
        mListener.onRangeChangeListener(
            this, mLeftIndex, mRightIndex, getPinValue(mLeftIndex), getPinValue(mRightIndex));
      }
    }

    invalidate();
    requestLayout();
  }
  /**
   * Sets the location of pin according by the supplied index. Numbered from 0 to mTickCount - 1
   * from the left.
   *
   * @param pinIndex Integer specifying the index of the seek pin
   */
  public void setSeekPinByIndex(int pinIndex) {
    if (pinIndex < 0 || pinIndex > mTickCount) {
      L.e(
          TAG,
          "Pin index "
              + pinIndex
              + " is out of bounds. Check that it is greater than the minimum ("
              + 0
              + ") and less than the maximum value ("
              + mTickCount
              + ")");
      throw new IllegalArgumentException(
          "Pin index "
              + pinIndex
              + " is out of bounds. Check that it is greater than the minimum ("
              + 0
              + ") and less than the maximum value ("
              + mTickCount
              + ")");

    } else {

      if (mFirstSetTickCount) {
        mFirstSetTickCount = false;
      }
      mRightIndex = pinIndex;
      createPins();

      if (mListener != null) {
        mListener.onRangeChangeListener(
            this, mLeftIndex, mRightIndex, getPinValue(mLeftIndex), getPinValue(mRightIndex));
      }
    }
    invalidate();
    requestLayout();
  }
  /**
   * Does all the functions of the constructor for RangeBar. Called by both RangeBar constructors in
   * lieu of copying the code for each constructor.
   *
   * @param context Context from the constructor.
   * @param attrs AttributeSet from the constructor.
   */
  private void rangeBarInit(
      Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    if (mTickMap == null) {
      mTickMap = new HashMap<>();
    }

    TypedArray ta = context.obtainStyledAttributes(attrs, RangeBar, defStyleAttr, defStyleRes);

    try {
      // Sets the values of the user-defined attributes based on the XML attributes.
      final float tickStart = ta.getFloat(0, DEFAULT_START);
      final float tickEnd = ta.getFloat(10, DEFAULT_END);
      final float tickInterval = ta.getFloat(2, DEFAULT_TICK_INTERVAL);
      int tickCount = (int) ((tickEnd - tickStart) / tickInterval) + 1;

      if (isValidTickCount(tickCount)) {
        // Similar functions performed above in setTickCount; make sure you know how they interact
        mTickCount = tickCount;
        mTickStart = tickStart;
        mTickEnd = tickEnd;
        mTickInterval = tickInterval;
        mLeftIndex = 0;
        mRightIndex = mTickCount - 1;

        if (mListener != null) {
          mListener.onRangeChangeListener(
              this, mLeftIndex, mRightIndex, getPinValue(mLeftIndex), getPinValue(mRightIndex));
        }

      } else {
        L.e(TAG, "tickCount less than 2; invalid tickCount. XML input ignored.");
      }

      mTickHeightDP = ta.getDimension(3, DEFAULT_TICK_HEIGHT_DP);
      mBarWeight = ta.getDimension(5, DEFAULT_BAR_WEIGHT_PX);
      mBarColor = ta.getColor(6, DEFAULT_BAR_COLOR);
      mTextColor = ta.getColor(7, DEFAULT_TEXT_COLOR);
      mPinColor = ta.getColor(8, DEFAULT_PIN_COLOR);
      mActiveBarColor = mBarColor;

      mCircleSize =
          TypedValue.applyDimension(
              TypedValue.COMPLEX_UNIT_DIP,
              ta.getDimension(9, DEFAULT_CIRCLE_SIZE_DP),
              getResources().getDisplayMetrics());

      mCircleColor = ta.getColor(12, DEFAULT_CONNECTING_LINE_COLOR);
      mActiveCircleColor = mCircleColor;

      mTickColor = ta.getColor(4, DEFAULT_TICK_COLOR);
      mActiveTickColor = mTickColor;

      mConnectingLineWeight = ta.getDimension(14, DEFAULT_CONNECTING_LINE_WEIGHT_PX);
      mConnectingLineColor = ta.getColor(15, DEFAULT_CONNECTING_LINE_COLOR);

      mActiveConnectingLineColor = mConnectingLineColor;
      mExpandedPinRadius =
          TypedValue.applyDimension(
              TypedValue.COMPLEX_UNIT_DIP,
              ta.getDimension(16, DEFAULT_EXPANDED_PIN_RADIUS_DP),
              getResources().getDisplayMetrics());

      mPinPadding =
          TypedValue.applyDimension(
              TypedValue.COMPLEX_UNIT_DIP,
              ta.getDimension(8, DEFAULT_PIN_PADDING_DP),
              getResources().getDisplayMetrics());

      mBarPaddingBottom =
          TypedValue.applyDimension(
              TypedValue.COMPLEX_UNIT_DIP,
              ta.getDimension(10, DEFAULT_BAR_PADDING_BOTTOM_DP),
              getResources().getDisplayMetrics());

      mIsRangeBar = ta.getBoolean(13, true);
    } finally {
      ta.recycle();
    }
  }