diff options
Diffstat (limited to 'src/com')
-rw-r--r-- | src/com/android/settings/widget/ChartAxis.java | 6 | ||||
-rw-r--r-- | src/com/android/settings/widget/ChartSweepView.java | 173 | ||||
-rw-r--r-- | src/com/android/settings/widget/ChartView.java | 25 | ||||
-rw-r--r-- | src/com/android/settings/widget/DataUsageChartView.java | 61 | ||||
-rw-r--r-- | src/com/android/settings/widget/InvertedChartAxis.java | 12 |
5 files changed, 204 insertions, 73 deletions
diff --git a/src/com/android/settings/widget/ChartAxis.java b/src/com/android/settings/widget/ChartAxis.java index e761202d6..463541fc5 100644 --- a/src/com/android/settings/widget/ChartAxis.java +++ b/src/com/android/settings/widget/ChartAxis.java @@ -16,6 +16,9 @@ package com.android.settings.widget; +import android.content.res.Resources; +import android.text.SpannableStringBuilder; + /** * Axis along a {@link ChartView} that knows how to convert between raw point * and screen coordinate systems. @@ -28,8 +31,7 @@ public interface ChartAxis { public float convertToPoint(long value); public long convertToValue(float point); - public CharSequence getLabel(long value); - public CharSequence getShortLabel(long value); + public void buildLabel(Resources res, SpannableStringBuilder builder, long value); public float[] getTickPoints(); diff --git a/src/com/android/settings/widget/ChartSweepView.java b/src/com/android/settings/widget/ChartSweepView.java index 6c9ded4ed..b0d00bb89 100644 --- a/src/com/android/settings/widget/ChartSweepView.java +++ b/src/com/android/settings/widget/ChartSweepView.java @@ -19,8 +19,15 @@ 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.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.text.DynamicLayout; +import android.text.Layout.Alignment; +import android.text.SpannableStringBuilder; +import android.text.TextPaint; import android.util.AttributeSet; import android.util.MathUtils; import android.view.MotionEvent; @@ -36,13 +43,20 @@ import com.google.common.base.Preconditions; */ public class ChartSweepView extends FrameLayout { - // TODO: paint label when requested - private Drawable mSweep; - private Rect mSweepMargins = new Rect(); + private Rect mSweepPadding = new Rect(); + private Point mSweepOffset = new Point(); + + private Rect mMargins = new Rect(); private int mFollowAxis; - private boolean mShowLabel; + + private int mLabelSize; + private int mLabelTemplateRes; + private int mLabelColor; + + private SpannableStringBuilder mLabelTemplate; + private DynamicLayout mLabelLayout; private ChartAxis mAxis; private long mValue; @@ -73,7 +87,10 @@ public class ChartSweepView extends FrameLayout { setSweepDrawable(a.getDrawable(R.styleable.ChartSweepView_sweepDrawable)); setFollowAxis(a.getInt(R.styleable.ChartSweepView_followAxis, -1)); - setShowLabel(a.getBoolean(R.styleable.ChartSweepView_showLabel, false)); + + setLabelSize(a.getDimensionPixelSize(R.styleable.ChartSweepView_labelSize, 0)); + setLabelTemplate(a.getResourceId(R.styleable.ChartSweepView_labelTemplate, 0)); + setLabelColor(a.getColor(R.styleable.ChartSweepView_labelColor, Color.BLUE)); a.recycle(); @@ -90,27 +107,23 @@ public class ChartSweepView extends FrameLayout { return mFollowAxis; } - /** - * Return margins of {@link #setSweepDrawable(Drawable)}, indicating how the - * sweep should be displayed around a content region. - */ - public Rect getSweepMargins() { - return mSweepMargins; + public Rect getMargins() { + return mMargins; } /** * Return the number of pixels that the "target" area is inset from the * {@link View} edge, along the current {@link #setFollowAxis(int)}. */ - public float getTargetInset() { + private float getTargetInset() { if (mFollowAxis == VERTICAL) { - final float targetHeight = mSweep.getIntrinsicHeight() - mSweepMargins.top - - mSweepMargins.bottom; - return mSweepMargins.top + (targetHeight / 2); + final float targetHeight = mSweep.getIntrinsicHeight() - mSweepPadding.top + - mSweepPadding.bottom; + return mSweepPadding.top + (targetHeight / 2); } else { - final float targetWidth = mSweep.getIntrinsicWidth() - mSweepMargins.left - - mSweepMargins.right; - return mSweepMargins.left + (targetWidth / 2); + final float targetWidth = mSweep.getIntrinsicWidth() - mSweepPadding.left + - mSweepPadding.right; + return mSweepPadding.left + (targetWidth / 2); } } @@ -124,6 +137,12 @@ public class ChartSweepView extends FrameLayout { } } + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + requestLayout(); + } + public void setSweepDrawable(Drawable sweep) { if (mSweep != null) { mSweep.setCallback(null); @@ -137,7 +156,7 @@ public class ChartSweepView extends FrameLayout { } sweep.setVisible(getVisibility() == VISIBLE, false); mSweep = sweep; - sweep.getPadding(mSweepMargins); + sweep.getPadding(mSweepPadding); } else { mSweep = null; } @@ -149,9 +168,49 @@ public class ChartSweepView extends FrameLayout { mFollowAxis = followAxis; } - public void setShowLabel(boolean showLabel) { - mShowLabel = showLabel; + public void setLabelSize(int size) { + mLabelSize = size; + invalidateLabelTemplate(); + } + + public void setLabelTemplate(int resId) { + mLabelTemplateRes = resId; + invalidateLabelTemplate(); + } + + public void setLabelColor(int color) { + mLabelColor = color; + invalidateLabelTemplate(); + } + + private void invalidateLabelTemplate() { + if (mLabelTemplateRes != 0) { + final CharSequence template = getResources().getText(mLabelTemplateRes); + + final TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + paint.density = getResources().getDisplayMetrics().density; + paint.setCompatibilityScaling(getResources().getCompatibilityInfo().applicationScale); + paint.setColor(mLabelColor); + + mLabelTemplate = new SpannableStringBuilder(template); + mLabelLayout = new DynamicLayout( + mLabelTemplate, paint, mLabelSize, Alignment.ALIGN_RIGHT, 1f, 0f, false); + invalidateLabel(); + + } else { + mLabelTemplate = null; + mLabelLayout = null; + } + invalidate(); + requestLayout(); + } + + private void invalidateLabel() { + if (mLabelTemplate != null && mAxis != null) { + mAxis.buildLabel(getResources(), mLabelTemplate, mValue); + invalidate(); + } } @Override @@ -181,6 +240,7 @@ public class ChartSweepView extends FrameLayout { public void setValue(long value) { mValue = value; + invalidateLabel(); } public long getValue() { @@ -207,9 +267,9 @@ public class ChartSweepView extends FrameLayout { // only start tracking when in sweet spot final boolean accept; if (mFollowAxis == VERTICAL) { - accept = event.getX() > getWidth() - (mSweepMargins.right * 2); + accept = event.getX() > getWidth() - (mSweepPadding.right * 2); } else { - accept = event.getY() > getHeight() - (mSweepMargins.bottom * 2); + accept = event.getY() > getHeight() - (mSweepPadding.bottom * 2); } if (accept) { @@ -222,42 +282,40 @@ public class ChartSweepView extends FrameLayout { case MotionEvent.ACTION_MOVE: { getParent().requestDisallowInterceptTouchEvent(true); - final Rect sweepMargins = mSweepMargins; - // content area of parent final Rect parentContent = new Rect(parent.getPaddingLeft(), parent.getPaddingTop(), parent.getWidth() - parent.getPaddingRight(), parent.getHeight() - parent.getPaddingBottom()); if (mFollowAxis == VERTICAL) { - final float currentTargetY = getTop() + getTargetInset(); + final float currentTargetY = getTop() - mMargins.top; final float requestedTargetY = currentTargetY + (event.getRawY() - mTracking.getRawY()); final float clampedTargetY = MathUtils.constrain( requestedTargetY, parentContent.top, parentContent.bottom); setTranslationY(clampedTargetY - currentTargetY); - mValue = mAxis.convertToValue(clampedTargetY - parentContent.top); - dispatchOnSweep(false); + setValue(mAxis.convertToValue(clampedTargetY - parentContent.top)); } else { - final float currentTargetX = getLeft() + getTargetInset(); + final float currentTargetX = getLeft() - mMargins.left; final float requestedTargetX = currentTargetX + (event.getRawX() - mTracking.getRawX()); final float clampedTargetX = MathUtils.constrain( requestedTargetX, parentContent.left, parentContent.right); setTranslationX(clampedTargetX - currentTargetX); - mValue = mAxis.convertToValue(clampedTargetX - parentContent.left); - dispatchOnSweep(false); + setValue(mAxis.convertToValue(clampedTargetX - parentContent.left)); } + + dispatchOnSweep(false); return true; } case MotionEvent.ACTION_UP: { mTracking = null; + dispatchOnSweep(true); setTranslationX(0); setTranslationY(0); requestLayout(); - dispatchOnSweep(true); return true; } default: { @@ -276,7 +334,39 @@ public class ChartSweepView extends FrameLayout { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(mSweep.getIntrinsicWidth(), mSweep.getIntrinsicHeight()); + + // TODO: handle vertical labels + if (isEnabled() && mLabelLayout != null) { + final int sweepHeight = mSweep.getIntrinsicHeight(); + final int templateHeight = mLabelLayout.getHeight(); + + mSweepOffset.x = 0; + mSweepOffset.y = (int) ((templateHeight / 2) - getTargetInset()); + setMeasuredDimension(mSweep.getIntrinsicWidth(), Math.max(sweepHeight, templateHeight)); + + } else { + mSweepOffset.x = 0; + mSweepOffset.y = 0; + setMeasuredDimension(mSweep.getIntrinsicWidth(), mSweep.getIntrinsicHeight()); + } + + if (mFollowAxis == VERTICAL) { + final int targetHeight = mSweep.getIntrinsicHeight() - mSweepPadding.top + - mSweepPadding.bottom; + mMargins.top = -(mSweepPadding.top + (targetHeight / 2)); + mMargins.bottom = 0; + mMargins.left = -mSweepPadding.left; + mMargins.right = mSweepPadding.right; + } else { + final int targetWidth = mSweep.getIntrinsicWidth() - mSweepPadding.left + - mSweepPadding.right; + mMargins.left = -(mSweepPadding.left + (targetWidth / 2)); + mMargins.right = 0; + mMargins.top = -mSweepPadding.top; + mMargins.bottom = mSweepPadding.bottom; + } + + mMargins.offset(-mSweepOffset.x, -mSweepOffset.y); } @Override @@ -284,7 +374,22 @@ public class ChartSweepView extends FrameLayout { final int width = getWidth(); final int height = getHeight(); - mSweep.setBounds(0, 0, width, height); + final int labelSize; + if (isEnabled() && mLabelLayout != null) { + mLabelLayout.draw(canvas); + labelSize = mLabelSize; + } else { + labelSize = 0; + } + + if (mFollowAxis == VERTICAL) { + mSweep.setBounds(labelSize, mSweepOffset.y, width, + mSweepOffset.y + mSweep.getIntrinsicHeight()); + } else { + mSweep.setBounds(mSweepOffset.x, labelSize, + mSweepOffset.x + mSweep.getIntrinsicWidth(), height); + } + mSweep.draw(canvas); } diff --git a/src/com/android/settings/widget/ChartView.java b/src/com/android/settings/widget/ChartView.java index 9223ca6d2..a5b8b0950 100644 --- a/src/com/android/settings/widget/ChartView.java +++ b/src/com/android/settings/widget/ChartView.java @@ -21,7 +21,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; -import android.util.Log; import android.view.Gravity; import android.view.View; import android.widget.FrameLayout; @@ -93,22 +92,22 @@ public class ChartView extends FrameLayout { } else if (child instanceof ChartSweepView) { // sweep is always placed along specific dimension final ChartSweepView sweep = (ChartSweepView) child; - final Rect sweepMargins = sweep.getSweepMargins(); + final Rect sweepMargins = sweep.getMargins(); - if (sweep.getFollowAxis() == ChartSweepView.HORIZONTAL) { - parentRect.left = parentRect.right = - (int) (sweep.getPoint() - sweep.getTargetInset()) + getPaddingLeft(); - parentRect.top -= sweepMargins.top; - parentRect.bottom += sweepMargins.bottom; - Gravity.apply(SWEEP_GRAVITY, child.getMeasuredWidth(), parentRect.height(), + 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.top = parentRect.bottom = - (int) (sweep.getPoint() - sweep.getTargetInset()) + getPaddingTop(); - parentRect.left -= sweepMargins.left; - parentRect.right += sweepMargins.right; - Gravity.apply(SWEEP_GRAVITY, parentRect.width(), child.getMeasuredHeight(), + 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); } } diff --git a/src/com/android/settings/widget/DataUsageChartView.java b/src/com/android/settings/widget/DataUsageChartView.java index a8bdaa6f8..89caef17e 100644 --- a/src/com/android/settings/widget/DataUsageChartView.java +++ b/src/com/android/settings/widget/DataUsageChartView.java @@ -17,8 +17,12 @@ package com.android.settings.widget; import android.content.Context; +import android.content.res.Resources; import android.net.NetworkPolicy; import android.net.NetworkStatsHistory; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.TextUtils; import android.text.format.DateUtils; import android.util.AttributeSet; import android.view.MotionEvent; @@ -283,15 +287,9 @@ public class DataUsageChartView extends ChartView { } /** {@inheritDoc} */ - public CharSequence getLabel(long value) { - // TODO: convert to string - return Long.toString(value); - } - - /** {@inheritDoc} */ - public CharSequence getShortLabel(long value) { - // TODO: convert to string - return Long.toString(value); + public void buildLabel(Resources res, SpannableStringBuilder builder, long value) { + // TODO: convert to better string + builder.replace(0, builder.length(), Long.toString(value)); } /** {@inheritDoc} */ @@ -345,16 +343,33 @@ public class DataUsageChartView extends ChartView { return (long) fraction; } - /** {@inheritDoc} */ - public CharSequence getLabel(long value) { - // TODO: use exploded string here - return Long.toString(value); - } + private static final Object sSpanSize = new Object(); + private static final Object sSpanUnit = new Object(); /** {@inheritDoc} */ - public CharSequence getShortLabel(long value) { - // TODO: convert to string - return Long.toString(value); + public void buildLabel(Resources res, SpannableStringBuilder builder, long value) { + + float result = value; + final CharSequence unit; + if (result <= 100 * MB_IN_BYTES) { + unit = res.getText(com.android.internal.R.string.megabyteShort); + result /= MB_IN_BYTES; + } else { + unit = res.getText(com.android.internal.R.string.gigabyteShort); + result /= GB_IN_BYTES; + } + + final CharSequence size; + if (result < 10) { + size = String.format("%.1f", result); + } else { + size = String.format("%.0f", result); + } + + final int[] sizeBounds = findOrCreateSpan(builder, sSpanSize, "^1"); + builder.replace(sizeBounds[0], sizeBounds[1], size); + final int[] unitBounds = findOrCreateSpan(builder, sSpanUnit, "^2"); + builder.replace(unitBounds[0], unitBounds[1], unit); } /** {@inheritDoc} */ @@ -372,4 +387,16 @@ public class DataUsageChartView extends ChartView { } } + private static int[] findOrCreateSpan( + SpannableStringBuilder builder, Object key, CharSequence bootstrap) { + int start = builder.getSpanStart(key); + int end = builder.getSpanEnd(key); + if (start == -1) { + start = TextUtils.indexOf(builder, bootstrap); + end = start + bootstrap.length(); + builder.setSpan(key, start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE); + } + return new int[] { start, end }; + } + } diff --git a/src/com/android/settings/widget/InvertedChartAxis.java b/src/com/android/settings/widget/InvertedChartAxis.java index a30d24cfa..e589da979 100644 --- a/src/com/android/settings/widget/InvertedChartAxis.java +++ b/src/com/android/settings/widget/InvertedChartAxis.java @@ -16,6 +16,9 @@ package com.android.settings.widget; +import android.content.res.Resources; +import android.text.SpannableStringBuilder; + /** * Utility to invert another {@link ChartAxis}. */ @@ -49,13 +52,8 @@ public class InvertedChartAxis implements ChartAxis { } /** {@inheritDoc} */ - public CharSequence getLabel(long value) { - return mWrapped.getLabel(value); - } - - /** {@inheritDoc} */ - public CharSequence getShortLabel(long value) { - return mWrapped.getShortLabel(value); + public void buildLabel(Resources res, SpannableStringBuilder builder, long value) { + mWrapped.buildLabel(res, builder, value); } /** {@inheritDoc} */ |