diff options
Diffstat (limited to 'src/com/android/settings/widget')
6 files changed, 102 insertions, 389 deletions
diff --git a/src/com/android/settings/widget/ChartDataUsageView.java b/src/com/android/settings/widget/ChartDataUsageView.java index 4e16bfc..c20a8db 100644 --- a/src/com/android/settings/widget/ChartDataUsageView.java +++ b/src/com/android/settings/widget/ChartDataUsageView.java @@ -50,26 +50,24 @@ public class ChartDataUsageView extends ChartView { private static final int MSG_UPDATE_AXIS = 100; private static final long DELAY_MILLIS = 250; - private static final boolean LIMIT_SWEEPS_TO_VALID_DATA = false; - private ChartGridView mGrid; private ChartNetworkSeriesView mSeries; private ChartNetworkSeriesView mDetailSeries; private NetworkStatsHistory mHistory; - private ChartSweepView mSweepLeft; - private ChartSweepView mSweepRight; private ChartSweepView mSweepWarning; private ChartSweepView mSweepLimit; + private long mInspectStart; + private long mInspectEnd; + private Handler mHandler; /** Current maximum value of {@link #mVert}. */ private long mVertMax; public interface DataUsageChartListener { - public void onInspectRangeChanged(); public void onWarningChanged(); public void onLimitChanged(); public void requestWarningEdit(); @@ -112,43 +110,27 @@ public class ChartDataUsageView extends ChartView { mDetailSeries = (ChartNetworkSeriesView) findViewById(R.id.detail_series); mDetailSeries.setVisibility(View.GONE); - mSweepLeft = (ChartSweepView) findViewById(R.id.sweep_left); - mSweepRight = (ChartSweepView) findViewById(R.id.sweep_right); mSweepLimit = (ChartSweepView) findViewById(R.id.sweep_limit); mSweepWarning = (ChartSweepView) findViewById(R.id.sweep_warning); // prevent sweeps from crossing each other - mSweepLeft.setValidRangeDynamic(null, mSweepRight); - mSweepRight.setValidRangeDynamic(mSweepLeft, null); mSweepWarning.setValidRangeDynamic(null, mSweepLimit); mSweepLimit.setValidRangeDynamic(mSweepWarning, null); // mark neighbors for checking touch events against - mSweepLeft.setNeighbors(mSweepRight); - mSweepRight.setNeighbors(mSweepLeft); - mSweepLimit.setNeighbors(mSweepWarning, mSweepLeft, mSweepRight); - mSweepWarning.setNeighbors(mSweepLimit, mSweepLeft, mSweepRight); + mSweepLimit.setNeighbors(mSweepWarning); + mSweepWarning.setNeighbors(mSweepLimit); - mSweepLeft.addOnSweepListener(mHorizListener); - mSweepRight.addOnSweepListener(mHorizListener); mSweepWarning.addOnSweepListener(mVertListener); mSweepLimit.addOnSweepListener(mVertListener); mSweepWarning.setDragInterval(5 * MB_IN_BYTES); mSweepLimit.setDragInterval(5 * MB_IN_BYTES); - // TODO: make time sweeps adjustable through dpad - mSweepLeft.setClickable(false); - mSweepLeft.setFocusable(false); - mSweepRight.setClickable(false); - mSweepRight.setFocusable(false); - // tell everyone about our axis mGrid.init(mHoriz, mVert); mSeries.init(mHoriz, mVert); mDetailSeries.init(mHoriz, mVert); - mSweepLeft.init(mHoriz); - mSweepRight.init(mHoriz); mSweepWarning.init(mVert); mSweepLimit.init(mVert); @@ -194,7 +176,7 @@ public class ChartDataUsageView extends ChartView { mSweepLimit.setEnabled(true); mSweepLimit.setValue(policy.limitBytes); } else { - mSweepLimit.setVisibility(View.VISIBLE); + mSweepLimit.setVisibility(View.INVISIBLE); mSweepLimit.setEnabled(false); mSweepLimit.setValue(-1); } @@ -295,23 +277,6 @@ public class ChartDataUsageView extends ChartView { mSeries.setEstimateVisible(estimateVisible); } - private OnSweepListener mHorizListener = new OnSweepListener() { - @Override - public void onSweep(ChartSweepView sweep, boolean sweepDone) { - updatePrimaryRange(); - - // update detail list only when done sweeping - if (sweepDone && mListener != null) { - mListener.onInspectRangeChanged(); - } - } - - @Override - public void requestEdit(ChartSweepView sweep) { - // ignored - } - }; - private void sendUpdateAxisDelayed(ChartSweepView sweep, boolean force) { if (force || !mHandler.hasMessages(MSG_UPDATE_AXIS, sweep)) { mHandler.sendMessageDelayed( @@ -369,11 +334,11 @@ public class ChartDataUsageView extends ChartView { } public long getInspectStart() { - return mSweepLeft.getValue(); + return mInspectStart; } public long getInspectEnd() { - return mSweepRight.getValue(); + return mInspectEnd; } public long getWarningBytes() { @@ -384,14 +349,6 @@ public class ChartDataUsageView extends ChartView { return mSweepLimit.getLabelValue(); } - private long getHistoryStart() { - return mHistory != null ? mHistory.getStart() : Long.MAX_VALUE; - } - - private long getHistoryEnd() { - return mHistory != null ? mHistory.getEnd() : Long.MIN_VALUE; - } - /** * Set the exact time range that should be displayed, updating how * {@link ChartNetworkSeriesView} paints. Moves inspection ranges to be the @@ -403,30 +360,8 @@ public class ChartDataUsageView extends ChartView { mSeries.setBounds(visibleStart, visibleEnd); mDetailSeries.setBounds(visibleStart, visibleEnd); - final long historyStart = getHistoryStart(); - final long historyEnd = getHistoryEnd(); - - final long validStart = historyStart == Long.MAX_VALUE ? visibleStart - : Math.max(visibleStart, historyStart); - final long validEnd = historyEnd == Long.MIN_VALUE ? visibleEnd - : Math.min(visibleEnd, historyEnd); - - if (LIMIT_SWEEPS_TO_VALID_DATA) { - // prevent time sweeps from leaving valid data - mSweepLeft.setValidRange(validStart, validEnd); - mSweepRight.setValidRange(validStart, validEnd); - } else { - mSweepLeft.setValidRange(visibleStart, visibleEnd); - mSweepRight.setValidRange(visibleStart, visibleEnd); - } - - // default sweeps to last week of data - final long halfRange = (visibleEnd + visibleStart) / 2; - final long sweepMax = validEnd; - final long sweepMin = Math.max(visibleStart, (sweepMax - DateUtils.WEEK_IN_MILLIS)); - - mSweepLeft.setValue(sweepMin); - mSweepRight.setValue(sweepMax); + mInspectStart = visibleStart; + mInspectEnd = visibleEnd; requestLayout(); if (changed) { @@ -440,15 +375,11 @@ public class ChartDataUsageView extends ChartView { } private void updatePrimaryRange() { - final long left = mSweepLeft.getValue(); - final long right = mSweepRight.getValue(); - // prefer showing primary range on detail series, when available if (mDetailSeries.getVisibility() == View.VISIBLE) { - mDetailSeries.setPrimaryRange(left, right); - mSeries.setPrimaryRange(0, 0); + mSeries.setSecondary(true); } else { - mSeries.setPrimaryRange(left, right); + mSeries.setSecondary(false); } } diff --git a/src/com/android/settings/widget/ChartGridView.java b/src/com/android/settings/widget/ChartGridView.java index ec5882c..4cd6f5f 100644 --- a/src/com/android/settings/widget/ChartGridView.java +++ b/src/com/android/settings/widget/ChartGridView.java @@ -19,22 +19,25 @@ package com.android.settings.widget; import static com.android.settings.DataUsageSummary.formatDateRange; import android.content.Context; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; import android.util.AttributeSet; +import android.util.Log; import android.util.TypedValue; import android.view.View; import com.android.internal.util.Preconditions; import com.android.settings.R; +import java.util.Locale; + /** * Background of {@link ChartView} that renders grid lines as requested by * {@link ChartAxis#getTickPoints()}. @@ -47,10 +50,13 @@ public class ChartGridView extends View { private Drawable mPrimary; private Drawable mSecondary; private Drawable mBorder; + + private int mLabelSize; private int mLabelColor; - private Layout mLayoutStart; - private Layout mLayoutEnd; + private Layout mLabelStart; + private Layout mLabelMid; + private Layout mLabelEnd; public ChartGridView(Context context) { this(context, null, 0); @@ -71,7 +77,17 @@ public class ChartGridView extends View { mPrimary = a.getDrawable(R.styleable.ChartGridView_primaryDrawable); mSecondary = a.getDrawable(R.styleable.ChartGridView_secondaryDrawable); mBorder = a.getDrawable(R.styleable.ChartGridView_borderDrawable); - mLabelColor = a.getColor(R.styleable.ChartGridView_labelColor, Color.RED); + + final int taId = a.getResourceId(R.styleable.ChartGridView_android_textAppearance, -1); + final TypedArray ta = context.obtainStyledAttributes(taId, + com.android.internal.R.styleable.TextAppearance); + mLabelSize = ta.getDimensionPixelSize( + com.android.internal.R.styleable.TextAppearance_textSize, 0); + ta.recycle(); + + final ColorStateList labelColor = a.getColorStateList( + R.styleable.ChartGridView_android_textColor); + mLabelColor = labelColor.getDefaultColor(); a.recycle(); } @@ -83,71 +99,83 @@ public class ChartGridView extends View { void setBounds(long start, long end) { final Context context = getContext(); - mLayoutStart = makeLayout(formatDateRange(context, start, start)); - mLayoutEnd = makeLayout(formatDateRange(context, end, end)); + final long mid = (start + end) / 2; + mLabelStart = makeLabel(formatDateRange(context, start, start)); + mLabelMid = makeLabel(formatDateRange(context, mid, mid)); + mLabelEnd = makeLabel(formatDateRange(context, end, end)); invalidate(); } @Override protected void onDraw(Canvas canvas) { final int width = getWidth(); - final int height = getHeight(); + final int height = getHeight() - getPaddingBottom(); final Drawable secondary = mSecondary; - final int secondaryHeight = mSecondary.getIntrinsicHeight(); - - final float[] vertTicks = mVert.getTickPoints(); - for (float y : vertTicks) { - final int bottom = (int) Math.min(y + secondaryHeight, height); - secondary.setBounds(0, (int) y, width, bottom); - secondary.draw(canvas); + if (secondary != null) { + final int secondaryHeight = secondary.getIntrinsicHeight(); + + final float[] vertTicks = mVert.getTickPoints(); + for (float y : vertTicks) { + final int bottom = (int) Math.min(y + secondaryHeight, height); + secondary.setBounds(0, (int) y, width, bottom); + secondary.draw(canvas); + } } final Drawable primary = mPrimary; - final int primaryWidth = mPrimary.getIntrinsicWidth(); - final int primaryHeight = mPrimary.getIntrinsicHeight(); - - final float[] horizTicks = mHoriz.getTickPoints(); - for (float x : horizTicks) { - final int right = (int) Math.min(x + primaryWidth, width); - primary.setBounds((int) x, 0, right, height); - primary.draw(canvas); + if (primary != null) { + final int primaryWidth = primary.getIntrinsicWidth(); + final int primaryHeight = primary.getIntrinsicHeight(); + + final float[] horizTicks = mHoriz.getTickPoints(); + for (float x : horizTicks) { + final int right = (int) Math.min(x + primaryWidth, width); + primary.setBounds((int) x, 0, right, height); + primary.draw(canvas); + } } mBorder.setBounds(0, 0, width, height); mBorder.draw(canvas); - final int padding = mLayoutStart != null ? mLayoutStart.getHeight() / 8 : 0; + final int padding = mLabelStart != null ? mLabelStart.getHeight() / 8 : 0; - final Layout start = mLayoutStart; + final Layout start = mLabelStart; if (start != null) { - canvas.save(); + final int saveCount = canvas.save(); canvas.translate(0, height + padding); start.draw(canvas); - canvas.restore(); + canvas.restoreToCount(saveCount); + } + + final Layout mid = mLabelMid; + if (mid != null) { + final int saveCount = canvas.save(); + canvas.translate((width - mid.getWidth()) / 2, height + padding); + mid.draw(canvas); + canvas.restoreToCount(saveCount); } - final Layout end = mLayoutEnd; + final Layout end = mLabelEnd; if (end != null) { - canvas.save(); + final int saveCount = canvas.save(); canvas.translate(width - end.getWidth(), height + padding); end.draw(canvas); - canvas.restore(); + canvas.restoreToCount(saveCount); } } - private Layout makeLayout(CharSequence text) { + private Layout makeLabel(CharSequence text) { final Resources res = getResources(); final TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG); paint.density = res.getDisplayMetrics().density; paint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale); paint.setColor(mLabelColor); - paint.setTextSize( - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10, res.getDisplayMetrics())); + paint.setTextSize(mLabelSize); return new StaticLayout(text, paint, (int) Math.ceil(Layout.getDesiredWidth(text, paint)), Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true); } - } diff --git a/src/com/android/settings/widget/ChartNetworkSeriesView.java b/src/com/android/settings/widget/ChartNetworkSeriesView.java index 6250a25..7aaba66 100644 --- a/src/com/android/settings/widget/ChartNetworkSeriesView.java +++ b/src/com/android/settings/widget/ChartNetworkSeriesView.java @@ -60,17 +60,17 @@ public class ChartNetworkSeriesView extends View { private Path mPathFill; private Path mPathEstimate; + private int mSafeRegion; + private long mStart; private long mEnd; - private long mPrimaryLeft; - private long mPrimaryRight; - /** Series will be extended to reach this end time. */ private long mEndTime = Long.MIN_VALUE; private boolean mPathValid = false; private boolean mEstimateVisible = false; + private boolean mSecondary = false; private long mMax; private long mMaxEstimate; @@ -93,8 +93,11 @@ public class ChartNetworkSeriesView extends View { final int fill = a.getColor(R.styleable.ChartNetworkSeriesView_fillColor, Color.RED); final int fillSecondary = a.getColor( R.styleable.ChartNetworkSeriesView_fillColorSecondary, Color.RED); + final int safeRegion = a.getDimensionPixelSize( + R.styleable.ChartNetworkSeriesView_safeRegion, 0); setChartColor(stroke, fill, fillSecondary); + setSafeRegion(safeRegion); setWillNotDraw(false); a.recycle(); @@ -134,6 +137,10 @@ public class ChartNetworkSeriesView extends View { mPaintEstimate.setPathEffect(new DashPathEffect(new float[] { 10, 10 }, 1)); } + public void setSafeRegion(int safeRegion) { + mSafeRegion = safeRegion; + } + public void bindNetworkStats(NetworkStatsHistory stats) { mStats = stats; invalidatePath(); @@ -145,14 +152,8 @@ public class ChartNetworkSeriesView extends View { mEnd = end; } - /** - * Set the range to paint with {@link #mPaintFill}, leaving the remaining - * area to be painted with {@link #mPaintFillSecondary}. - */ - public void setPrimaryRange(long left, long right) { - mPrimaryLeft = left; - mPrimaryRight = right; - invalidate(); + public void setSecondary(boolean secondary) { + mSecondary = secondary; } public void invalidatePath() { @@ -322,9 +323,6 @@ public class ChartNetworkSeriesView extends View { generatePath(); } - final float primaryLeftPoint = mHoriz.convertToPoint(mPrimaryLeft); - final float primaryRightPoint = mHoriz.convertToPoint(mPrimaryRight); - if (mEstimateVisible) { save = canvas.save(); canvas.clipRect(0, 0, getWidth(), getHeight()); @@ -332,21 +330,11 @@ public class ChartNetworkSeriesView extends View { canvas.restoreToCount(save); } - save = canvas.save(); - canvas.clipRect(0, 0, primaryLeftPoint, getHeight()); - canvas.drawPath(mPathFill, mPaintFillSecondary); - canvas.restoreToCount(save); + final Paint paintFill = mSecondary ? mPaintFillSecondary : mPaintFill; save = canvas.save(); - canvas.clipRect(primaryRightPoint, 0, getWidth(), getHeight()); - canvas.drawPath(mPathFill, mPaintFillSecondary); + canvas.clipRect(mSafeRegion, 0, getWidth(), getHeight() - mSafeRegion); + canvas.drawPath(mPathFill, paintFill); canvas.restoreToCount(save); - - save = canvas.save(); - canvas.clipRect(primaryLeftPoint, 0, primaryRightPoint, getHeight()); - canvas.drawPath(mPathFill, mPaintFill); - canvas.drawPath(mPathStroke, mPaintStroke); - canvas.restoreToCount(save); - } } diff --git a/src/com/android/settings/widget/ChartSweepView.java b/src/com/android/settings/widget/ChartSweepView.java index 774e5d8..04fc862 100644 --- a/src/com/android/settings/widget/ChartSweepView.java +++ b/src/com/android/settings/widget/ChartSweepView.java @@ -58,6 +58,7 @@ public class ChartSweepView extends View { private Rect mMargins = new Rect(); private float mNeighborMargin; + private int mSafeRegion; private int mFollowAxis; @@ -125,6 +126,7 @@ public class ChartSweepView extends View { setSweepDrawable(a.getDrawable(R.styleable.ChartSweepView_sweepDrawable)); setFollowAxis(a.getInt(R.styleable.ChartSweepView_followAxis, -1)); setNeighborMargin(a.getDimensionPixelSize(R.styleable.ChartSweepView_neighborMargin, 0)); + setSafeRegion(a.getDimensionPixelSize(R.styleable.ChartSweepView_safeRegion, 0)); setLabelMinSize(a.getDimensionPixelSize(R.styleable.ChartSweepView_labelSize, 0)); setLabelTemplate(a.getResourceId(R.styleable.ChartSweepView_labelTemplate, 0)); @@ -259,7 +261,6 @@ public class ChartSweepView extends View { paint.density = getResources().getDisplayMetrics().density; paint.setCompatibilityScaling(getResources().getCompatibilityInfo().applicationScale); paint.setColor(mLabelColor); - paint.setShadowLayer(4 * paint.density, 0, 0, Color.BLACK); mLabelTemplate = new SpannableStringBuilder(template); mLabelLayout = new DynamicLayout( @@ -383,6 +384,10 @@ public class ChartSweepView extends View { mNeighborMargin = neighborMargin; } + public void setSafeRegion(int safeRegion) { + mSafeRegion = safeRegion; + } + /** * Set valid range this sweep can move within, defined by the given * {@link ChartSweepView}. The most restrictive combination of all valid @@ -709,7 +714,7 @@ public class ChartSweepView extends View { mLabelLayout.draw(canvas); } canvas.restoreToCount(count); - labelSize = (int) mLabelSize; + labelSize = (int) mLabelSize + mSafeRegion; } else { labelSize = 0; } diff --git a/src/com/android/settings/widget/ChartView.java b/src/com/android/settings/widget/ChartView.java index 69e6e94..30284bc 100644 --- a/src/com/android/settings/widget/ChartView.java +++ b/src/com/android/settings/widget/ChartView.java @@ -112,12 +112,18 @@ public class ChartView extends FrameLayout { parentRect.set(mContent); - if (child instanceof ChartNetworkSeriesView || child instanceof ChartGridView) { + if (child instanceof ChartNetworkSeriesView) { // series are always laid out to fill entire graph area // TODO: handle scrolling for series larger than content area Gravity.apply(params.gravity, width, height, parentRect, childRect); child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom); + } else if (child instanceof ChartGridView) { + // Grid uses some extra room for labels + Gravity.apply(params.gravity, width, height, parentRect, childRect); + child.layout(childRect.left, childRect.top, childRect.right, + childRect.bottom + child.getPaddingBottom()); + } else if (child instanceof ChartSweepView) { layoutSweep((ChartSweepView) child, parentRect, childRect); child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom); @@ -154,5 +160,4 @@ public class ChartView extends FrameLayout { parentRect, childRect); } } - } diff --git a/src/com/android/settings/widget/PieChartView.java b/src/com/android/settings/widget/PieChartView.java deleted file mode 100644 index 6070190..0000000 --- a/src/com/android/settings/widget/PieChartView.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (C) 2011 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.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Paint.Style; -import android.graphics.Path; -import android.graphics.Path.Direction; -import android.graphics.RadialGradient; -import android.graphics.RectF; -import android.graphics.Shader.TileMode; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; - -import com.google.android.collect.Lists; - -import java.util.ArrayList; - -/** - * Pie chart with multiple items. - */ -public class PieChartView extends View { - public static final String TAG = "PieChartView"; - public static final boolean LOGD = false; - - private static final boolean FILL_GRADIENT = false; - - private ArrayList<Slice> mSlices = Lists.newArrayList(); - - private int mOriginAngle; - private Matrix mMatrix = new Matrix(); - - private Paint mPaintOutline = new Paint(); - - private Path mPathSide = new Path(); - private Path mPathSideOutline = new Path(); - - private Path mPathOutline = new Path(); - - private int mSideWidth; - - public class Slice { - public long value; - - public Path path = new Path(); - public Path pathSide = new Path(); - public Path pathOutline = new Path(); - - public Paint paint; - - public Slice(long value, int color) { - this.value = value; - this.paint = buildFillPaint(color, getResources()); - } - } - - public PieChartView(Context context) { - this(context, null); - } - - public PieChartView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public PieChartView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - mPaintOutline.setColor(Color.BLACK); - mPaintOutline.setStyle(Style.STROKE); - mPaintOutline.setStrokeWidth(3f * getResources().getDisplayMetrics().density); - mPaintOutline.setAntiAlias(true); - - mSideWidth = (int) (20 * getResources().getDisplayMetrics().density); - - setWillNotDraw(false); - } - - private static Paint buildFillPaint(int color, Resources res) { - final Paint paint = new Paint(); - - paint.setColor(color); - paint.setStyle(Style.FILL_AND_STROKE); - paint.setAntiAlias(true); - - if (FILL_GRADIENT) { - final int width = (int) (280 * res.getDisplayMetrics().density); - paint.setShader(new RadialGradient(0, 0, width, color, darken(color), TileMode.MIRROR)); - } - - return paint; - } - - public void setOriginAngle(int originAngle) { - mOriginAngle = originAngle; - } - - public void addSlice(long value, int color) { - mSlices.add(new Slice(value, color)); - } - - public void removeAllSlices() { - mSlices.clear(); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - final float centerX = getWidth() / 2; - final float centerY = getHeight() / 2; - - mMatrix.reset(); - mMatrix.postScale(0.665f, 0.95f, centerX, centerY); - mMatrix.postRotate(-40, centerX, centerY); - - generatePath(); - } - - public void generatePath() { - if (LOGD) Log.d(TAG, "generatePath()"); - - long total = 0; - for (Slice slice : mSlices) { - slice.path.reset(); - slice.pathSide.reset(); - slice.pathOutline.reset(); - total += slice.value; - } - - mPathSide.reset(); - mPathSideOutline.reset(); - mPathOutline.reset(); - - // bail when not enough stats to render - if (total == 0) { - invalidate(); - return; - } - - final int width = getWidth(); - final int height = getHeight(); - - final RectF rect = new RectF(0, 0, width, height); - final RectF rectSide = new RectF(); - rectSide.set(rect); - rectSide.offset(-mSideWidth, 0); - - mPathSide.addOval(rectSide, Direction.CW); - mPathSideOutline.addOval(rectSide, Direction.CW); - mPathOutline.addOval(rect, Direction.CW); - - int startAngle = mOriginAngle; - for (Slice slice : mSlices) { - final int sweepAngle = (int) (slice.value * 360 / total); - final int endAngle = startAngle + sweepAngle; - - final float startAngleMod = startAngle % 360; - final float endAngleMod = endAngle % 360; - final boolean startSideVisible = startAngleMod > 90 && startAngleMod < 270; - final boolean endSideVisible = endAngleMod > 90 && endAngleMod < 270; - - // draw slice - slice.path.moveTo(rect.centerX(), rect.centerY()); - slice.path.arcTo(rect, startAngle, sweepAngle); - slice.path.lineTo(rect.centerX(), rect.centerY()); - - if (startSideVisible || endSideVisible) { - - // when start is beyond horizon, push until visible - final float startAngleSide = startSideVisible ? startAngle : 450; - final float endAngleSide = endSideVisible ? endAngle : 270; - final float sweepAngleSide = endAngleSide - startAngleSide; - - // draw slice side - slice.pathSide.moveTo(rect.centerX(), rect.centerY()); - slice.pathSide.arcTo(rect, startAngleSide, 0); - slice.pathSide.rLineTo(-mSideWidth, 0); - slice.pathSide.arcTo(rectSide, startAngleSide, sweepAngleSide); - slice.pathSide.rLineTo(mSideWidth, 0); - slice.pathSide.arcTo(rect, endAngleSide, -sweepAngleSide); - } - - // draw slice outline - slice.pathOutline.moveTo(rect.centerX(), rect.centerY()); - slice.pathOutline.arcTo(rect, startAngle, 0); - if (startSideVisible) { - slice.pathOutline.rLineTo(-mSideWidth, 0); - } - slice.pathOutline.moveTo(rect.centerX(), rect.centerY()); - slice.pathOutline.arcTo(rect, startAngle + sweepAngle, 0); - if (endSideVisible) { - slice.pathOutline.rLineTo(-mSideWidth, 0); - } - - startAngle += sweepAngle; - } - - invalidate(); - } - - @Override - protected void onDraw(Canvas canvas) { - - canvas.concat(mMatrix); - - for (Slice slice : mSlices) { - canvas.drawPath(slice.pathSide, slice.paint); - } - canvas.drawPath(mPathSideOutline, mPaintOutline); - - for (Slice slice : mSlices) { - canvas.drawPath(slice.path, slice.paint); - canvas.drawPath(slice.pathOutline, mPaintOutline); - } - canvas.drawPath(mPathOutline, mPaintOutline); - } - - public static int darken(int color) { - float[] hsv = new float[3]; - Color.colorToHSV(color, hsv); - hsv[2] /= 2; - hsv[1] /= 2; - return Color.HSVToColor(hsv); - } - -} |