diff options
author | Jeff Sharkey <jsharkey@android.com> | 2011-06-23 00:39:38 -0700 |
---|---|---|
committer | Jeff Sharkey <jsharkey@android.com> | 2011-06-23 00:39:47 -0700 |
commit | 52c3f4461b806e4f1ce48455ee2ba0ac05dfdab4 (patch) | |
tree | 413297650a61f914f6e212b73af8fb76cacbc3d9 /src/com/android/settings/widget | |
parent | aef3981e86909a6a5b4f6ecab972e43fd77582c1 (diff) | |
download | packages_apps_Settings-52c3f4461b806e4f1ce48455ee2ba0ac05dfdab4.zip packages_apps_Settings-52c3f4461b806e4f1ce48455ee2ba0ac05dfdab4.tar.gz packages_apps_Settings-52c3f4461b806e4f1ce48455ee2ba0ac05dfdab4.tar.bz2 |
Iterate on data usage chart UI.
Switched to inflating chart views from XML, using attributes for
configuration. Start using drawable assets for chart components
instead of manually painting. Include hand-cut assets, and animate
between states when touched to invoke.
Clamp sweeps to valid chart ranges and prepare for sweep labels.
Bug: 4768483, 4598460
Change-Id: Ic660c35bec826eb5e3f6a1dde3cc04d8c437ef2b
Diffstat (limited to 'src/com/android/settings/widget')
7 files changed, 360 insertions, 202 deletions
diff --git a/src/com/android/settings/widget/ChartAxis.java b/src/com/android/settings/widget/ChartAxis.java index 2b21d28..e761202 100644 --- a/src/com/android/settings/widget/ChartAxis.java +++ b/src/com/android/settings/widget/ChartAxis.java @@ -29,6 +29,7 @@ public interface ChartAxis { public long convertToValue(float point); public CharSequence getLabel(long value); + public CharSequence getShortLabel(long value); public float[] getTickPoints(); diff --git a/src/com/android/settings/widget/ChartGridView.java b/src/com/android/settings/widget/ChartGridView.java index be71890..7a83fbf 100644 --- a/src/com/android/settings/widget/ChartGridView.java +++ b/src/com/android/settings/widget/ChartGridView.java @@ -17,12 +17,13 @@ package com.android.settings.widget; import android.content.Context; +import android.content.res.TypedArray; import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Paint.Style; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; import android.view.View; +import com.android.settings.R; import com.google.common.base.Preconditions; /** @@ -31,32 +32,42 @@ import com.google.common.base.Preconditions; */ public class ChartGridView extends View { - private final ChartAxis mHoriz; - private final ChartAxis mVert; + // TODO: eventually teach about drawing chart labels - private final Paint mPaintHoriz; - private final Paint mPaintVert; + private ChartAxis mHoriz; + private ChartAxis mVert; - public ChartGridView(Context context, ChartAxis horiz, ChartAxis vert) { - super(context); + private Drawable mPrimary; + private Drawable mSecondary; + private Drawable mBorder; - mHoriz = Preconditions.checkNotNull(horiz, "missing horiz"); - mVert = Preconditions.checkNotNull(vert, "missing vert"); + public ChartGridView(Context context) { + this(context, null, 0); + } + + public ChartGridView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ChartGridView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); setWillNotDraw(false); - // TODO: convert these colors to resources - mPaintHoriz = new Paint(); - mPaintHoriz.setColor(Color.parseColor("#667bb5")); - mPaintHoriz.setStrokeWidth(2.0f); - mPaintHoriz.setStyle(Style.STROKE); - mPaintHoriz.setAntiAlias(true); - - mPaintVert = new Paint(); - mPaintVert.setColor(Color.parseColor("#28262c")); - mPaintVert.setStrokeWidth(1.0f); - mPaintVert.setStyle(Style.STROKE); - mPaintVert.setAntiAlias(true); + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.ChartGridView, defStyle, 0); + + mPrimary = a.getDrawable(R.styleable.ChartGridView_primaryDrawable); + mSecondary = a.getDrawable(R.styleable.ChartGridView_secondaryDrawable); + mBorder = a.getDrawable(R.styleable.ChartGridView_borderDrawable); + // TODO: eventually read labelColor + + a.recycle(); + } + + void init(ChartAxis horiz, ChartAxis vert) { + mHoriz = Preconditions.checkNotNull(horiz, "missing horiz"); + mVert = Preconditions.checkNotNull(vert, "missing vert"); } @Override @@ -64,16 +75,28 @@ public class ChartGridView extends View { final int width = getWidth(); final int height = getHeight(); + final Drawable secondary = mSecondary; + final int secondaryHeight = mSecondary.getIntrinsicHeight(); + final float[] vertTicks = mVert.getTickPoints(); for (float y : vertTicks) { - canvas.drawLine(0, y, width, y, mPaintVert); + 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) { - canvas.drawLine(x, 0, x, height, mPaintHoriz); + final int right = (int) Math.min(x + primaryWidth, width); + primary.setBounds((int) x, 0, right, height); + primary.draw(canvas); } - canvas.drawRect(0, 0, width, height, mPaintHoriz); + mBorder.setBounds(0, 0, width, height); + mBorder.draw(canvas); } } diff --git a/src/com/android/settings/widget/ChartNetworkSeriesView.java b/src/com/android/settings/widget/ChartNetworkSeriesView.java index 780ca46..0a34565 100644 --- a/src/com/android/settings/widget/ChartNetworkSeriesView.java +++ b/src/com/android/settings/widget/ChartNetworkSeriesView.java @@ -17,6 +17,7 @@ package com.android.settings.widget; import android.content.Context; +import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; @@ -24,9 +25,11 @@ import android.graphics.Paint.Style; import android.graphics.Path; import android.graphics.RectF; import android.net.NetworkStatsHistory; +import android.util.AttributeSet; import android.util.Log; import android.view.View; +import com.android.settings.R; import com.google.common.base.Preconditions; /** @@ -37,35 +40,54 @@ public class ChartNetworkSeriesView extends View { private static final String TAG = "ChartNetworkSeriesView"; private static final boolean LOGD = true; - private final ChartAxis mHoriz; - private final ChartAxis mVert; + private ChartAxis mHoriz; + private ChartAxis mVert; private Paint mPaintStroke; private Paint mPaintFill; - private Paint mPaintFillDisabled; + private Paint mPaintFillSecondary; private NetworkStatsHistory mStats; private Path mPathStroke; private Path mPathFill; - private ChartSweepView mSweep1; - private ChartSweepView mSweep2; + private long mPrimaryLeft; + private long mPrimaryRight; - public ChartNetworkSeriesView(Context context, ChartAxis horiz, ChartAxis vert) { - super(context); + public ChartNetworkSeriesView(Context context) { + this(context, null, 0); + } - mHoriz = Preconditions.checkNotNull(horiz, "missing horiz"); - mVert = Preconditions.checkNotNull(vert, "missing vert"); + public ChartNetworkSeriesView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ChartNetworkSeriesView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.ChartNetworkSeriesView, defStyle, 0); + + final int stroke = a.getColor(R.styleable.ChartNetworkSeriesView_strokeColor, Color.RED); + final int fill = a.getColor(R.styleable.ChartNetworkSeriesView_fillColor, Color.RED); + final int fillSecondary = a.getColor( + R.styleable.ChartNetworkSeriesView_fillColorSecondary, Color.RED); + + setChartColor(stroke, fill, fillSecondary); - setChartColor(Color.parseColor("#24aae1"), Color.parseColor("#c050ade5"), - Color.parseColor("#88566abc")); + a.recycle(); mPathStroke = new Path(); mPathFill = new Path(); } - public void setChartColor(int stroke, int fill, int disabled) { + void init(ChartAxis horiz, ChartAxis vert) { + mHoriz = Preconditions.checkNotNull(horiz, "missing horiz"); + mVert = Preconditions.checkNotNull(vert, "missing vert"); + } + + public void setChartColor(int stroke, int fill, int fillSecondary) { mPaintStroke = new Paint(); mPaintStroke.setStrokeWidth(6.0f); mPaintStroke.setColor(stroke); @@ -77,10 +99,10 @@ public class ChartNetworkSeriesView extends View { mPaintFill.setStyle(Style.FILL); mPaintFill.setAntiAlias(true); - mPaintFillDisabled = new Paint(); - mPaintFillDisabled.setColor(disabled); - mPaintFillDisabled.setStyle(Style.FILL); - mPaintFillDisabled.setAntiAlias(true); + mPaintFillSecondary = new Paint(); + mPaintFillSecondary.setColor(fillSecondary); + mPaintFillSecondary.setStyle(Style.FILL); + mPaintFillSecondary.setAntiAlias(true); } public void bindNetworkStats(NetworkStatsHistory stats) { @@ -90,12 +112,10 @@ public class ChartNetworkSeriesView extends View { mPathFill.reset(); } - public void bindSweepRange(ChartSweepView sweep1, ChartSweepView sweep2) { - // TODO: generalize to support vertical sweeps - // TODO: enforce that both sweeps are along same dimension - - mSweep1 = Preconditions.checkNotNull(sweep1, "missing sweep1"); - mSweep2 = Preconditions.checkNotNull(sweep2, "missing sweep2"); + public void setPrimaryRange(long left, long right) { + mPrimaryLeft = left; + mPrimaryRight = right; + invalidate(); } @Override @@ -168,27 +188,20 @@ public class ChartNetworkSeriesView extends View { @Override protected void onDraw(Canvas canvas) { - - // clip to sweep area - final float sweep1 = mSweep1.getPoint(); - final float sweep2 = mSweep2.getPoint(); - final float sweepLeft = Math.min(sweep1, sweep2); - final float sweepRight = Math.max(sweep1, sweep2); - int save; save = canvas.save(); - canvas.clipRect(0, 0, sweepLeft, getHeight()); - canvas.drawPath(mPathFill, mPaintFillDisabled); + canvas.clipRect(0, 0, mPrimaryLeft, getHeight()); + canvas.drawPath(mPathFill, mPaintFillSecondary); canvas.restoreToCount(save); save = canvas.save(); - canvas.clipRect(sweepRight, 0, getWidth(), getHeight()); - canvas.drawPath(mPathFill, mPaintFillDisabled); + canvas.clipRect(mPrimaryRight, 0, getWidth(), getHeight()); + canvas.drawPath(mPathFill, mPaintFillSecondary); canvas.restoreToCount(save); save = canvas.save(); - canvas.clipRect(sweepLeft, 0, sweepRight, getHeight()); + canvas.clipRect(mPrimaryLeft, 0, mPrimaryRight, 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 788caad..881fde4 100644 --- a/src/com/android/settings/widget/ChartSweepView.java +++ b/src/com/android/settings/widget/ChartSweepView.java @@ -17,63 +17,79 @@ package com.android.settings.widget; import android.content.Context; +import android.content.res.TypedArray; import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.DashPathEffect; -import android.graphics.Paint; -import android.graphics.Paint.Style; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +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; /** * Sweep across a {@link ChartView} at a specific {@link ChartAxis} value, which * a user can drag. */ -public class ChartSweepView extends View { +public class ChartSweepView extends FrameLayout { - private final Paint mPaintSweep; - private final Paint mPaintSweepDisabled; - private final Paint mPaintShadow; + // TODO: paint label when requested - private final ChartAxis mAxis; + private Drawable mSweep; + private int mFollowAxis; + private boolean mShowLabel; + + private ChartAxis mAxis; private long mValue; + public static final int HORIZONTAL = 0; + public static final int VERTICAL = 1; + public interface OnSweepListener { public void onSweep(ChartSweepView sweep, boolean sweepDone); } private OnSweepListener mListener; - - private boolean mHorizontal; private MotionEvent mTracking; - public ChartSweepView(Context context, ChartAxis axis, long value, int color) { - super(context); + public ChartSweepView(Context context) { + this(context, null, 0); + } - mAxis = Preconditions.checkNotNull(axis, "missing axis"); - mValue = value; + public ChartSweepView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } - mPaintSweep = new Paint(); - mPaintSweep.setColor(color); - mPaintSweep.setStrokeWidth(3.0f); - mPaintSweep.setStyle(Style.FILL_AND_STROKE); - mPaintSweep.setAntiAlias(true); + public ChartSweepView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); - mPaintSweepDisabled = new Paint(); - mPaintSweepDisabled.setColor(color); - mPaintSweepDisabled.setStrokeWidth(1.5f); - mPaintSweepDisabled.setStyle(Style.FILL_AND_STROKE); - mPaintSweepDisabled.setPathEffect(new DashPathEffect(new float[] { 5, 5 }, 0)); - mPaintSweepDisabled.setAntiAlias(true); + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.ChartSweepView, defStyle, 0); - mPaintShadow = new Paint(); - mPaintShadow.setColor(Color.BLACK); - mPaintShadow.setStrokeWidth(6.0f); - mPaintShadow.setStyle(Style.FILL_AND_STROKE); - mPaintShadow.setAntiAlias(true); + setSweepDrawable(a.getDrawable(R.styleable.ChartSweepView_sweepDrawable)); + setFollowAxis(a.getInt(R.styleable.ChartSweepView_followAxis, -1)); + setShowLabel(a.getBoolean(R.styleable.ChartSweepView_showLabel, false)); + + a.recycle(); + + setClipToPadding(false); + setClipChildren(false); + setWillNotDraw(false); + } + + void init(ChartAxis axis) { + mAxis = Preconditions.checkNotNull(axis, "missing axis"); + } + public int getFollowAxis() { + return mFollowAxis; + } + + public void getExtraMargins(Rect rect) { + mSweep.getPadding(rect); } public void addOnSweepListener(OnSweepListener listener) { @@ -86,6 +102,56 @@ public class ChartSweepView extends View { } } + public void setSweepDrawable(Drawable sweep) { + if (mSweep != null) { + mSweep.setCallback(null); + unscheduleDrawable(mSweep); + } + + if (sweep != null) { + sweep.setCallback(this); + if (sweep.isStateful()) { + sweep.setState(getDrawableState()); + } + sweep.setVisible(getVisibility() == VISIBLE, false); + mSweep = sweep; + } else { + mSweep = null; + } + + invalidate(); + } + + public void setFollowAxis(int followAxis) { + mFollowAxis = followAxis; + } + + public void setShowLabel(boolean showLabel) { + mShowLabel = showLabel; + invalidate(); + } + + @Override + public void jumpDrawablesToCurrentState() { + super.jumpDrawablesToCurrentState(); + if (mSweep != null) { + mSweep.jumpToCurrentState(); + } + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + if (mSweep != null) { + mSweep.setVisible(visibility == VISIBLE, false); + } + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return who == mSweep || super.verifyDrawable(who); + } + public ChartAxis getAxis() { return mAxis; } @@ -115,14 +181,24 @@ public class ChartSweepView extends View { case MotionEvent.ACTION_MOVE: { getParent().requestDisallowInterceptTouchEvent(true); - if (mHorizontal) { - setTranslationY(event.getRawY() - mTracking.getRawY()); + if (mFollowAxis == VERTICAL) { + final float chartHeight = parent.getHeight() - parent.getPaddingTop() + - parent.getPaddingBottom(); + final float translationY = MathUtils.constrain( + event.getRawY() - mTracking.getRawY(), -getTop(), + chartHeight - getTop()); + setTranslationY(translationY); final float point = (getTop() + getTranslationY() + (getHeight() / 2)) - parent.getPaddingTop(); mValue = mAxis.convertToValue(point); dispatchOnSweep(false); } else { - setTranslationX(event.getRawX() - mTracking.getRawX()); + final float chartWidth = parent.getWidth() - parent.getPaddingLeft() + - parent.getPaddingRight(); + final float translationX = MathUtils.constrain( + event.getRawX() - mTracking.getRawX(), -getLeft(), + chartWidth - getLeft()); + setTranslationX(translationX); final float point = (getLeft() + getTranslationX() + (getWidth() / 2)) - parent.getPaddingLeft(); mValue = mAxis.convertToValue(point); @@ -145,40 +221,25 @@ public class ChartSweepView extends View { } @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + if (mSweep.isStateful()) { + mSweep.setState(getDrawableState()); + } + } + + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // need at least 50px in each direction for grippies - // TODO: provide this value through params - setMeasuredDimension(50, 50); + setMeasuredDimension(mSweep.getIntrinsicWidth(), mSweep.getIntrinsicHeight()); } @Override protected void onDraw(Canvas canvas) { - - // draw line across larger dimension final int width = getWidth(); final int height = getHeight(); - mHorizontal = width > height; - - final Paint linePaint = isEnabled() ? mPaintSweep : mPaintSweepDisabled; - - if (mHorizontal) { - final int centerY = height / 2; - final int endX = width - height; - - canvas.drawLine(0, centerY, endX, centerY, mPaintShadow); - canvas.drawLine(0, centerY, endX, centerY, linePaint); - canvas.drawCircle(endX, centerY, 4.0f, mPaintShadow); - canvas.drawCircle(endX, centerY, 4.0f, mPaintSweep); - } else { - final int centerX = width / 2; - final int endY = height - width; - - canvas.drawLine(centerX, 0, centerX, endY, mPaintShadow); - canvas.drawLine(centerX, 0, centerX, endY, linePaint); - canvas.drawCircle(centerX, endY, 4.0f, mPaintShadow); - canvas.drawCircle(centerX, endY, 4.0f, mPaintSweep); - } + mSweep.setBounds(0, 0, width, height); + mSweep.draw(canvas); } } diff --git a/src/com/android/settings/widget/ChartView.java b/src/com/android/settings/widget/ChartView.java index 3e5fc50..d762631 100644 --- a/src/com/android/settings/widget/ChartView.java +++ b/src/com/android/settings/widget/ChartView.java @@ -16,13 +16,11 @@ package com.android.settings.widget; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static com.google.common.base.Preconditions.checkNotNull; import android.content.Context; import android.graphics.Rect; -import android.util.Log; +import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.widget.FrameLayout; @@ -38,21 +36,31 @@ public class ChartView extends FrameLayout { // TODO: extend something that supports two-dimensional scrolling - final ChartAxis mHoriz; - final ChartAxis mVert; + ChartAxis mHoriz; + ChartAxis mVert; private Rect mContent = new Rect(); - public ChartView(Context context, ChartAxis horiz, ChartAxis vert) { - super(context); + public ChartView(Context context) { + this(context, null, 0); + } - mHoriz = checkNotNull(horiz, "missing horiz"); - mVert = checkNotNull(vert, "missing vert"); + public ChartView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ChartView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); setClipToPadding(false); setClipChildren(false); } + void init(ChartAxis horiz, ChartAxis vert) { + mHoriz = checkNotNull(horiz, "missing horiz"); + mVert = checkNotNull(vert, "missing vert"); + } + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { mContent.set(getPaddingLeft(), getPaddingTop(), r - l - getPaddingRight(), @@ -66,6 +74,7 @@ public class ChartView extends FrameLayout { final Rect parentRect = new Rect(); final Rect childRect = new Rect(); + final Rect extraMargins = new Rect(); for (int i = 0; i < getChildCount(); i++) { final View child = getChildAt(i); @@ -82,23 +91,22 @@ public class ChartView extends FrameLayout { } else if (child instanceof ChartSweepView) { // sweep is always placed along specific dimension final ChartSweepView sweep = (ChartSweepView) child; - final ChartAxis axis = sweep.getAxis(); final float point = sweep.getPoint(); + sweep.getExtraMargins(extraMargins); - if (axis == mHoriz) { + if (sweep.getFollowAxis() == ChartSweepView.HORIZONTAL) { parentRect.left = parentRect.right = (int) point + getPaddingLeft(); - parentRect.bottom += child.getMeasuredWidth(); + parentRect.top -= extraMargins.top; + parentRect.bottom += extraMargins.bottom; Gravity.apply(params.gravity, child.getMeasuredWidth(), parentRect.height(), parentRect, childRect); - } else if (axis == mVert) { + } else { parentRect.top = parentRect.bottom = (int) point + getPaddingTop(); - parentRect.right += child.getMeasuredHeight(); + parentRect.left -= extraMargins.left; + parentRect.right += extraMargins.right; Gravity.apply(params.gravity, parentRect.width(), child.getMeasuredHeight(), parentRect, childRect); - - } else { - throw new IllegalStateException("unexpected axis"); } } @@ -106,16 +114,4 @@ public class ChartView extends FrameLayout { } } - public static LayoutParams buildChartParams() { - final LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT); - params.gravity = Gravity.LEFT | Gravity.BOTTOM; - return params; - } - - public static LayoutParams buildSweepParams() { - final LayoutParams params = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT); - params.gravity = Gravity.CENTER; - return params; - } - } diff --git a/src/com/android/settings/widget/DataUsageChartView.java b/src/com/android/settings/widget/DataUsageChartView.java index 6c62fa8..1c76291 100644 --- a/src/com/android/settings/widget/DataUsageChartView.java +++ b/src/com/android/settings/widget/DataUsageChartView.java @@ -17,12 +17,14 @@ package com.android.settings.widget; import android.content.Context; -import android.graphics.Color; import android.net.NetworkPolicy; import android.net.NetworkStatsHistory; import android.text.format.DateUtils; +import android.util.AttributeSet; +import android.view.MotionEvent; import android.view.View; +import com.android.settings.R; import com.android.settings.widget.ChartSweepView.OnSweepListener; /** @@ -35,13 +37,16 @@ public class DataUsageChartView extends ChartView { private static final long MB_IN_BYTES = KB_IN_BYTES * 1024; private static final long GB_IN_BYTES = MB_IN_BYTES * 1024; + // TODO: enforce that sweeps cant cross each other + // TODO: limit sweeps at graph boundaries + + private ChartGridView mGrid; private ChartNetworkSeriesView mSeries; - // TODO: limit sweeps at graph boundaries - private ChartSweepView mSweepTime1; - private ChartSweepView mSweepTime2; - private ChartSweepView mSweepDataWarn; - private ChartSweepView mSweepDataLimit; + private ChartSweepView mSweepLeft; + private ChartSweepView mSweepRight; + private ChartSweepView mSweepWarning; + private ChartSweepView mSweepLimit; public interface DataUsageChartListener { public void onInspectRangeChanged(); @@ -51,46 +56,58 @@ public class DataUsageChartView extends ChartView { private DataUsageChartListener mListener; - private static ChartAxis buildTimeAxis() { - return new TimeAxis(); + public DataUsageChartView(Context context) { + this(context, null, 0); } - private static ChartAxis buildDataAxis() { - return new InvertedChartAxis(new DataAxis()); + public DataUsageChartView(Context context, AttributeSet attrs) { + this(context, attrs, 0); } - public DataUsageChartView(Context context) { - super(context, buildTimeAxis(), buildDataAxis()); - setPadding(20, 20, 20, 20); - - addView(new ChartGridView(context, mHoriz, mVert), buildChartParams()); + public DataUsageChartView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(new TimeAxis(), new InvertedChartAxis(new DataAxis())); + } - mSeries = new ChartNetworkSeriesView(context, mHoriz, mVert); - addView(mSeries, buildChartParams()); + @Override + protected void onFinishInflate() { + super.onFinishInflate(); - mSweepTime1 = new ChartSweepView(context, mHoriz, 0L, Color.parseColor("#ffffff")); - mSweepTime2 = new ChartSweepView(context, mHoriz, 0L, Color.parseColor("#ffffff")); - mSweepDataWarn = new ChartSweepView(context, mVert, 0L, Color.parseColor("#f7931d")); - mSweepDataLimit = new ChartSweepView(context, mVert, 0L, Color.parseColor("#be1d2c")); + mGrid = (ChartGridView) findViewById(R.id.grid); + mSeries = (ChartNetworkSeriesView) findViewById(R.id.series); - addView(mSweepTime1, buildSweepParams()); - addView(mSweepTime2, buildSweepParams()); - addView(mSweepDataWarn, buildSweepParams()); - addView(mSweepDataLimit, buildSweepParams()); + 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); - mSeries.bindSweepRange(mSweepTime1, mSweepTime2); + mSweepLeft.addOnSweepListener(mSweepListener); + mSweepRight.addOnSweepListener(mSweepListener); + mSweepWarning.addOnSweepListener(mWarningListener); + mSweepLimit.addOnSweepListener(mLimitListener); - mSweepDataWarn.addOnSweepListener(mWarningListener); - mSweepDataLimit.addOnSweepListener(mLimitListener); + // tell everyone about our axis + mGrid.init(mHoriz, mVert); + mSeries.init(mHoriz, mVert); + mSweepLeft.init(mHoriz); + mSweepRight.init(mHoriz); + mSweepWarning.init(mVert); + mSweepLimit.init(mVert); - mSweepTime1.addOnSweepListener(mSweepListener); - mSweepTime2.addOnSweepListener(mSweepListener); + setActivated(false); + } - mSweepDataWarn.setVisibility(View.INVISIBLE); - mSweepDataLimit.setVisibility(View.INVISIBLE); + @Override + public void setActivated(boolean activated) { + super.setActivated(activated); + mSweepLeft.setEnabled(activated); + mSweepRight.setEnabled(activated); + mSweepWarning.setEnabled(activated); + mSweepLimit.setEnabled(activated); } + @Deprecated public void setChartColor(int stroke, int fill, int disabled) { mSeries.setChartColor(stroke, fill, disabled); } @@ -105,36 +122,46 @@ public class DataUsageChartView extends ChartView { public void bindNetworkPolicy(NetworkPolicy policy) { if (policy == null) { - mSweepDataLimit.setVisibility(View.INVISIBLE); - mSweepDataWarn.setVisibility(View.INVISIBLE); + mSweepLimit.setVisibility(View.INVISIBLE); + mSweepWarning.setVisibility(View.INVISIBLE); return; } if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) { - mSweepDataLimit.setVisibility(View.VISIBLE); - mSweepDataLimit.setValue(policy.limitBytes); - mSweepDataLimit.setEnabled(true); + mSweepLimit.setVisibility(View.VISIBLE); + mSweepLimit.setValue(policy.limitBytes); + mSweepLimit.setEnabled(true); } else { // TODO: set limit default based on axis maximum - mSweepDataLimit.setVisibility(View.VISIBLE); - mSweepDataLimit.setValue(5 * GB_IN_BYTES); - mSweepDataLimit.setEnabled(false); + mSweepLimit.setVisibility(View.VISIBLE); + mSweepLimit.setValue(5 * GB_IN_BYTES); + mSweepLimit.setEnabled(false); } if (policy.warningBytes != NetworkPolicy.WARNING_DISABLED) { - mSweepDataWarn.setVisibility(View.VISIBLE); - mSweepDataWarn.setValue(policy.warningBytes); + mSweepWarning.setVisibility(View.VISIBLE); + mSweepWarning.setValue(policy.warningBytes); } else { - mSweepDataWarn.setVisibility(View.INVISIBLE); + mSweepWarning.setVisibility(View.INVISIBLE); } requestLayout(); + + // TODO: eventually remove this; was to work around lack of sweep clamping + if (policy.limitBytes < -1 || policy.limitBytes > 5 * GB_IN_BYTES) { + policy.limitBytes = 5 * GB_IN_BYTES; + mLimitListener.onSweep(mSweepLimit, true); + } + if (policy.warningBytes < -1 || policy.warningBytes > 5 * GB_IN_BYTES) { + policy.warningBytes = 4 * GB_IN_BYTES; + mWarningListener.onSweep(mSweepWarning, true); + } + } private OnSweepListener mSweepListener = new OnSweepListener() { public void onSweep(ChartSweepView sweep, boolean sweepDone) { - // always update graph clip region - mSeries.invalidate(); + mSeries.setPrimaryRange(mSweepLeft.getValue(), mSweepRight.getValue()); // update detail list only when done sweeping if (sweepDone && mListener != null) { @@ -159,24 +186,39 @@ public class DataUsageChartView extends ChartView { } }; + @Override + public boolean onTouchEvent(MotionEvent event) { + if (isActivated()) return false; + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: { + return true; + } + case MotionEvent.ACTION_UP: { + setActivated(true); + return true; + } + default: { + return false; + } + } + } + /** * Return current inspection range (start and end time) based on internal * {@link ChartSweepView} positions. */ public long[] getInspectRange() { - final long sweep1 = mSweepTime1.getValue(); - final long sweep2 = mSweepTime2.getValue(); - final long start = Math.min(sweep1, sweep2); - final long end = Math.max(sweep1, sweep2); + final long start = mSweepLeft.getValue(); + final long end = mSweepRight.getValue(); return new long[] { start, end }; } public long getWarningBytes() { - return mSweepDataWarn.getValue(); + return mSweepWarning.getValue(); } public long getLimitBytes() { - return mSweepDataLimit.getValue(); + return mSweepLimit.getValue(); } /** @@ -192,8 +234,9 @@ public class DataUsageChartView extends ChartView { final long sweepMax = Math.min(end, dataBoundary); final long sweepMin = Math.max(start, (sweepMax - DateUtils.WEEK_IN_MILLIS)); - mSweepTime1.setValue(sweepMin); - mSweepTime2.setValue(sweepMax); + mSweepLeft.setValue(sweepMin); + mSweepRight.setValue(sweepMax); + mSeries.setPrimaryRange(sweepMin, sweepMax); requestLayout(); mSeries.generatePath(); @@ -240,6 +283,12 @@ public class DataUsageChartView extends ChartView { } /** {@inheritDoc} */ + public CharSequence getShortLabel(long value) { + // TODO: convert to string + return Long.toString(value); + } + + /** {@inheritDoc} */ public float[] getTickPoints() { // tick mark for every week final int tickCount = (int) ((mMax - mMin) / TICK_INTERVAL); @@ -299,6 +348,16 @@ public class DataUsageChartView extends ChartView { /** {@inheritDoc} */ public CharSequence getLabel(long value) { + + // TODO: use exploded string here + + + // TODO: convert to string + return Long.toString(value); + } + + /** {@inheritDoc} */ + public CharSequence getShortLabel(long value) { // TODO: convert to string return Long.toString(value); } diff --git a/src/com/android/settings/widget/InvertedChartAxis.java b/src/com/android/settings/widget/InvertedChartAxis.java index e7e7893..a30d24c 100644 --- a/src/com/android/settings/widget/InvertedChartAxis.java +++ b/src/com/android/settings/widget/InvertedChartAxis.java @@ -54,6 +54,11 @@ public class InvertedChartAxis implements ChartAxis { } /** {@inheritDoc} */ + public CharSequence getShortLabel(long value) { + return mWrapped.getShortLabel(value); + } + + /** {@inheritDoc} */ public float[] getTickPoints() { final float[] points = mWrapped.getTickPoints(); for (int i = 0; i < points.length; i++) { |