diff options
Diffstat (limited to 'src/com/android/settings/widget')
5 files changed, 243 insertions, 10 deletions
diff --git a/src/com/android/settings/widget/ChartNetworkSeriesView.java b/src/com/android/settings/widget/ChartNetworkSeriesView.java index 481f7cc..f0ccc1b 100644 --- a/src/com/android/settings/widget/ChartNetworkSeriesView.java +++ b/src/com/android/settings/widget/ChartNetworkSeriesView.java @@ -105,7 +105,7 @@ public class ChartNetworkSeriesView extends View { public void setChartColor(int stroke, int fill, int fillSecondary) { mPaintStroke = new Paint(); - mPaintStroke.setStrokeWidth(6.0f); + mPaintStroke.setStrokeWidth(4.0f * getResources().getDisplayMetrics().density); mPaintStroke.setColor(stroke); mPaintStroke.setStyle(Style.STROKE); mPaintStroke.setAntiAlias(true); @@ -165,7 +165,10 @@ public class ChartNetworkSeriesView extends View { mPathEstimate.reset(); // bail when not enough stats to render - if (mStats == null || mStats.size() < 2) return; + if (mStats == null || mStats.size() < 2) { + invalidate(); + return; + } final int width = getWidth(); final int height = getHeight(); @@ -263,6 +266,8 @@ public class ChartNetworkSeriesView extends View { } mMaxEstimate = totalData; + + invalidate(); } public void setEndTime(long endTime) { diff --git a/src/com/android/settings/widget/ChartSweepView.java b/src/com/android/settings/widget/ChartSweepView.java index d5e8de8..81aeb84 100644 --- a/src/com/android/settings/widget/ChartSweepView.java +++ b/src/com/android/settings/widget/ChartSweepView.java @@ -32,7 +32,6 @@ import android.util.AttributeSet; import android.util.MathUtils; import android.view.MotionEvent; import android.view.View; -import android.widget.FrameLayout; import com.android.settings.R; import com.google.common.base.Preconditions; @@ -41,7 +40,7 @@ import com.google.common.base.Preconditions; * Sweep across a {@link ChartView} at a specific {@link ChartAxis} value, which * a user can drag. */ -public class ChartSweepView extends FrameLayout { +public class ChartSweepView extends View { private Drawable mSweep; private Rect mSweepPadding = new Rect(); @@ -78,7 +77,7 @@ public class ChartSweepView extends FrameLayout { private MotionEvent mTracking; public ChartSweepView(Context context) { - this(context, null, 0); + this(context, null); } public ChartSweepView(Context context, AttributeSet attrs) { @@ -101,8 +100,6 @@ public class ChartSweepView extends FrameLayout { a.recycle(); - setClipToPadding(false); - setClipChildren(false); setWillNotDraw(false); } diff --git a/src/com/android/settings/widget/ChartView.java b/src/com/android/settings/widget/ChartView.java index a5b8b09..e3a658a 100644 --- a/src/com/android/settings/widget/ChartView.java +++ b/src/com/android/settings/widget/ChartView.java @@ -19,12 +19,16 @@ package com.android.settings.widget; import static com.google.common.base.Preconditions.checkNotNull; import android.content.Context; +import android.content.res.TypedArray; import android.graphics.Rect; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; +import android.view.ViewDebug; import android.widget.FrameLayout; +import com.android.settings.R; + /** * Container for two-dimensional chart, drawn with a combination of * {@link ChartGridView}, {@link ChartNetworkSeriesView} and {@link ChartSweepView} @@ -41,6 +45,10 @@ public class ChartView extends FrameLayout { ChartAxis mHoriz; ChartAxis mVert; + @ViewDebug.ExportedProperty + private int mOptimalWidth = -1; + private float mOptimalWidthWeight = 0; + private Rect mContent = new Rect(); public ChartView(Context context) { @@ -54,6 +62,12 @@ public class ChartView extends FrameLayout { public ChartView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.ChartView, defStyle, 0); + setOptimalWidth(a.getDimensionPixelSize(R.styleable.ChartView_optimalWidth, -1), + a.getFloat(R.styleable.ChartView_optimalWidthWeight, 0)); + a.recycle(); + setClipToPadding(false); setClipChildren(false); } @@ -63,6 +77,24 @@ public class ChartView extends FrameLayout { mVert = checkNotNull(vert, "missing vert"); } + public void setOptimalWidth(int optimalWidth, float optimalWidthWeight) { + mOptimalWidth = optimalWidth; + mOptimalWidthWeight = optimalWidthWeight; + requestLayout(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + final int slack = getMeasuredWidth() - mOptimalWidth; + if (mOptimalWidth > 0 && slack > 0) { + final int targetWidth = (int) (mOptimalWidth + (slack * mOptimalWidthWeight)); + widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { mContent.set(getPaddingLeft(), getPaddingTop(), r - l - getPaddingRight(), diff --git a/src/com/android/settings/widget/DataUsageChartView.java b/src/com/android/settings/widget/DataUsageChartView.java index a1c92e1..f6ae5a0 100644 --- a/src/com/android/settings/widget/DataUsageChartView.java +++ b/src/com/android/settings/widget/DataUsageChartView.java @@ -226,8 +226,6 @@ public class DataUsageChartView extends ChartView { mDetailSeries.generatePath(); mGrid.invalidate(); - mSeries.invalidate(); - mDetailSeries.invalidate(); // since we just changed axis, make sweep recalculate its value if (activeSweep != null) { @@ -362,7 +360,6 @@ public class DataUsageChartView extends ChartView { requestLayout(); mSeries.generatePath(); - mSeries.invalidate(); updateVertAxisBounds(null); updateEstimateVisible(); diff --git a/src/com/android/settings/widget/PieChartView.java b/src/com/android/settings/widget/PieChartView.java new file mode 100644 index 0000000..85d45a2 --- /dev/null +++ b/src/com/android/settings/widget/PieChartView.java @@ -0,0 +1,202 @@ +/* + * 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.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.common.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 = true; + + private ArrayList<Slice> mSlices = Lists.newArrayList(); + + private int mOriginAngle; + + private Paint mPaintPrimary = new Paint(); + private Paint mPaintShadow = new Paint(); + + private Path mPathSide = new Path(); + private Path mPathSideShadow = new Path(); + + private Path mPathShadow = new Path(); + + private int mSideWidth; + + public class Slice { + public long value; + + public Path pathPrimary = new Path(); + public Path pathShadow = new Path(); + + public Paint paintPrimary; + + public Slice(long value, int color) { + this.value = value; + this.paintPrimary = 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); + + mPaintPrimary = buildFillPaint(Color.parseColor("#666666"), getResources()); + + mPaintShadow.setColor(Color.BLACK); + mPaintShadow.setStyle(Style.STROKE); + mPaintShadow.setStrokeWidth(3f * getResources().getDisplayMetrics().density); + mPaintShadow.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); + + 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) { + generatePath(); + } + + public void generatePath() { + if (LOGD) Log.d(TAG, "generatePath()"); + + long total = 0; + for (Slice slice : mSlices) { + slice.pathPrimary.reset(); + slice.pathShadow.reset(); + total += slice.value; + } + + mPathSide.reset(); + mPathSideShadow.reset(); + mPathShadow.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); + + mPathSide.addOval(rect, Direction.CW); + mPathSideShadow.addOval(rect, Direction.CW); + mPathShadow.addOval(rect, Direction.CW); + + int startAngle = mOriginAngle; + for (Slice slice : mSlices) { + final int sweepAngle = (int) (slice.value * 360 / total); + + slice.pathPrimary.moveTo(rect.centerX(), rect.centerY()); + slice.pathPrimary.arcTo(rect, startAngle, sweepAngle); + slice.pathPrimary.lineTo(rect.centerX(), rect.centerY()); + + slice.pathShadow.moveTo(rect.centerX(), rect.centerY()); + slice.pathShadow.arcTo(rect, startAngle, 0); + slice.pathShadow.moveTo(rect.centerX(), rect.centerY()); + slice.pathShadow.arcTo(rect, startAngle + sweepAngle, 0); + + startAngle += sweepAngle; + } + + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + + canvas.translate(getWidth() * 0.25f, getHeight() * -0.05f); + canvas.rotate(-40, getWidth() * 0.5f, getHeight()); + canvas.scale(0.7f, 1.0f, getWidth(), getHeight()); + + canvas.save(); + canvas.translate(-mSideWidth, 0); + canvas.drawPath(mPathSide, mPaintPrimary); + canvas.drawPath(mPathSideShadow, mPaintShadow); + canvas.restore(); + + for (Slice slice : mSlices) { + canvas.drawPath(slice.pathPrimary, slice.paintPrimary); + canvas.drawPath(slice.pathShadow, mPaintShadow); + } + canvas.drawPath(mPathShadow, mPaintShadow); + } + + 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); + } + +} |