content: package com.github.lzyzsd.circleprogress;
  
  import android.content.Context;
  import android.content.res.TypedArray;
  import android.graphics.Canvas;
  import android.graphics.Color;
  import android.graphics.Paint;
  import android.graphics.RectF;
  import android.os.Bundle;
  import android.os.Parcelable;
  import android.text.TextPaint;
  import android.text.TextUtils;
  import android.util.AttributeSet;
  import android.view.View;
  
  /**
   * Created by bruce on 14-10-30.
   */
  public class DonutProgress extends View {
      private Paint finishedPaint;
      private Paint unfinishedPaint;
      private Paint innerCirclePaint;
      protected Paint textPaint;
  
      private RectF finishedOuterRect = new RectF();
      private RectF unfinishedOuterRect = new RectF();
  
      private float textSize;
      private int textColor;
      private int progress = 0;
      private int max;
      private int finishedStrokeColor;
      private int unfinishedStrokeColor;
      private float finishedStrokeWidth;
      private float unfinishedStrokeWidth;
      private int innerBackgroundColor;
      private String prefixText = "";
      private String suffixText = "%";
  
      private final float default_stroke_width;
      private final int default_finished_color = Color.rgb(66, 145, 241);
      private final int default_unfinished_color = Color.rgb(204, 204, 204);
      private final int default_text_color = Color.rgb(66, 145, 241);
      private final int default_inner_background_color = Color.TRANSPARENT;
      private final int default_max = 100;
      private final float default_text_size;
      private final int min_size;
  
      private static final String INSTANCE_STATE = "saved_instance";
      private static final String INSTANCE_TEXT_COLOR = "text_color";
      private static final String INSTANCE_TEXT_SIZE = "text_size";
      private static final String INSTANCE_FINISHED_STROKE_COLOR = "finished_stroke_color";
      private static final String INSTANCE_UNFINISHED_STROKE_COLOR = "unfinished_stroke_color";
      private static final String INSTANCE_MAX = "max";
      private static final String INSTANCE_PROGRESS = "progress";
      private static final String INSTANCE_SUFFIX = "suffix";
      private static final String INSTANCE_PREFIX = "prefix";
      private static final String INSTANCE_FINISHED_STROKE_WIDTH = "finished_stroke_width";
      private static final String INSTANCE_UNFINISHED_STROKE_WIDTH = "unfinished_stroke_width";
      private static final String INSTANCE_BACKGROUND_COLOR = "inner_background_color";
  
      public DonutProgress(Context context) {
          this(context, null);
      }
  
      public DonutProgress(Context context, AttributeSet attrs) {
          this(context, attrs, 0);
      }
  
      public DonutProgress(Context context, AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
  
          default_text_size = Utils.sp2px(getResources(), 18);
          min_size = (int) Utils.dp2px(getResources(), 100);
          default_stroke_width = Utils.dp2px(getResources(), 10);
  
          final TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DonutProgress, defStyleAttr, 0);
          initByAttributes(attributes);
          attributes.recycle();
  
          initPainters();
      }
  
      protected void initPainters() {
          textPaint = new TextPaint();
          textPaint.setColor(textColor);
          textPaint.setTextSize(textSize);
          textPaint.setAntiAlias(true);
  
          finishedPaint = new Paint();
          finishedPaint.setColor(finishedStrokeColor);
          finishedPaint.setStyle(Paint.Style.STROKE);
          finishedPaint.setAntiAlias(true);
          finishedPaint.setStrokeWidth(finishedStrokeWidth);
  
          unfinishedPaint = new Paint();
          unfinishedPaint.setColor(unfinishedStrokeColor);
          unfinishedPaint.setStyle(Paint.Style.STROKE);
          unfinishedPaint.setAntiAlias(true);
          unfinishedPaint.setStrokeWidth(unfinishedStrokeWidth);
  
          innerCirclePaint = new Paint();
          innerCirclePaint.setColor(innerBackgroundColor);
          innerCirclePaint.setAntiAlias(true);
      }
  
      protected void initByAttributes(TypedArray attributes) {
          finishedStrokeColor = attributes.getColor(R.styleable.DonutProgress_donut_finished_color, default_finished_color);
          unfinishedStrokeColor = attributes.getColor(R.styleable.DonutProgress_donut_unfinished_color, default_unfinished_color);
          textColor = attributes.getColor(R.styleable.DonutProgress_donut_text_color, default_text_color);
          textSize = attributes.getDimension(R.styleable.DonutProgress_donut_text_size, default_text_size);
  
          setMax(attributes.getInt(R.styleable.DonutProgress_donut_max, default_max));
          setProgress(attributes.getInt(R.styleable.DonutProgress_donut_progress, 0));
          finishedStrokeWidth = attributes.getDimension(R.styleable.DonutProgress_donut_finished_stroke_width, default_stroke_width);
          unfinishedStrokeWidth = attributes.getDimension(R.styleable.DonutProgress_donut_unfinished_stroke_width, default_stroke_width);
          if (attributes.getString(R.styleable.DonutProgress_donut_prefix_text) != null) {
              prefixText = attributes.getString(R.styleable.DonutProgress_donut_prefix_text);
          }
          if (attributes.getString(R.styleable.DonutProgress_donut_suffix_text) != null) {
              suffixText = attributes.getString(R.styleable.DonutProgress_donut_suffix_text);
          }
          innerBackgroundColor = attributes.getColor(R.styleable.DonutProgress_donut_background_color, default_inner_background_color);
      }
  
      @Override
      public void invalidate() {
          initPainters();
          super.invalidate();
      }
  
      public float getFinishedStrokeWidth() {
          return finishedStrokeWidth;
      }
  
      public void setFinishedStrokeWidth(float finishedStrokeWidth) {
          this.finishedStrokeWidth = finishedStrokeWidth;
          this.invalidate();
      }
  
      public float getUnfinishedStrokeWidth() {
          return unfinishedStrokeWidth;
      }
  
      public void setUnfinishedStrokeWidth(float unfinishedStrokeWidth) {
          this.unfinishedStrokeWidth = unfinishedStrokeWidth;
          this.invalidate();
      }
  
      private float getProgressAngle() {
          return getProgress() / (float) max * 360f;
      }
  
      public int getProgress() {
          return progress;
      }
  
      public void setProgress(int progress) {
          this.progress = progress;
          if (this.progress > getMax()) {
              this.progress %= getMax();
          }
          invalidate();
      }
  
      public int getMax() {
          return max;
      }
  
      public void setMax(int max) {
          if (max > 0) {
              this.max = max;
              invalidate();
          }
      }
  
      public float getTextSize() {
          return textSize;
      }
  
      public void setTextSize(float textSize) {
          this.textSize = textSize;
          this.invalidate();
      }
  
      public int getTextColor() {
          return textColor;
      }
  
      public void setTextColor(int textColor) {
          this.textColor = textColor;
          this.invalidate();
      }
  
      public int getFinishedStrokeColor() {
          return finishedStrokeColor;
      }
  
      public void setFinishedStrokeColor(int finishedStrokeColor) {
          this.finishedStrokeColor = finishedStrokeColor;
          this.invalidate();
      }
  
      public int getUnfinishedStrokeColor() {
          return unfinishedStrokeColor;
      }
  
      public void setUnfinishedStrokeColor(int unfinishedStrokeColor) {
          this.unfinishedStrokeColor = unfinishedStrokeColor;
          this.invalidate();
      }
  
      public String getSuffixText() {
          return suffixText;
      }
  
      public void setSuffixText(String suffixText) {
          this.suffixText = suffixText;
          this.invalidate();
      }
  
      public String getPrefixText() {
          return prefixText;
      }
  
      public void setPrefixText(String prefixText) {
          this.prefixText = prefixText;
          this.invalidate();
      }
  
      public int getInnerBackgroundColor() {
          return innerBackgroundColor;
      }
  
      public void setInnerBackgroundColor(int innerBackgroundColor) {
          this.innerBackgroundColor = innerBackgroundColor;
          this.invalidate();
      }
  
      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
          setMeasuredDimension(measure(widthMeasureSpec), measure(heightMeasureSpec));
      }
  
      private int measure(int measureSpec){
          int result;
          int mode = MeasureSpec.getMode(measureSpec);
          int size = MeasureSpec.getSize(measureSpec);
          if(mode == MeasureSpec.EXACTLY){
              result = size;
          }else{
              result = min_size;
              if(mode == MeasureSpec.AT_MOST){
                  result = Math.min(result, size);
              }
          }
          return result;
      }
  
      @Override
      protected void onDraw(Canvas canvas) {
          super.onDraw(canvas);
  
          if (finishedStrokeWidth > unfinishedStrokeWidth) {
              finishedOuterRect.set(finishedStrokeWidth / 2,
                  finishedStrokeWidth / 2,
                  getWidth() - finishedStrokeWidth / 2,
                  getHeight() - finishedStrokeWidth / 2);
              float delta = (finishedStrokeWidth - unfinishedStrokeWidth) / 2f;
              unfinishedOuterRect.set(unfinishedStrokeWidth / 2,
                  unfinishedStrokeWidth / 2,
                  getWidth() - unfinishedStrokeWidth / 2 - delta,
                  getHeight() - unfinishedStrokeWidth / 2 - delta);
          } else {
              float delta = (unfinishedStrokeWidth - finishedStrokeWidth) / 2f;
              finishedOuterRect.set(finishedStrokeWidth / 2,
                  finishedStrokeWidth / 2,
                  getWidth() - finishedStrokeWidth / 2 - delta,
                  getHeight() - finishedStrokeWidth / 2 - delta);
              unfinishedOuterRect.set(unfinishedStrokeWidth / 2,
                  unfinishedStrokeWidth / 2,
                  getWidth() - unfinishedStrokeWidth / 2,
                  getHeight() - unfinishedStrokeWidth / 2);
          }
          float innerCircleRadius = (getWidth() - Math.min(finishedStrokeWidth, unfinishedStrokeWidth) + Math.abs(finishedStrokeWidth - unfinishedStrokeWidth)) / 2f;
          canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, innerCircleRadius, innerCirclePaint);
          canvas.drawArc(finishedOuterRect, 0, getProgressAngle(), false, finishedPaint);
          canvas.drawArc(unfinishedOuterRect, getProgressAngle(), 360 - getProgressAngle(), false, unfinishedPaint);
  
          String text = prefixText + progress + suffixText;
          if (!TextUtils.isEmpty(text)) {
              float textHeight = textPaint.descent() + textPaint.ascent();
              canvas.drawText(text, (getWidth() - textPaint.measureText(text)) / 2.0f, (getWidth() - textHeight) / 2.0f, textPaint);
          }
      }
  
      @Override
      protected Parcelable onSaveInstanceState() {
          final Bundle bundle = new Bundle();
          bundle.putParcelable(INSTANCE_STATE, super.onSaveInstanceState());
          bundle.putInt(INSTANCE_TEXT_COLOR, getTextColor());
          bundle.putFloat(INSTANCE_TEXT_SIZE, getTextSize());
          bundle.putInt(INSTANCE_FINISHED_STROKE_COLOR, getFinishedStrokeColor());
          bundle.putInt(INSTANCE_UNFINISHED_STROKE_COLOR, getUnfinishedStrokeColor());
          bundle.putInt(INSTANCE_MAX, getMax());
          bundle.putInt(INSTANCE_PROGRESS, getProgress());
          bundle.putString(INSTANCE_SUFFIX, getSuffixText());
          bundle.putString(INSTANCE_PREFIX, getPrefixText());
          bundle.putFloat(INSTANCE_FINISHED_STROKE_WIDTH, getFinishedStrokeWidth());
          bundle.putFloat(INSTANCE_UNFINISHED_STROKE_WIDTH, getUnfinishedStrokeWidth());
          bundle.putInt(INSTANCE_BACKGROUND_COLOR, getInnerBackgroundColor());
          return bundle;
      }
  
      @Override
      protected void onRestoreInstanceState(Parcelable state) {
          if(state instanceof Bundle) {
              final Bundle bundle = (Bundle) state;
              textColor = bundle.getInt(INSTANCE_TEXT_COLOR);
              textSize = bundle.getFloat(INSTANCE_TEXT_SIZE);
              finishedStrokeColor = bundle.getInt(INSTANCE_FINISHED_STROKE_COLOR);
              unfinishedStrokeColor = bundle.getInt(INSTANCE_UNFINISHED_STROKE_COLOR);
              finishedStrokeWidth = bundle.getFloat(INSTANCE_FINISHED_STROKE_WIDTH);
              unfinishedStrokeWidth = bundle.getFloat(INSTANCE_UNFINISHED_STROKE_WIDTH);
              innerBackgroundColor = bundle.getInt(INSTANCE_BACKGROUND_COLOR);
              initPainters();
              setMax(bundle.getInt(INSTANCE_MAX));
              setProgress(bundle.getInt(INSTANCE_PROGRESS));
              prefixText = bundle.getString(INSTANCE_PREFIX);
              suffixText = bundle.getString(INSTANCE_SUFFIX);
              super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE));
              return;
          }
          super.onRestoreInstanceState(state);
      }
  }
  