summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/widget
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2011-06-10 13:31:21 -0700
committerJeff Sharkey <jsharkey@android.com>2011-06-10 16:17:21 -0700
commit8a50364a71e7c261b54840210f8bacff5abecb34 (patch)
tree6ddcd421fd26829af3c6b0a6bcd656c6986dc182 /src/com/android/settings/widget
parent86432504d356e3de7e63b48251f653245bcafd32 (diff)
downloadpackages_apps_Settings-8a50364a71e7c261b54840210f8bacff5abecb34.zip
packages_apps_Settings-8a50364a71e7c261b54840210f8bacff5abecb34.tar.gz
packages_apps_Settings-8a50364a71e7c261b54840210f8bacff5abecb34.tar.bz2
Iterating on data usage; tabs, scrolling, cycles.
Added ActionBar items to control complexity of data surfaced; checked state causes tabs to be shown/hidden for "Mobile", "2G-3G", "4G", and "Wi-Fi" network templates. Loading historical stats and policy from system services based on selected tab. Change entire body under tabs to scroll, treating network options and chart as ListView headers. Teach chart sweep to disable intercept to play with ListView, and draw sweep disabled as dashed line. Hijacking Preference views for toggles to offer consistency. No policy updates are persisted yet. Based on available historical network stats and policy cycle reset day, build list of user-selectable cycles. Wired up chart to display cycle data and reset inspection region to last week of available data. Change-Id: Ia561578276fa23908b745fbc06a6ef828d9ccc2e
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);