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/ChartDataUsageView.java (renamed from src/com/android/settings/widget/DataUsageChartView.java)59
-rw-r--r--src/com/android/settings/widget/ChartSweepView.java112
-rw-r--r--src/com/android/settings/widget/ChartView.java54
3 files changed, 181 insertions, 44 deletions
diff --git a/src/com/android/settings/widget/DataUsageChartView.java b/src/com/android/settings/widget/ChartDataUsageView.java
index f6ae5a0..9554368 100644
--- a/src/com/android/settings/widget/DataUsageChartView.java
+++ b/src/com/android/settings/widget/ChartDataUsageView.java
@@ -27,6 +27,7 @@ import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.AttributeSet;
+import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
@@ -37,7 +38,7 @@ 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 {
+public class ChartDataUsageView extends ChartView {
private static final long KB_IN_BYTES = 1024;
private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
@@ -46,6 +47,8 @@ public class DataUsageChartView 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;
@@ -70,15 +73,15 @@ public class DataUsageChartView extends ChartView {
private DataUsageChartListener mListener;
- public DataUsageChartView(Context context) {
+ public ChartDataUsageView(Context context) {
this(context, null, 0);
}
- public DataUsageChartView(Context context, AttributeSet attrs) {
+ public ChartDataUsageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
- public DataUsageChartView(Context context, AttributeSet attrs, int defStyle) {
+ public ChartDataUsageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(new TimeAxis(), new InvertedChartAxis(new DataAxis()));
@@ -186,6 +189,7 @@ public class DataUsageChartView extends ChartView {
updateVertAxisBounds(null);
requestLayout();
+ invalidate();
}
/**
@@ -194,7 +198,8 @@ public class DataUsageChartView extends ChartView {
*/
private void updateVertAxisBounds(ChartSweepView activeSweep) {
final long max = mVertMax;
- final long newMax;
+
+ long newMax = 0;
if (activeSweep != null) {
final int adjustAxis = activeSweep.shouldAdjustAxis();
if (adjustAxis > 0) {
@@ -206,14 +211,14 @@ public class DataUsageChartView extends ChartView {
} else {
newMax = max;
}
-
- } else {
- // try showing all known data and policy
- final long maxSweep = Math.max(mSweepWarning.getValue(), mSweepLimit.getValue());
- final long maxVisible = Math.max(mSeries.getMaxVisible(), maxSweep) * 12 / 10;
- newMax = Math.max(maxVisible, 2 * GB_IN_BYTES);
}
+ // always show known data and policy lines
+ final long maxSweep = Math.max(mSweepWarning.getValue(), mSweepLimit.getValue());
+ final long maxVisible = Math.max(mSeries.getMaxVisible(), maxSweep) * 12 / 10;
+ final long maxDefault = Math.max(maxVisible, 2 * GB_IN_BYTES);
+ newMax = Math.max(maxDefault, newMax);
+
// only invalidate when vertMax actually changed
if (newMax != mVertMax) {
mVertMax = newMax;
@@ -231,6 +236,16 @@ public class DataUsageChartView extends ChartView {
if (activeSweep != null) {
activeSweep.updateValueFromPosition();
}
+
+ // layout other sweeps to match changed axis
+ // TODO: find cleaner way of doing this, such as requesting full
+ // layout and making activeSweep discard its tracking MotionEvent.
+ if (mSweepLimit != activeSweep) {
+ layoutSweep(mSweepLimit);
+ }
+ if (mSweepWarning != activeSweep) {
+ layoutSweep(mSweepWarning);
+ }
}
}
@@ -346,9 +361,14 @@ public class DataUsageChartView extends ChartView {
final long validStart = Math.max(visibleStart, getStatsStart());
final long validEnd = Math.min(visibleEnd, getStatsEnd());
- // prevent time sweeps from leaving valid data
- mSweepLeft.setValidRange(validStart, validEnd);
- mSweepRight.setValidRange(validStart, validEnd);
+ 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;
@@ -424,7 +444,7 @@ public class DataUsageChartView extends ChartView {
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));
+ tickPoints[i] = convertToPoint(mMax - (TICK_INTERVAL * (i + 1)));
}
return tickPoints;
}
@@ -501,7 +521,14 @@ public class DataUsageChartView extends ChartView {
/** {@inheritDoc} */
public float[] getTickPoints() {
final long range = mMax - mMin;
- final long tickJump = 256 * MB_IN_BYTES;
+ final long tickJump;
+ if (range < 6 * GB_IN_BYTES) {
+ tickJump = 256 * MB_IN_BYTES;
+ } else if (range < 12 * GB_IN_BYTES) {
+ tickJump = 512 * MB_IN_BYTES;
+ } else {
+ tickJump = 1 * GB_IN_BYTES;
+ }
final int tickCount = (int) (range / tickJump);
final float[] tickPoints = new float[tickCount];
diff --git a/src/com/android/settings/widget/ChartSweepView.java b/src/com/android/settings/widget/ChartSweepView.java
index 81aeb84..0d91a76 100644
--- a/src/com/android/settings/widget/ChartSweepView.java
+++ b/src/com/android/settings/widget/ChartSweepView.java
@@ -21,6 +21,7 @@ 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.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -42,8 +43,14 @@ import com.google.common.base.Preconditions;
*/
public class ChartSweepView extends View {
+ private static final boolean DRAW_OUTLINE = false;
+
private Drawable mSweep;
private Rect mSweepPadding = new Rect();
+
+ /** Offset of content inside this view. */
+ private Point mContentOffset = new Point();
+ /** Offset of {@link #mSweep} inside this view. */
private Point mSweepOffset = new Point();
private Rect mMargins = new Rect();
@@ -66,6 +73,8 @@ public class ChartSweepView extends View {
private ChartSweepView mValidAfterDynamic;
private ChartSweepView mValidBeforeDynamic;
+ private Paint mOutlinePaint = new Paint();
+
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
@@ -98,6 +107,10 @@ public class ChartSweepView extends View {
setLabelTemplate(a.getResourceId(R.styleable.ChartSweepView_labelTemplate, 0));
setLabelColor(a.getColor(R.styleable.ChartSweepView_labelColor, Color.BLUE));
+ mOutlinePaint.setColor(Color.RED);
+ mOutlinePaint.setStrokeWidth(1f);
+ mOutlinePaint.setStyle(Style.STROKE);
+
a.recycle();
setWillNotDraw(false);
@@ -123,11 +136,11 @@ public class ChartSweepView extends View {
if (mFollowAxis == VERTICAL) {
final float targetHeight = mSweep.getIntrinsicHeight() - mSweepPadding.top
- mSweepPadding.bottom;
- return mSweepPadding.top + (targetHeight / 2);
+ return mSweepPadding.top + (targetHeight / 2) + mSweepOffset.y;
} else {
final float targetWidth = mSweep.getIntrinsicWidth() - mSweepPadding.left
- mSweepPadding.right;
- return mSweepPadding.left + (targetWidth / 2);
+ return mSweepPadding.left + (targetWidth / 2) + mSweepOffset.x;
}
}
@@ -195,6 +208,7 @@ 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(
@@ -283,6 +297,26 @@ public class ChartSweepView extends View {
mValidBeforeDynamic = validBefore;
}
+ /**
+ * Test if given {@link MotionEvent} is closer to another
+ * {@link ChartSweepView} compared to ourselves.
+ */
+ public boolean isTouchCloserTo(MotionEvent eventInParent, ChartSweepView another) {
+ if (another == null) return false;
+
+ if (mFollowAxis == HORIZONTAL) {
+ final float selfDist = Math.abs(eventInParent.getX() - (getX() + getTargetInset()));
+ final float anotherDist = Math.abs(
+ eventInParent.getX() - (another.getX() + another.getTargetInset()));
+ return anotherDist < selfDist;
+ } else {
+ final float selfDist = Math.abs(eventInParent.getY() - (getY() + getTargetInset()));
+ final float anotherDist = Math.abs(
+ eventInParent.getY() - (another.getY() + another.getTargetInset()));
+ return anotherDist < selfDist;
+ }
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) return false;
@@ -294,9 +328,18 @@ public class ChartSweepView extends View {
// only start tracking when in sweet spot
final boolean accept;
if (mFollowAxis == VERTICAL) {
- accept = event.getX() > getWidth() - (mSweepPadding.right * 2);
+ accept = event.getX() > getWidth() - (mSweepPadding.right * 3);
} else {
- accept = event.getY() > getHeight() - (mSweepPadding.bottom * 2);
+ accept = event.getY() > getHeight() - (mSweepPadding.bottom * 3);
+ }
+
+ final MotionEvent eventInParent = event.copy();
+ eventInParent.offsetLocation(getLeft(), getTop());
+
+ // ignore event when closer to a neighbor
+ if (isTouchCloserTo(eventInParent, mValidAfterDynamic)
+ || isTouchCloserTo(eventInParent, mValidBeforeDynamic)) {
+ return false;
}
if (accept) {
@@ -460,6 +503,7 @@ public class ChartSweepView extends View {
final int templateHeight = mLabelLayout.getHeight();
mSweepOffset.x = 0;
+ mSweepOffset.y = 0;
mSweepOffset.y = (int) ((templateHeight / 2) - getTargetInset());
setMeasuredDimension(mSweep.getIntrinsicWidth(), Math.max(sweepHeight, templateHeight));
@@ -485,6 +529,23 @@ public class ChartSweepView extends View {
mMargins.bottom = mSweepPadding.bottom;
}
+ mContentOffset.x = 0;
+ mContentOffset.y = 0;
+
+ // make touch target area larger
+ if (mFollowAxis == HORIZONTAL) {
+ final int widthBefore = getMeasuredWidth();
+ final int widthAfter = widthBefore * 3;
+ setMeasuredDimension(widthAfter, getMeasuredHeight());
+ mContentOffset.offset((widthAfter - widthBefore) / 2, 0);
+ } else {
+ final int heightBefore = getMeasuredHeight();
+ final int heightAfter = heightBefore * 3;
+ setMeasuredDimension(getMeasuredWidth(), heightAfter);
+ mContentOffset.offset(0, (heightAfter - heightBefore) / 2);
+ }
+
+ mSweepOffset.offset(mContentOffset.x, mContentOffset.y);
mMargins.offset(-mSweepOffset.x, -mSweepOffset.y);
}
@@ -493,9 +554,43 @@ public class ChartSweepView extends View {
final int width = getWidth();
final int height = getHeight();
+ if (DRAW_OUTLINE) {
+ canvas.drawRect(0, 0, width, height, mOutlinePaint);
+ }
+
+ // when overlapping with neighbor, split difference and push label
+ float margin;
+ float labelOffset = 0;
+ if (mFollowAxis == VERTICAL) {
+ if (mValidAfterDynamic != null) {
+ margin = getLabelTop(mValidAfterDynamic) - getLabelBottom(this);
+ if (margin < 0) {
+ labelOffset = margin / 2;
+ }
+ } else if (mValidBeforeDynamic != null) {
+ margin = getLabelTop(this) - getLabelBottom(mValidBeforeDynamic);
+ if (margin < 0) {
+ labelOffset = -margin / 2;
+ }
+ }
+ } else {
+ // TODO: implement horizontal labels
+ }
+
+ // when offsetting label, neighbor probably needs to offset too
+ if (labelOffset != 0) {
+ if (mValidAfterDynamic != null) mValidAfterDynamic.invalidate();
+ if (mValidBeforeDynamic != null) mValidBeforeDynamic.invalidate();
+ }
+
final int labelSize;
if (isEnabled() && mLabelLayout != null) {
- mLabelLayout.draw(canvas);
+ final int count = canvas.save();
+ {
+ canvas.translate(mContentOffset.x, mContentOffset.y + labelOffset);
+ mLabelLayout.draw(canvas);
+ }
+ canvas.restoreToCount(count);
labelSize = mLabelSize;
} else {
labelSize = 0;
@@ -512,4 +607,11 @@ public class ChartSweepView extends View {
mSweep.draw(canvas);
}
+ public static float getLabelTop(ChartSweepView view) {
+ return view.getY() + view.mContentOffset.y;
+ }
+
+ public static float getLabelBottom(ChartSweepView view) {
+ return getLabelTop(view) + view.mLabelLayout.getHeight();
+ }
}
diff --git a/src/com/android/settings/widget/ChartView.java b/src/com/android/settings/widget/ChartView.java
index e3a658a..f410d57 100644
--- a/src/com/android/settings/widget/ChartView.java
+++ b/src/com/android/settings/widget/ChartView.java
@@ -36,8 +36,6 @@ import com.android.settings.R;
* and screen coordinates.
*/
public class ChartView extends FrameLayout {
- private static final String TAG = "ChartView";
-
// TODO: extend something that supports two-dimensional scrolling
private static final int SWEEP_GRAVITY = Gravity.TOP | Gravity.LEFT;
@@ -122,29 +120,39 @@ public class ChartView extends FrameLayout {
child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
} else if (child instanceof ChartSweepView) {
- // sweep is always placed along specific dimension
- final ChartSweepView sweep = (ChartSweepView) child;
- final Rect sweepMargins = sweep.getMargins();
-
- if (sweep.getFollowAxis() == ChartSweepView.VERTICAL) {
- parentRect.top += sweepMargins.top + (int) sweep.getPoint();
- parentRect.bottom = parentRect.top;
- parentRect.left += sweepMargins.left;
- parentRect.right += sweepMargins.right;
- Gravity.apply(SWEEP_GRAVITY, parentRect.width(), child.getMeasuredHeight(),
- parentRect, childRect);
-
- } else {
- parentRect.left += sweepMargins.left + (int) sweep.getPoint();
- parentRect.right = parentRect.left;
- parentRect.top += sweepMargins.top;
- parentRect.bottom += sweepMargins.bottom;
- Gravity.apply(SWEEP_GRAVITY, child.getMeasuredWidth(), parentRect.height(),
- parentRect, childRect);
- }
+ layoutSweep((ChartSweepView) child, parentRect, childRect);
+ child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
}
+ }
+ }
+
+ protected void layoutSweep(ChartSweepView sweep) {
+ final Rect parentRect = new Rect(mContent);
+ final Rect childRect = new Rect();
+
+ layoutSweep(sweep, parentRect, childRect);
+ sweep.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
+ }
- child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
+ protected void layoutSweep(ChartSweepView sweep, Rect parentRect, Rect childRect) {
+ final Rect sweepMargins = sweep.getMargins();
+
+ // sweep is always placed along specific dimension
+ if (sweep.getFollowAxis() == ChartSweepView.VERTICAL) {
+ parentRect.top += sweepMargins.top + (int) sweep.getPoint();
+ parentRect.bottom = parentRect.top;
+ parentRect.left += sweepMargins.left;
+ parentRect.right += sweepMargins.right;
+ Gravity.apply(SWEEP_GRAVITY, parentRect.width(), sweep.getMeasuredHeight(),
+ parentRect, childRect);
+
+ } else {
+ parentRect.left += sweepMargins.left + (int) sweep.getPoint();
+ parentRect.right = parentRect.left;
+ parentRect.top += sweepMargins.top;
+ parentRect.bottom += sweepMargins.bottom;
+ Gravity.apply(SWEEP_GRAVITY, sweep.getMeasuredWidth(), parentRect.height(),
+ parentRect, childRect);
}
}