blob: 0feaa07c3d7f40387682645fe1cfb8f92a80df8d [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.settings.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;
import com.android.internal.util.Preconditions;
import com.android.settings.R;
import com.android.settings.Utils;
/**
* DonutView represents a donut graph. It visualizes a certain percentage of fullness with a
* corresponding label with the fullness on the inside (i.e. "50%" inside of the donut).
*/
public class DonutView extends View {
private static final int TOP = -90;
private float mStrokeWidth;
private float mDeviceDensity;
private int mPercent;
private Paint mBackgroundCircle;
private Paint mFilledArc;
private TextPaint mTextPaint;
private TextPaint mBigNumberPaint;
private String mPercentString;
private String mFullString;
public DonutView(Context context) {
super(context);
}
public DonutView(Context context, AttributeSet attrs) {
super(context, attrs);
mDeviceDensity = getResources().getDisplayMetrics().density;
mStrokeWidth = 6f * mDeviceDensity;
mBackgroundCircle = new Paint();
mBackgroundCircle.setAntiAlias(true);
mBackgroundCircle.setStrokeCap(Paint.Cap.BUTT);
mBackgroundCircle.setStyle(Paint.Style.STROKE);
mBackgroundCircle.setStrokeWidth(mStrokeWidth);
mBackgroundCircle.setColor(getResources().getColor(R.color.donut_background_grey));
mFilledArc = new Paint();
mFilledArc.setAntiAlias(true);
mFilledArc.setStrokeCap(Paint.Cap.BUTT);
mFilledArc.setStyle(Paint.Style.STROKE);
mFilledArc.setStrokeWidth(mStrokeWidth);
mFilledArc.setColor(Utils.getColorAccent(getContext()));
mTextPaint = new TextPaint();
mTextPaint.setColor(Utils.getColorAccent(getContext()));
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(14f * mDeviceDensity);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mBigNumberPaint = new TextPaint();
mBigNumberPaint.setColor(Utils.getColorAccent(getContext()));
mBigNumberPaint.setAntiAlias(true);
mBigNumberPaint.setTextSize(30f * mDeviceDensity);
mBigNumberPaint.setTextAlign(Paint.Align.CENTER);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawDonut(canvas);
drawInnerText(canvas);
}
private void drawDonut(Canvas canvas) {
canvas.drawArc(0 + mStrokeWidth, 0 + mStrokeWidth, getWidth() - mStrokeWidth,
getHeight() - mStrokeWidth, TOP, 360, false, mBackgroundCircle);
canvas.drawArc(0 + mStrokeWidth, 0 + mStrokeWidth, getWidth() - mStrokeWidth,
getHeight() - mStrokeWidth, TOP, (360 * mPercent / 100), false, mFilledArc);
}
private void drawInnerText(Canvas canvas) {
final float centerX = getWidth() / 2;
final float centerY = getHeight() / 2;
final float totalHeight = getTextHeight(mTextPaint) + getTextHeight(mBigNumberPaint);
final float startY = centerY + totalHeight / 2;
// The first line is the height of the bottom text + its descender above the bottom line.
canvas.drawText(mPercentString, centerX,
startY - getTextHeight(mTextPaint) - mBigNumberPaint.descent(),
mBigNumberPaint);
// The second line starts at the bottom + room for the descender.
canvas.drawText(mFullString, centerX, startY - mTextPaint.descent(), mTextPaint);
}
/**
* Set a percentage full to have the donut graph.
*/
public void setPercentage(int percent) {
mPercent = percent;
mPercentString = Utils.formatPercentage(mPercent);
mFullString = getContext().getString(R.string.storage_percent_full);
invalidate();
}
private float getTextHeight(TextPaint paint) {
// Technically, this should be the cap height, but I can live with the descent - ascent.
return paint.descent() - paint.ascent();
}
}