protected void drawHole(Canvas c) {

    if (mChart.isDrawHoleEnabled()) {

      float transparentCircleRadius = mChart.getTransparentCircleRadius();
      float holeRadius = mChart.getHoleRadius();
      float radius = mChart.getRadius();

      PointF center = mChart.getCenterCircleBox();

      // only draw the circle if it can be seen (not covered by the hole)
      if (transparentCircleRadius > holeRadius) {

        // get original alpha
        int alpha = mTransparentCirclePaint.getAlpha();
        mTransparentCirclePaint.setAlpha(
            (int) ((float) alpha * mAnimator.getPhaseX() * mAnimator.getPhaseY()));

        // draw the transparent-circle
        mBitmapCanvas.drawCircle(
            center.x, center.y, radius / 100 * transparentCircleRadius, mTransparentCirclePaint);

        // reset alpha
        mTransparentCirclePaint.setAlpha(alpha);
      }

      // draw the hole-circle
      mBitmapCanvas.drawCircle(center.x, center.y, radius / 100 * holeRadius, mHolePaint);
    }
  }
  protected void drawCenterText(Canvas c) {

    SpannableString centerText = mChart.getCenterText();

    if (mChart.isDrawCenterTextEnabled() && centerText != null) {

      PointF center = mChart.getCenterCircleBox();

      float innerRadius =
          mChart.isDrawHoleEnabled() && mChart.isHoleTransparent()
              ? mChart.getRadius() * (mChart.getHoleRadius() / 100f)
              : mChart.getRadius();

      RectF holeRect = mRectBuffer[0];
      holeRect.left = center.x - innerRadius;
      holeRect.top = center.y - innerRadius;
      holeRect.right = center.x + innerRadius;
      holeRect.bottom = center.y + innerRadius;
      RectF boundingRect = mRectBuffer[1];
      boundingRect.set(holeRect);

      float radiusPercent = mChart.getCenterTextRadiusPercent();
      if (radiusPercent > 0.0) {
        boundingRect.inset(
            (boundingRect.width() - boundingRect.width() * radiusPercent) / 2.f,
            (boundingRect.height() - boundingRect.height() * radiusPercent) / 2.f);
      }

      if (!centerText.equals(mCenterTextLastValue) || !boundingRect.equals(mCenterTextLastBounds)) {

        // Next time we won't recalculate StaticLayout...
        mCenterTextLastBounds.set(boundingRect);
        mCenterTextLastValue = centerText;

        float width = mCenterTextLastBounds.width();

        // If width is 0, it will crash. Always have a minimum of 1
        mCenterTextLayout =
            new StaticLayout(
                centerText,
                0,
                centerText.length(),
                mCenterTextPaint,
                (int) Math.max(Math.ceil(width), 1.f),
                Layout.Alignment.ALIGN_CENTER,
                1.f,
                0.f,
                false);
      }

      float layoutHeight = mCenterTextLayout.getHeight();

      c.save();
      c.translate(
          boundingRect.left, boundingRect.top + (boundingRect.height() - layoutHeight) / 2.f);
      mCenterTextLayout.draw(c);
      c.restore();
    }
  }
  protected void drawRoundedSlices(Canvas c) {

    if (!mChart.isDrawRoundedSlicesEnabled()) return;

    PieDataSet dataSet = mChart.getData().getDataSet();

    if (!dataSet.isVisible()) return;

    PointF center = mChart.getCenterCircleBox();
    float r = mChart.getRadius();

    // calculate the radius of the "slice-circle"
    float circleRadius = (r - (r * mChart.getHoleRadius() / 100f)) / 2f;

    List<Entry> entries = dataSet.getYVals();
    float[] drawAngles = mChart.getDrawAngles();
    float angle = mChart.getRotationAngle();

    for (int j = 0; j < entries.size(); j++) {

      float newangle = drawAngles[j];

      Entry e = entries.get(j);

      // draw only if the value is greater than zero
      if ((Math.abs(e.getVal()) > 0.000001)) {

        float x =
            (float)
                ((r - circleRadius)
                        * Math.cos(Math.toRadians((angle + newangle) * mAnimator.getPhaseY()))
                    + center.x);
        float y =
            (float)
                ((r - circleRadius)
                        * Math.sin(Math.toRadians((angle + newangle) * mAnimator.getPhaseY()))
                    + center.y);

        mRenderPaint.setColor(dataSet.getColor(j));
        mBitmapCanvas.drawCircle(x, y, circleRadius, mRenderPaint);
      }

      angle += newangle * mAnimator.getPhaseX();
    }
  }
  @Override
  public void drawValues(Canvas c) {

    PointF center = mChart.getCenterCircleBox();

    // get whole the radius
    float r = mChart.getRadius();
    float rotationAngle = mChart.getRotationAngle();
    float[] drawAngles = mChart.getDrawAngles();
    float[] absoluteAngles = mChart.getAbsoluteAngles();

    float off = r / 10f * 3.6f;

    if (mChart.isDrawHoleEnabled()) {
      off = (r - (r / 100f * mChart.getHoleRadius())) / 2f;
    }

    r -= off; // offset to keep things inside the chart

    PieData data = mChart.getData();
    List<PieDataSet> dataSets = data.getDataSets();
    boolean drawXVals = mChart.isDrawSliceTextEnabled();

    int cnt = 0;

    for (int i = 0; i < dataSets.size(); i++) {

      PieDataSet dataSet = dataSets.get(i);

      if (!dataSet.isDrawValuesEnabled() && !drawXVals) continue;

      // apply the text-styling defined by the DataSet
      applyValueTextStyle(dataSet);

      float lineHeight = Utils.calcTextHeight(mValuePaint, "Q") + Utils.convertDpToPixel(4f);

      List<Entry> entries = dataSet.getYVals();

      for (int j = 0,
              maxEntry =
                  Math.min((int) Math.ceil(entries.size() * mAnimator.getPhaseX()), entries.size());
          j < maxEntry;
          j++) {

        Entry entry = entries.get(j);

        // offset needed to center the drawn text in the slice
        float offset = drawAngles[cnt] / 2;

        // calculate the text position
        float x =
            (float)
                (r
                        * Math.cos(
                            Math.toRadians(
                                (rotationAngle + absoluteAngles[cnt] - offset)
                                    * mAnimator.getPhaseY()))
                    + center.x);
        float y =
            (float)
                (r
                        * Math.sin(
                            Math.toRadians(
                                (rotationAngle + absoluteAngles[cnt] - offset)
                                    * mAnimator.getPhaseY()))
                    + center.y);

        float value =
            mChart.isUsePercentValuesEnabled()
                ? entry.getVal() / data.getYValueSum() * 100f
                : entry.getVal();

        ValueFormatter formatter = dataSet.getValueFormatter();

        boolean drawYVals = dataSet.isDrawValuesEnabled();

        // draw everything, depending on settings
        if (drawXVals && drawYVals) {

          drawValue(c, formatter, value, entry, 0, x, y);

          if (j < data.getXValCount())
            c.drawText(data.getXVals().get(j), x, y + lineHeight, mValuePaint);

        } else if (drawXVals && !drawYVals) {
          if (j < data.getXValCount())
            c.drawText(data.getXVals().get(j), x, y + lineHeight / 2f, mValuePaint);
        } else if (!drawXVals && drawYVals) {

          drawValue(c, formatter, value, entry, 0, x, y + lineHeight / 2f);
        }

        cnt++;
      }
    }
  }