/** Draws the widget on the given canvas. */
  @Override
  protected synchronized void onDraw(@NonNull Canvas canvas) {
    super.onDraw(canvas);

    paint.setTextSize(mTextSize);
    paint.setStyle(Style.FILL);
    paint.setColor(mDefaultColor);
    paint.setAntiAlias(true);
    float minMaxLabelSize = 0;

    if (mShowLabels) {
      // draw min and max labels
      String minLabel = getContext().getString(R.string.demo_min_label);
      String maxLabel = getContext().getString(R.string.demo_max_label);
      minMaxLabelSize = Math.max(paint.measureText(minLabel), paint.measureText(maxLabel));
      float minMaxHeight = mTextOffset + mThumbHalfHeight + mTextSize / 3;
      canvas.drawText(minLabel, 0, minMaxHeight, paint);
      canvas.drawText(maxLabel, getWidth() - minMaxLabelSize, minMaxHeight, paint);
    }
    padding = mInternalPad + minMaxLabelSize + mThumbHalfWidth;

    // draw seek bar background line
    mRect.left = padding;
    mRect.right = getWidth() - padding;
    canvas.drawRect(mRect, paint);

    boolean selectedValuesAreDefault =
        (getSelectedMinValue().equals(getAbsoluteMinValue())
            && getSelectedMaxValue().equals(getAbsoluteMaxValue()));

    int colorToUseForButtonsAndHighlightedLine =
        !mAlwaysActive && selectedValuesAreDefault
            ? mDefaultColor
            : // default values
            mActiveColor; // non default, filter is active

    // draw seek bar active range line
    mRect.left = normalizedToScreen(normalizedMinValue);
    mRect.right = normalizedToScreen(normalizedMaxValue);

    paint.setColor(colorToUseForButtonsAndHighlightedLine);
    canvas.drawRect(mRect, paint);

    // draw minimum thumb if not a single thumb control
    if (!mSingleThumb) {
      drawThumb(canvas, selectedValuesAreDefault, true);
    }

    // draw maximum thumb
    drawThumb(canvas, selectedValuesAreDefault, false);

    // draw the text if sliders have moved from default edges
    if (mShowTextAboveThumbs && !selectedValuesAreDefault) {
      paint.setTextSize(mTextSize);
      paint.setColor(mTextAboveThumbsColor);
      // give text a bit more space here so it doesn't get cut off
      int offset = PixelUtil.dpToPx(getContext(), TEXT_LATERAL_PADDING_IN_DP);

      String minText = String.valueOf(getSelectedMinValue());
      String maxText = String.valueOf(getSelectedMaxValue());
      float minTextWidth = paint.measureText(minText) + offset;
      float maxTextWidth = paint.measureText(maxText) + offset;

      if (!mSingleThumb) {
        canvas.drawText(
            minText,
            normalizedToScreen(normalizedMinValue)
                - minTextWidth * 0.5f
                + PixelUtil.dpToPx(getContext(), 1),
            mDistanceToTop + mTextSize + mMinTextPadding,
            paint);
      }

      canvas.drawText(
          maxText,
          normalizedToScreen(normalizedMaxValue)
              - maxTextWidth * 0.5f
              + PixelUtil.dpToPx(getContext(), 1),
          mDistanceToTop + mTextSize + mMaxTextPadding,
          paint);
    }
  }
  private void init(Context context, AttributeSet attrs) {
    float barHeight;
    int thumbNormal = R.drawable.seek_thumb_normal;
    int thumbPressed = R.drawable.seek_thumb_pressed;
    int thumbDisabled = R.drawable.seek_thumb_disabled;
    int maxThumbNormal = thumbNormal;
    int maxThumbPressed = thumbPressed;

    if (attrs == null) {
      setRangeToDefaultValues();
      mInternalPad = PixelUtil.dpToPx(context, INITIAL_PADDING_IN_DP);
      barHeight = PixelUtil.dpToPx(context, LINE_HEIGHT_IN_DP);
      mActiveColor = ACTIVE_COLOR;
      mDefaultColor = Color.GRAY;
      mTextAboveThumbsColor = Color.WHITE;
      mAlwaysActive = false;
      mShowTextAboveThumbs = true;
    } else {
      TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.RangeSeekBar, 0, 0);
      try {
        setRangeValues(
            extractNumericValueFromAttributes(
                a, R.styleable.RangeSeekBar_absoluteMinValue, DEFAULT_MINIMUM),
            extractNumericValueFromAttributes(
                a, R.styleable.RangeSeekBar_absoluteMaxValue, DEFAULT_MAXIMUM));
        mShowTextAboveThumbs = a.getBoolean(R.styleable.RangeSeekBar_valuesAboveThumbs, true);
        mSingleThumb = a.getBoolean(R.styleable.RangeSeekBar_singleThumb, false);
        mShowLabels = a.getBoolean(R.styleable.RangeSeekBar_showLabels, true);
        mInternalPad =
            a.getDimensionPixelSize(
                R.styleable.RangeSeekBar_internalPadding, INITIAL_PADDING_IN_DP);
        barHeight = a.getDimensionPixelSize(R.styleable.RangeSeekBar_barHeight, LINE_HEIGHT_IN_DP);
        mActiveColor = a.getColor(R.styleable.RangeSeekBar_activeColor, ACTIVE_COLOR);
        mDefaultColor = a.getColor(R.styleable.RangeSeekBar_defaultColor, Color.GRAY);
        mTextAboveThumbsColor =
            a.getColor(R.styleable.RangeSeekBar_textAboveThumbsColor, Color.WHITE);
        mAlwaysActive = a.getBoolean(R.styleable.RangeSeekBar_alwaysActive, false);
        mMinThumbOffset = a.getDimensionPixelSize(R.styleable.RangeSeekBar_minThumbOffset, 0);
        mMaxThumbOffset = a.getDimensionPixelSize(R.styleable.RangeSeekBar_maxThumbOffset, 0);
        mMaxTextPadding = a.getDimensionPixelSize(R.styleable.RangeSeekBar_maxTextPadding, 0);
        mMinTextPadding = a.getDimensionPixelSize(R.styleable.RangeSeekBar_minTextPadding, 0);

        Drawable normalDrawable = a.getDrawable(R.styleable.RangeSeekBar_thumbNormal);
        if (normalDrawable != null) {
          thumbImage = BitmapUtil.drawableToBitmap(normalDrawable);
        }
        Drawable disabledDrawable = a.getDrawable(R.styleable.RangeSeekBar_thumbDisabled);
        if (disabledDrawable != null) {
          thumbDisabledImage = BitmapUtil.drawableToBitmap(disabledDrawable);
        }
        Drawable pressedDrawable = a.getDrawable(R.styleable.RangeSeekBar_thumbPressed);
        if (pressedDrawable != null) {
          thumbPressedImage = BitmapUtil.drawableToBitmap(pressedDrawable);
        }
        Drawable maxNormalDrawable = a.getDrawable(R.styleable.RangeSeekBar_maxThumbNormal);
        if (maxNormalDrawable != null) {
          maxThumbImage = BitmapUtil.drawableToBitmap(maxNormalDrawable);
        }
        Drawable maxPressedDrawable = a.getDrawable(R.styleable.RangeSeekBar_maxThumbPressed);
        if (maxPressedDrawable != null) {
          maxThumbPressedImage = BitmapUtil.drawableToBitmap(maxPressedDrawable);
        }

      } finally {
        a.recycle();
      }
    }

    if (thumbImage == null) {
      thumbImage = BitmapFactory.decodeResource(getResources(), thumbNormal);
    }
    if (thumbPressedImage == null) {
      thumbPressedImage = BitmapFactory.decodeResource(getResources(), thumbPressed);
    }
    if (thumbDisabledImage == null) {
      thumbDisabledImage = BitmapFactory.decodeResource(getResources(), thumbDisabled);
    }
    if (maxThumbImage == null) {
      maxThumbImage = BitmapFactory.decodeResource(getResources(), maxThumbNormal);
    }
    if (maxThumbPressedImage == null) {
      maxThumbPressedImage = BitmapFactory.decodeResource(getResources(), maxThumbPressed);
    }

    mThumbHalfWidth = 0.5f * thumbImage.getWidth();
    mThumbHalfHeight = 0.5f * thumbImage.getHeight();

    setValuePrimAndNumberType();

    mTextSize = PixelUtil.dpToPx(context, DEFAULT_TEXT_SIZE_IN_DP);
    mDistanceToTop = PixelUtil.dpToPx(context, DEFAULT_TEXT_DISTANCE_TO_TOP_IN_DP);
    mTextOffset =
        !mShowTextAboveThumbs
            ? 0
            : this.mTextSize
                + PixelUtil.dpToPx(context, DEFAULT_TEXT_DISTANCE_TO_BUTTON_IN_DP)
                + this.mDistanceToTop;

    mRect =
        new RectF(
            padding,
            mTextOffset + mThumbHalfHeight - barHeight / 2,
            getWidth() - padding,
            mTextOffset + mThumbHalfHeight + barHeight / 2);

    // make RangeSeekBar focusable. This solves focus handling issues in case EditText widgets are
    // being used along with the RangeSeekBar within ScrollViews.
    setFocusable(true);
    setFocusableInTouchMode(true);
    mScaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
  }