summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/widget
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/settings/widget')
-rw-r--r--src/com/android/settings/widget/ChartAxis.java1
-rw-r--r--src/com/android/settings/widget/ChartNetworkSeriesView.java12
-rw-r--r--src/com/android/settings/widget/ChartSweepView.java23
-rw-r--r--src/com/android/settings/widget/ChartView.java9
-rw-r--r--src/com/android/settings/widget/DataUsageChartView.java276
-rw-r--r--src/com/android/settings/widget/InvertedChartAxis.java5
6 files changed, 318 insertions, 8 deletions
diff --git a/src/com/android/settings/widget/ChartAxis.java b/src/com/android/settings/widget/ChartAxis.java
index 0b77ac6..2b21d28 100644
--- a/src/com/android/settings/widget/ChartAxis.java
+++ b/src/com/android/settings/widget/ChartAxis.java
@@ -22,6 +22,7 @@ package com.android.settings.widget;
*/
public interface ChartAxis {
+ public void setBounds(long min, long max);
public void setSize(float size);
public float convertToPoint(long value);
diff --git a/src/com/android/settings/widget/ChartNetworkSeriesView.java b/src/com/android/settings/widget/ChartNetworkSeriesView.java
index 1008761..d0a2742 100644
--- a/src/com/android/settings/widget/ChartNetworkSeriesView.java
+++ b/src/com/android/settings/widget/ChartNetworkSeriesView.java
@@ -35,7 +35,7 @@ import com.google.common.base.Preconditions;
*/
public class ChartNetworkSeriesView extends View {
private static final String TAG = "ChartNetworkSeriesView";
- private static final boolean LOGD = false;
+ private static final boolean LOGD = true;
private final ChartAxis mHoriz;
private final ChartAxis mVert;
@@ -80,6 +80,9 @@ public class ChartNetworkSeriesView extends View {
public void bindNetworkStats(NetworkStatsHistory stats) {
mStats = stats;
+
+ mPathStroke.reset();
+ mPathFill.reset();
}
public void bindSweepRange(ChartSweepView sweep1, ChartSweepView sweep2) {
@@ -99,7 +102,9 @@ public class ChartNetworkSeriesView extends View {
* Erase any existing {@link Path} and generate series outline based on
* currently bound {@link NetworkStatsHistory} data.
*/
- private void generatePath() {
+ public void generatePath() {
+ if (LOGD) Log.d(TAG, "generatePath()");
+
mPathStroke.reset();
mPathFill.reset();
@@ -114,6 +119,9 @@ public class ChartNetworkSeriesView extends View {
float lastX = 0;
float lastY = 0;
+ // TODO: count fractional data from first bucket crossing start;
+ // currently it only accepts first full bucket.
+
long totalData = 0;
for (int i = 0; i < mStats.bucketCount; i++) {
diff --git a/src/com/android/settings/widget/ChartSweepView.java b/src/com/android/settings/widget/ChartSweepView.java
index e3130ce..788caad 100644
--- a/src/com/android/settings/widget/ChartSweepView.java
+++ b/src/com/android/settings/widget/ChartSweepView.java
@@ -19,6 +19,7 @@ package com.android.settings.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.view.MotionEvent;
@@ -33,6 +34,7 @@ import com.google.common.base.Preconditions;
public class ChartSweepView extends View {
private final Paint mPaintSweep;
+ private final Paint mPaintSweepDisabled;
private final Paint mPaintShadow;
private final ChartAxis mAxis;
@@ -59,6 +61,13 @@ public class ChartSweepView extends View {
mPaintSweep.setStyle(Style.FILL_AND_STROKE);
mPaintSweep.setAntiAlias(true);
+ 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);
+
mPaintShadow = new Paint();
mPaintShadow.setColor(Color.BLACK);
mPaintShadow.setStrokeWidth(6.0f);
@@ -81,6 +90,10 @@ public class ChartSweepView extends View {
return mAxis;
}
+ public void setValue(long value) {
+ mValue = value;
+ }
+
public long getValue() {
return mValue;
}
@@ -91,6 +104,8 @@ public class ChartSweepView extends View {
@Override
public boolean onTouchEvent(MotionEvent event) {
+ if (!isEnabled()) return false;
+
final View parent = (View) getParent();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
@@ -98,6 +113,8 @@ public class ChartSweepView extends View {
return true;
}
case MotionEvent.ACTION_MOVE: {
+ getParent().requestDisallowInterceptTouchEvent(true);
+
if (mHorizontal) {
setTranslationY(event.getRawY() - mTracking.getRawY());
final float point = (getTop() + getTranslationY() + (getHeight() / 2))
@@ -143,12 +160,14 @@ public class ChartSweepView extends View {
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, mPaintSweep);
+ canvas.drawLine(0, centerY, endX, centerY, linePaint);
canvas.drawCircle(endX, centerY, 4.0f, mPaintShadow);
canvas.drawCircle(endX, centerY, 4.0f, mPaintSweep);
} else {
@@ -156,7 +175,7 @@ public class ChartSweepView extends View {
final int endY = height - width;
canvas.drawLine(centerX, 0, centerX, endY, mPaintShadow);
- canvas.drawLine(centerX, 0, centerX, endY, mPaintSweep);
+ canvas.drawLine(centerX, 0, centerX, endY, linePaint);
canvas.drawCircle(centerX, endY, 4.0f, mPaintShadow);
canvas.drawCircle(centerX, endY, 4.0f, mPaintSweep);
}
diff --git a/src/com/android/settings/widget/ChartView.java b/src/com/android/settings/widget/ChartView.java
index bcb54f0..3e5fc50 100644
--- a/src/com/android/settings/widget/ChartView.java
+++ b/src/com/android/settings/widget/ChartView.java
@@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import android.content.Context;
import android.graphics.Rect;
+import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
@@ -37,8 +38,8 @@ public class ChartView extends FrameLayout {
// TODO: extend something that supports two-dimensional scrolling
- private final ChartAxis mHoriz;
- private final ChartAxis mVert;
+ final ChartAxis mHoriz;
+ final ChartAxis mVert;
private Rect mContent = new Rect();
@@ -54,8 +55,8 @@ public class ChartView extends FrameLayout {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
- mContent.set(l + getPaddingLeft(), t + getPaddingTop(), r - getPaddingRight(),
- b - getPaddingBottom());
+ mContent.set(getPaddingLeft(), getPaddingTop(), r - l - getPaddingRight(),
+ b - t - getPaddingBottom());
final int width = mContent.width();
final int height = mContent.height();
diff --git a/src/com/android/settings/widget/DataUsageChartView.java b/src/com/android/settings/widget/DataUsageChartView.java
new file mode 100644
index 0000000..defa953
--- /dev/null
+++ b/src/com/android/settings/widget/DataUsageChartView.java
@@ -0,0 +1,276 @@
+/*
+ * 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.graphics.Color;
+import android.net.NetworkPolicy;
+import android.net.NetworkStatsHistory;
+import android.text.format.DateUtils;
+
+import com.android.settings.widget.ChartSweepView.OnSweepListener;
+
+/**
+ * Specific {@link ChartView} that displays {@link ChartNetworkSeriesView} along
+ * with {@link ChartSweepView} for inspection ranges and warning/limits.
+ */
+public class DataUsageChartView extends ChartView {
+
+ private static final long KB_IN_BYTES = 1024;
+ private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
+ private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
+
+ private ChartNetworkSeriesView mSeries;
+
+ // TODO: limit sweeps at graph boundaries
+ private ChartSweepView mSweepTime1;
+ private ChartSweepView mSweepTime2;
+ private ChartSweepView mSweepDataWarn;
+ private ChartSweepView mSweepDataLimit;
+
+ public interface DataUsageChartListener {
+ public void onInspectRangeChanged();
+ public void onLimitsChanged();
+ }
+
+ private DataUsageChartListener mListener;
+
+ private static ChartAxis buildTimeAxis() {
+ return new TimeAxis();
+ }
+
+ private static ChartAxis buildDataAxis() {
+ return new InvertedChartAxis(new DataAxis());
+ }
+
+ public DataUsageChartView(Context context) {
+ super(context, buildTimeAxis(), buildDataAxis());
+ setPadding(20, 20, 20, 20);
+
+ addView(new ChartGridView(context, mHoriz, mVert), buildChartParams());
+
+ mSeries = new ChartNetworkSeriesView(context, mHoriz, mVert);
+ addView(mSeries, buildChartParams());
+
+ 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"));
+
+ addView(mSweepTime1, buildSweepParams());
+ addView(mSweepTime2, buildSweepParams());
+ addView(mSweepDataWarn, buildSweepParams());
+ addView(mSweepDataLimit, buildSweepParams());
+
+ mSeries.bindSweepRange(mSweepTime1, mSweepTime2);
+
+ mSweepTime1.addOnSweepListener(mSweepListener);
+ mSweepTime2.addOnSweepListener(mSweepListener);
+
+ }
+
+ public void setListener(DataUsageChartListener listener) {
+ mListener = listener;
+ }
+
+ public void bindNetworkStats(NetworkStatsHistory stats) {
+ mSeries.bindNetworkStats(stats);
+ }
+
+ public void bindNetworkPolicy(NetworkPolicy policy) {
+ if (policy.limitBytes != -1) {
+ mSweepDataLimit.setValue(policy.limitBytes);
+ mSweepDataLimit.setEnabled(true);
+ } else {
+ mSweepDataLimit.setValue(5 * GB_IN_BYTES);
+ mSweepDataLimit.setEnabled(false);
+ }
+
+ mSweepDataWarn.setValue(policy.warningBytes);
+ }
+
+ private OnSweepListener mSweepListener = new OnSweepListener() {
+ public void onSweep(ChartSweepView sweep, boolean sweepDone) {
+ // always update graph clip region
+ mSeries.invalidate();
+
+ // update detail list only when done sweeping
+ if (sweepDone && mListener != null) {
+ mListener.onInspectRangeChanged();
+ }
+ }
+ };
+
+ /**
+ * 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);
+ return new long[] { start, end };
+ }
+
+ public long getWarningBytes() {
+ return mSweepDataWarn.getValue();
+ }
+
+ public long getLimitBytes() {
+ return mSweepDataLimit.getValue();
+ }
+
+ /**
+ * Set the exact time range that should be displayed, updating how
+ * {@link ChartNetworkSeriesView} paints. Moves inspection ranges to be the
+ * last "week" of available data, without triggering listener events.
+ */
+ public void setVisibleRange(long start, long end, long dataBoundary) {
+ mHoriz.setBounds(start, end);
+
+ // default sweeps to last week of data
+ final long halfRange = (end + start) / 2;
+ final long sweepMax = Math.min(end, dataBoundary);
+ final long sweepMin = Math.max(start, (sweepMax - DateUtils.WEEK_IN_MILLIS));
+
+ mSweepTime1.setValue(sweepMin);
+ mSweepTime2.setValue(sweepMax);
+
+ requestLayout();
+ mSeries.generatePath();
+ }
+
+ public static class TimeAxis implements ChartAxis {
+ private static final long TICK_INTERVAL = DateUtils.DAY_IN_MILLIS * 7;
+
+ private long mMin;
+ private long mMax;
+ private float mSize;
+
+ public TimeAxis() {
+ final long currentTime = System.currentTimeMillis();
+ setBounds(currentTime - DateUtils.DAY_IN_MILLIS * 30, currentTime);
+ }
+
+ /** {@inheritDoc} */
+ public void setBounds(long min, long max) {
+ mMin = min;
+ mMax = max;
+ }
+
+ /** {@inheritDoc} */
+ public void setSize(float size) {
+ this.mSize = size;
+ }
+
+ /** {@inheritDoc} */
+ public float convertToPoint(long value) {
+ return (mSize * (value - mMin)) / (mMax - mMin);
+ }
+
+ /** {@inheritDoc} */
+ public long convertToValue(float point) {
+ return (long) (mMin + ((point * (mMax - mMin)) / mSize));
+ }
+
+ /** {@inheritDoc} */
+ public CharSequence getLabel(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);
+ final float[] tickPoints = new float[tickCount];
+ for (int i = 0; i < tickCount; i++) {
+ tickPoints[i] = convertToPoint(mMax - (TICK_INTERVAL * i));
+ }
+ return tickPoints;
+ }
+ }
+
+ public static class DataAxis implements ChartAxis {
+ private long mMin;
+ private long mMax;
+ private long mMinLog;
+ private long mMaxLog;
+ private float mSize;
+
+ public DataAxis() {
+ // TODO: adapt ranges to show when history >5GB, and handle 4G
+ // interfaces with higher limits.
+ setBounds(1 * MB_IN_BYTES, 5 * GB_IN_BYTES);
+ }
+
+ /** {@inheritDoc} */
+ public void setBounds(long min, long max) {
+ mMin = min;
+ mMax = max;
+ mMinLog = (long) Math.log(mMin);
+ mMaxLog = (long) Math.log(mMax);
+ }
+
+ /** {@inheritDoc} */
+ public void setSize(float size) {
+ this.mSize = size;
+ }
+
+ /** {@inheritDoc} */
+ public float convertToPoint(long value) {
+ return (mSize * (value - mMin)) / (mMax - mMin);
+
+ // TODO: finish tweaking log scale
+// if (value > mMin) {
+// return (float) ((mSize * (Math.log(value) - mMinLog)) / (mMaxLog - mMinLog));
+// } else {
+// return 0;
+// }
+ }
+
+ /** {@inheritDoc} */
+ public long convertToValue(float point) {
+ return (long) (mMin + ((point * (mMax - mMin)) / mSize));
+
+ // TODO: finish tweaking log scale
+// return (long) Math.pow(Math.E, (mMinLog + ((point * (mMaxLog - mMinLog)) / mSize)));
+ }
+
+ /** {@inheritDoc} */
+ public CharSequence getLabel(long value) {
+ // TODO: convert to string
+ return Long.toString(value);
+ }
+
+ /** {@inheritDoc} */
+ public float[] getTickPoints() {
+ final float[] tickPoints = new float[16];
+
+ long value = mMax;
+ float mult = 0.8f;
+ for (int i = 0; i < tickPoints.length; i++) {
+ tickPoints[i] = convertToPoint(value);
+ value = (long) (value * mult);
+ mult *= 0.9;
+ }
+ return tickPoints;
+ }
+ }
+
+}
diff --git a/src/com/android/settings/widget/InvertedChartAxis.java b/src/com/android/settings/widget/InvertedChartAxis.java
index 2bda320..e7e7893 100644
--- a/src/com/android/settings/widget/InvertedChartAxis.java
+++ b/src/com/android/settings/widget/InvertedChartAxis.java
@@ -28,6 +28,11 @@ public class InvertedChartAxis implements ChartAxis {
}
/** {@inheritDoc} */
+ public void setBounds(long min, long max) {
+ mWrapped.setBounds(min, max);
+ }
+
+ /** {@inheritDoc} */
public void setSize(float size) {
mSize = size;
mWrapped.setSize(size);