Pie chart-like progress bar

This custom view shows a clock-like circular countdown, and can be used as a timer or as a ProgressBar. To use as a timer, create your own handler (or similar) to update the progress automatically.

Based on source code from FreeOTP released under Apache 2.0 license.

Usage

<com.pixplicity.example.ui.CircleProgressBar
        android:id="@+id/progress"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:max="1000"
        android:padding="6dp"
        android:progress="750" />

ProgressTextView.java

package com.pixplicity.example.ui;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader.TileMode;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.widget.ProgressBar;

import com.pixplicity.example.R;

public class CircleProgressBar extends ProgressBar {

    private static final int PADDING = 6;
    private Paint paintBorder;
    private Paint paint;
    private RectF rectf;
    private Rect rect;
    private LinearGradient mGradient;

    public CircleProgressBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setup();
    }

    public CircleProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        setup();
    }

    public CircleProgressBar(Context context) {
        super(context);
        setup();
    }

    private void setup() {
        paint = new Paint();
        paintBorder = new Paint();
        rectf = new RectF();
        rect = new Rect();

        paint.setColor(ContextCompat.getColor(getContext(), R.color.progress_color));
        paint.setAntiAlias(true);
        paint.setStyle(Style.FILL_AND_STROKE);

        paintBorder.setColor(ContextCompat.getColor(getContext(), R.color.progress_border));
        paintBorder.setAntiAlias(true);
        paintBorder.setStyle(Style.STROKE);
        paintBorder.setStrokeWidth(2);
    }

    @Override
    public synchronized void setProgress(int progress) {
        super.setProgress(progress);
        if (paint != null) {
            int percent = progress * 100 / getMax();
            if (percent > 25 || progress == 0) {
                paint.setColor(ContextCompat.getColor(getContext(), R.color.progress_color));
                paint.setShader(mGradient);
            } else {
                paint.setARGB(0x99, 0xff, 0xe0 * percent / 25, 0x00);
                paint.setShader(null);
            }
        }
    }

    @Override
    protected synchronized void onDraw(Canvas canvas) {
        getDrawingRect(rect);

        rect.left += getPaddingLeft();
        rect.top += getPaddingTop();
        rect.right -= getPaddingRight();
        rect.bottom -= getPaddingBottom();
        rectf.set(rect);

        canvas.drawOval(rectf, paintBorder);

        rect.left += PADDING;
        rect.top += PADDING;
        rect.right -= PADDING;
        rect.bottom -= PADDING;
        rectf.set(rect);

        if (mGradient == null) {
            mGradient = new LinearGradient(0, 0, 100, 100,
                    ContextCompat.getColor(getContext(), R.color.progress_color_light),
                    ContextCompat.getColor(getContext(), R.color.progress_color),
                    TileMode.CLAMP);
        }

        float sweep = getProgress() * 360 / getMax();
        float angle = 270 - sweep;
        canvas.drawArc(rectf, angle, sweep, true, paint);
    }
}