diff --git a/color-check-baseline.xml b/color-check-baseline.xml index 4b36b507ee1..62c7915a3d3 100644 --- a/color-check-baseline.xml +++ b/color-check-baseline.xml @@ -1501,22 +1501,6 @@ column="9"/> - - - - - - - - - - - - - - - - - - - - diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 42473262b2f..afff3cebe22 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -50,13 +50,6 @@ - - - - - - - diff --git a/src/com/android/settings/datausage/DataUsageList.java b/src/com/android/settings/datausage/DataUsageList.java index cc405644a8e..0458207e8ad 100644 --- a/src/com/android/settings/datausage/DataUsageList.java +++ b/src/com/android/settings/datausage/DataUsageList.java @@ -14,18 +14,15 @@ package com.android.settings.datausage; -import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; import static android.net.TrafficStats.UID_REMOVED; import static android.net.TrafficStats.UID_TETHERING; -import static android.telephony.TelephonyManager.SIM_STATE_READY; import android.app.ActivityManager; import android.content.Context; import android.content.Intent; import android.content.pm.UserInfo; import android.graphics.Color; -import android.net.ConnectivityManager; import android.net.INetworkStatsSession; import android.net.NetworkPolicy; import android.net.NetworkStats; @@ -35,13 +32,11 @@ import android.net.TrafficStats; import android.os.AsyncTask; import android.os.Bundle; import android.os.RemoteException; -import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; import android.text.format.DateUtils; import android.util.Log; import android.util.SparseArray; diff --git a/src/com/android/settings/datausage/DataUsageListV2.java b/src/com/android/settings/datausage/DataUsageListV2.java index c6d3b4d23c3..aef9519b870 100644 --- a/src/com/android/settings/datausage/DataUsageListV2.java +++ b/src/com/android/settings/datausage/DataUsageListV2.java @@ -28,7 +28,6 @@ import android.content.pm.UserInfo; import android.graphics.Color; import android.net.ConnectivityManager; import android.net.NetworkPolicy; -import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.AsyncTask; import android.os.Bundle; @@ -252,8 +251,7 @@ public class DataUsageListV2 extends DataUsageBaseFragment { } /** - * Update body content based on current tab. Loads - * {@link NetworkStatsHistory} and {@link NetworkPolicy} from system, and + * Update body content based on current tab. Loads network cycle data from system, and * binds them to visible controls. */ private void updateBody() { diff --git a/src/com/android/settings/widget/ChartDataUsageView.java b/src/com/android/settings/widget/ChartDataUsageView.java deleted file mode 100644 index d1ddc14b40c..00000000000 --- a/src/com/android/settings/widget/ChartDataUsageView.java +++ /dev/null @@ -1,606 +0,0 @@ -/* - * 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 static android.net.TrafficStats.MB_IN_BYTES; - -import android.content.Context; -import android.content.res.Resources; -import android.net.NetworkPolicy; -import android.net.NetworkStatsHistory; -import android.net.TrafficStats; -import android.os.Handler; -import android.os.Message; -import android.text.Spannable; -import android.text.SpannableStringBuilder; -import android.text.TextUtils; -import android.text.format.DateUtils; -import android.text.format.Formatter; -import android.text.format.Formatter.BytesResult; -import android.text.format.Time; -import android.util.AttributeSet; -import android.util.MathUtils; -import android.view.MotionEvent; -import android.view.View; - -import com.android.settings.R; -import com.android.settings.widget.ChartSweepView.OnSweepListener; - -import java.util.Arrays; -import java.util.Calendar; -import java.util.Objects; - -/** - * Specific {@link ChartView} that displays {@link ChartNetworkSeriesView} along - * with {@link ChartSweepView} for inspection ranges and warning/limits. - */ -public class ChartDataUsageView extends ChartView { - - private static final int MSG_UPDATE_AXIS = 100; - private static final long DELAY_MILLIS = 250; - - private ChartGridView mGrid; - private ChartNetworkSeriesView mSeries; - private ChartNetworkSeriesView mDetailSeries; - - private NetworkStatsHistory mHistory; - - private ChartSweepView mSweepWarning; - private ChartSweepView mSweepLimit; - - private long mInspectStart; - private long mInspectEnd; - - private Handler mHandler; - - /** Current maximum value of {@link #mVert}. */ - private long mVertMax; - - public interface DataUsageChartListener { - public void onWarningChanged(); - public void onLimitChanged(); - public void requestWarningEdit(); - public void requestLimitEdit(); - } - - private DataUsageChartListener mListener; - - public ChartDataUsageView(Context context) { - this(context, null, 0); - } - - public ChartDataUsageView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public ChartDataUsageView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(new TimeAxis(), new InvertedChartAxis(new DataAxis())); - - mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - final ChartSweepView sweep = (ChartSweepView) msg.obj; - updateVertAxisBounds(sweep); - updateEstimateVisible(); - - // we keep dispatching repeating updates until sweep is dropped - sendUpdateAxisDelayed(sweep, true); - } - }; - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - mGrid = (ChartGridView) findViewById(R.id.grid); - mSeries = (ChartNetworkSeriesView) findViewById(R.id.series); - mDetailSeries = (ChartNetworkSeriesView) findViewById(R.id.detail_series); - mDetailSeries.setVisibility(View.GONE); - - mSweepLimit = (ChartSweepView) findViewById(R.id.sweep_limit); - mSweepWarning = (ChartSweepView) findViewById(R.id.sweep_warning); - - // prevent sweeps from crossing each other - mSweepWarning.setValidRangeDynamic(null, mSweepLimit); - mSweepLimit.setValidRangeDynamic(mSweepWarning, null); - - // mark neighbors for checking touch events against - mSweepLimit.setNeighbors(mSweepWarning); - mSweepWarning.setNeighbors(mSweepLimit); - - mSweepWarning.addOnSweepListener(mVertListener); - mSweepLimit.addOnSweepListener(mVertListener); - - mSweepWarning.setDragInterval(5 * MB_IN_BYTES); - mSweepLimit.setDragInterval(5 * MB_IN_BYTES); - - // tell everyone about our axis - mGrid.init(mHoriz, mVert); - mSeries.init(mHoriz, mVert); - mDetailSeries.init(mHoriz, mVert); - mSweepWarning.init(mVert); - mSweepLimit.init(mVert); - - setActivated(false); - } - - public void setListener(DataUsageChartListener listener) { - mListener = listener; - } - - public void bindNetworkStats(NetworkStatsHistory stats) { - mSeries.bindNetworkStats(stats); - mHistory = stats; - updateVertAxisBounds(null); - updateEstimateVisible(); - updatePrimaryRange(); - requestLayout(); - } - - public void bindDetailNetworkStats(NetworkStatsHistory stats) { - mDetailSeries.bindNetworkStats(stats); - mDetailSeries.setVisibility(stats != null ? View.VISIBLE : View.GONE); - if (mHistory != null) { - mDetailSeries.setEndTime(mHistory.getEnd()); - } - updateVertAxisBounds(null); - updateEstimateVisible(); - updatePrimaryRange(); - requestLayout(); - } - - public void bindNetworkPolicy(NetworkPolicy policy) { - if (policy == null) { - mSweepLimit.setVisibility(View.INVISIBLE); - mSweepLimit.setValue(-1); - mSweepWarning.setVisibility(View.INVISIBLE); - mSweepWarning.setValue(-1); - return; - } - - if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) { - mSweepLimit.setVisibility(View.VISIBLE); - mSweepLimit.setEnabled(true); - mSweepLimit.setValue(policy.limitBytes); - } else { - mSweepLimit.setVisibility(View.INVISIBLE); - mSweepLimit.setEnabled(false); - mSweepLimit.setValue(-1); - } - - if (policy.warningBytes != NetworkPolicy.WARNING_DISABLED) { - mSweepWarning.setVisibility(View.VISIBLE); - mSweepWarning.setValue(policy.warningBytes); - } else { - mSweepWarning.setVisibility(View.INVISIBLE); - mSweepWarning.setValue(-1); - } - - updateVertAxisBounds(null); - requestLayout(); - invalidate(); - } - - /** - * Update {@link #mVert} to both show data from {@link NetworkStatsHistory} - * and controls from {@link NetworkPolicy}. - */ - private void updateVertAxisBounds(ChartSweepView activeSweep) { - final long max = mVertMax; - - long newMax = 0; - if (activeSweep != null) { - final int adjustAxis = activeSweep.shouldAdjustAxis(); - if (adjustAxis > 0) { - // hovering around upper edge, grow axis - newMax = max * 11 / 10; - } else if (adjustAxis < 0) { - // hovering around lower edge, shrink axis - newMax = max * 9 / 10; - } else { - newMax = max; - } - } - - // always show known data and policy lines - final long maxSweep = Math.max(mSweepWarning.getValue(), mSweepLimit.getValue()); - final long maxSeries = Math.max(mSeries.getMaxVisible(), mDetailSeries.getMaxVisible()); - final long maxVisible = Math.max(maxSeries, maxSweep) * 12 / 10; - final long maxDefault = Math.max(maxVisible, 50 * MB_IN_BYTES); - newMax = Math.max(maxDefault, newMax); - - // only invalidate when vertMax actually changed - if (newMax != mVertMax) { - mVertMax = newMax; - - final boolean changed = mVert.setBounds(0L, newMax); - mSweepWarning.setValidRange(0L, newMax); - mSweepLimit.setValidRange(0L, newMax); - - if (changed) { - mSeries.invalidatePath(); - mDetailSeries.invalidatePath(); - } - - mGrid.invalidate(); - - // since we just changed axis, make sweep recalculate its value - 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); - } - } - } - - /** - * Control {@link ChartNetworkSeriesView#setEstimateVisible(boolean)} based - * on how close estimate comes to {@link #mSweepWarning}. - */ - private void updateEstimateVisible() { - final long maxEstimate = mSeries.getMaxEstimate(); - - // show estimate when near warning/limit - long interestLine = Long.MAX_VALUE; - if (mSweepWarning.isEnabled()) { - interestLine = mSweepWarning.getValue(); - } else if (mSweepLimit.isEnabled()) { - interestLine = mSweepLimit.getValue(); - } - - if (interestLine < 0) { - interestLine = Long.MAX_VALUE; - } - - final boolean estimateVisible = (maxEstimate >= interestLine * 7 / 10); - mSeries.setEstimateVisible(estimateVisible); - } - - private void sendUpdateAxisDelayed(ChartSweepView sweep, boolean force) { - if (force || !mHandler.hasMessages(MSG_UPDATE_AXIS, sweep)) { - mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_UPDATE_AXIS, sweep), DELAY_MILLIS); - } - } - - private void clearUpdateAxisDelayed(ChartSweepView sweep) { - mHandler.removeMessages(MSG_UPDATE_AXIS, sweep); - } - - private OnSweepListener mVertListener = new OnSweepListener() { - @Override - public void onSweep(ChartSweepView sweep, boolean sweepDone) { - if (sweepDone) { - clearUpdateAxisDelayed(sweep); - updateEstimateVisible(); - - if (sweep == mSweepWarning && mListener != null) { - mListener.onWarningChanged(); - } else if (sweep == mSweepLimit && mListener != null) { - mListener.onLimitChanged(); - } - } else { - // while moving, kick off delayed grow/shrink axis updates - sendUpdateAxisDelayed(sweep, false); - } - } - - @Override - public void requestEdit(ChartSweepView sweep) { - if (sweep == mSweepWarning && mListener != null) { - mListener.requestWarningEdit(); - } else if (sweep == mSweepLimit && mListener != null) { - mListener.requestLimitEdit(); - } - } - }; - - @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; - } - } - } - - public long getInspectStart() { - return mInspectStart; - } - - public long getInspectEnd() { - return mInspectEnd; - } - - public long getWarningBytes() { - return mSweepWarning.getLabelValue(); - } - - public long getLimitBytes() { - return mSweepLimit.getLabelValue(); - } - - /** - * 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 visibleStart, long visibleEnd) { - final boolean changed = mHoriz.setBounds(visibleStart, visibleEnd); - mGrid.setBounds(visibleStart, visibleEnd); - mSeries.setBounds(visibleStart, visibleEnd); - mDetailSeries.setBounds(visibleStart, visibleEnd); - - mInspectStart = visibleStart; - mInspectEnd = visibleEnd; - - requestLayout(); - if (changed) { - mSeries.invalidatePath(); - mDetailSeries.invalidatePath(); - } - - updateVertAxisBounds(null); - updateEstimateVisible(); - updatePrimaryRange(); - } - - private void updatePrimaryRange() { - // prefer showing primary range on detail series, when available - if (mDetailSeries.getVisibility() == View.VISIBLE) { - mSeries.setSecondary(true); - } else { - mSeries.setSecondary(false); - } - } - - public static class TimeAxis implements ChartAxis { - private static final int FIRST_DAY_OF_WEEK = Calendar.getInstance().getFirstDayOfWeek() - 1; - - private long mMin; - private long mMax; - private float mSize; - - public TimeAxis() { - final long currentTime = System.currentTimeMillis(); - setBounds(currentTime - DateUtils.DAY_IN_MILLIS * 30, currentTime); - } - - @Override - public int hashCode() { - return Objects.hash(mMin, mMax, mSize); - } - - @Override - public boolean setBounds(long min, long max) { - if (mMin != min || mMax != max) { - mMin = min; - mMax = max; - return true; - } else { - return false; - } - } - - @Override - public boolean setSize(float size) { - if (mSize != size) { - mSize = size; - return true; - } else { - return false; - } - } - - @Override - public float convertToPoint(long value) { - return (mSize * (value - mMin)) / (mMax - mMin); - } - - @Override - public long convertToValue(float point) { - return (long) (mMin + ((point * (mMax - mMin)) / mSize)); - } - - @Override - public long buildLabel(Resources res, SpannableStringBuilder builder, long value) { - // TODO: convert to better string - builder.replace(0, builder.length(), Long.toString(value)); - return value; - } - - @Override - public float[] getTickPoints() { - final float[] ticks = new float[32]; - int i = 0; - - // tick mark for first day of each week - final Time time = new Time(); - time.set(mMax); - time.monthDay -= time.weekDay - FIRST_DAY_OF_WEEK; - time.hour = time.minute = time.second = 0; - - time.normalize(true); - long timeMillis = time.toMillis(true); - while (timeMillis > mMin) { - if (timeMillis <= mMax) { - ticks[i++] = convertToPoint(timeMillis); - } - time.monthDay -= 7; - time.normalize(true); - timeMillis = time.toMillis(true); - } - - return Arrays.copyOf(ticks, i); - } - - @Override - public int shouldAdjustAxis(long value) { - // time axis never adjusts - return 0; - } - } - - public static class DataAxis implements ChartAxis { - private long mMin; - private long mMax; - private float mSize; - - private static final boolean LOG_SCALE = false; - - @Override - public int hashCode() { - return Objects.hash(mMin, mMax, mSize); - } - - @Override - public boolean setBounds(long min, long max) { - if (mMin != min || mMax != max) { - mMin = min; - mMax = max; - return true; - } else { - return false; - } - } - - @Override - public boolean setSize(float size) { - if (mSize != size) { - mSize = size; - return true; - } else { - return false; - } - } - - @Override - public float convertToPoint(long value) { - if (LOG_SCALE) { - // derived polynomial fit to make lower values more visible - final double normalized = ((double) value - mMin) / (mMax - mMin); - final double fraction = Math.pow(10, - 0.36884343106175121463 * Math.log10(normalized) + -0.04328199452018252624); - return (float) (fraction * mSize); - } else { - return (mSize * (value - mMin)) / (mMax - mMin); - } - } - - @Override - public long convertToValue(float point) { - if (LOG_SCALE) { - final double normalized = point / mSize; - final double fraction = 1.3102228476089056629 - * Math.pow(normalized, 2.7111774693164631640); - return (long) (mMin + (fraction * (mMax - mMin))); - } else { - return (long) (mMin + ((point * (mMax - mMin)) / mSize)); - } - } - - private static final Object sSpanSize = new Object(); - private static final Object sSpanUnit = new Object(); - - @Override - public long buildLabel(Resources res, SpannableStringBuilder builder, long value) { - value = MathUtils.constrain(value, 0, TrafficStats.TB_IN_BYTES); - final BytesResult result = Formatter.formatBytes(res, value, - Formatter.FLAG_SHORTER | Formatter.FLAG_CALCULATE_ROUNDED); - setText(builder, sSpanSize, result.value, "^1"); - setText(builder, sSpanUnit, result.units, "^2"); - return result.roundedBytes; - } - - @Override - public float[] getTickPoints() { - final long range = mMax - mMin; - - // target about 16 ticks on screen, rounded to nearest power of 2 - final long tickJump = roundUpToPowerOfTwo(range / 16); - final int tickCount = (int) (range / tickJump); - final float[] tickPoints = new float[tickCount]; - long value = mMin; - for (int i = 0; i < tickPoints.length; i++) { - tickPoints[i] = convertToPoint(value); - value += tickJump; - } - - return tickPoints; - } - - @Override - public int shouldAdjustAxis(long value) { - final float point = convertToPoint(value); - if (point < mSize * 0.1) { - return -1; - } else if (point > mSize * 0.85) { - return 1; - } else { - return 0; - } - } - } - - private static void setText( - SpannableStringBuilder builder, Object key, CharSequence text, String 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); - } - builder.replace(start, end, text); - } - - private static long roundUpToPowerOfTwo(long i) { - // NOTE: borrowed from Hashtable.roundUpToPowerOfTwo() - - i--; // If input is a power of two, shift its high-order bit right - - // "Smear" the high-order bit all the way to the right - i |= i >>> 1; - i |= i >>> 2; - i |= i >>> 4; - i |= i >>> 8; - i |= i >>> 16; - i |= i >>> 32; - - i++; - - return i > 0 ? i : Long.MAX_VALUE; - } -} diff --git a/src/com/android/settings/widget/ChartNetworkSeriesView.java b/src/com/android/settings/widget/ChartNetworkSeriesView.java deleted file mode 100644 index 7aaba6626a1..00000000000 --- a/src/com/android/settings/widget/ChartNetworkSeriesView.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * 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 static android.text.format.DateUtils.DAY_IN_MILLIS; -import static android.text.format.DateUtils.WEEK_IN_MILLIS; - -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.Path; -import android.graphics.RectF; -import android.net.NetworkStatsHistory; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; - -import com.android.internal.util.Preconditions; -import com.android.settings.R; - -/** - * {@link NetworkStatsHistory} series to render inside a {@link ChartView}, - * using {@link ChartAxis} to map into screen coordinates. - */ -public class ChartNetworkSeriesView extends View { - private static final String TAG = "ChartNetworkSeriesView"; - private static final boolean LOGD = false; - - private static final boolean ESTIMATE_ENABLED = false; - - private ChartAxis mHoriz; - private ChartAxis mVert; - - private Paint mPaintStroke; - private Paint mPaintFill; - private Paint mPaintFillSecondary; - private Paint mPaintEstimate; - - private NetworkStatsHistory mStats; - - private Path mPathStroke; - private Path mPathFill; - private Path mPathEstimate; - - private int mSafeRegion; - - private long mStart; - private long mEnd; - - /** Series will be extended to reach this end time. */ - private long mEndTime = Long.MIN_VALUE; - - private boolean mPathValid = false; - private boolean mEstimateVisible = false; - private boolean mSecondary = false; - - private long mMax; - private long mMaxEstimate; - - public ChartNetworkSeriesView(Context context) { - this(context, null, 0); - } - - 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); - final int safeRegion = a.getDimensionPixelSize( - R.styleable.ChartNetworkSeriesView_safeRegion, 0); - - setChartColor(stroke, fill, fillSecondary); - setSafeRegion(safeRegion); - setWillNotDraw(false); - - a.recycle(); - - mPathStroke = new Path(); - mPathFill = new Path(); - mPathEstimate = new Path(); - } - - 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(4.0f * getResources().getDisplayMetrics().density); - mPaintStroke.setColor(stroke); - mPaintStroke.setStyle(Style.STROKE); - mPaintStroke.setAntiAlias(true); - - mPaintFill = new Paint(); - mPaintFill.setColor(fill); - mPaintFill.setStyle(Style.FILL); - mPaintFill.setAntiAlias(true); - - mPaintFillSecondary = new Paint(); - mPaintFillSecondary.setColor(fillSecondary); - mPaintFillSecondary.setStyle(Style.FILL); - mPaintFillSecondary.setAntiAlias(true); - - mPaintEstimate = new Paint(); - mPaintEstimate.setStrokeWidth(3.0f); - mPaintEstimate.setColor(fillSecondary); - mPaintEstimate.setStyle(Style.STROKE); - mPaintEstimate.setAntiAlias(true); - mPaintEstimate.setPathEffect(new DashPathEffect(new float[] { 10, 10 }, 1)); - } - - public void setSafeRegion(int safeRegion) { - mSafeRegion = safeRegion; - } - - public void bindNetworkStats(NetworkStatsHistory stats) { - mStats = stats; - invalidatePath(); - invalidate(); - } - - public void setBounds(long start, long end) { - mStart = start; - mEnd = end; - } - - public void setSecondary(boolean secondary) { - mSecondary = secondary; - } - - public void invalidatePath() { - mPathValid = false; - mMax = 0; - invalidate(); - } - - /** - * Erase any existing {@link Path} and generate series outline based on - * currently bound {@link NetworkStatsHistory} data. - */ - private void generatePath() { - if (LOGD) Log.d(TAG, "generatePath()"); - - mMax = 0; - mPathStroke.reset(); - mPathFill.reset(); - mPathEstimate.reset(); - mPathValid = true; - - // bail when not enough stats to render - if (mStats == null || mStats.size() < 2) { - return; - } - - final int width = getWidth(); - final int height = getHeight(); - - boolean started = false; - float lastX = 0; - float lastY = height; - long lastTime = mHoriz.convertToValue(lastX); - - // move into starting position - mPathStroke.moveTo(lastX, lastY); - mPathFill.moveTo(lastX, lastY); - - // TODO: count fractional data from first bucket crossing start; - // currently it only accepts first full bucket. - - long totalData = 0; - - NetworkStatsHistory.Entry entry = null; - - final int start = mStats.getIndexBefore(mStart); - final int end = mStats.getIndexAfter(mEnd); - for (int i = start; i <= end; i++) { - entry = mStats.getValues(i, entry); - - final long startTime = entry.bucketStart; - final long endTime = startTime + entry.bucketDuration; - - final float startX = mHoriz.convertToPoint(startTime); - final float endX = mHoriz.convertToPoint(endTime); - - // skip until we find first stats on screen - if (endX < 0) continue; - - // increment by current bucket total - totalData += entry.rxBytes + entry.txBytes; - - final float startY = lastY; - final float endY = mVert.convertToPoint(totalData); - - if (lastTime != startTime) { - // gap in buckets; line to start of current bucket - mPathStroke.lineTo(startX, startY); - mPathFill.lineTo(startX, startY); - } - - // always draw to end of current bucket - mPathStroke.lineTo(endX, endY); - mPathFill.lineTo(endX, endY); - - lastX = endX; - lastY = endY; - lastTime = endTime; - } - - // when data falls short, extend to requested end time - if (lastTime < mEndTime) { - lastX = mHoriz.convertToPoint(mEndTime); - - mPathStroke.lineTo(lastX, lastY); - mPathFill.lineTo(lastX, lastY); - } - - if (LOGD) { - final RectF bounds = new RectF(); - mPathFill.computeBounds(bounds, true); - Log.d(TAG, "onLayout() rendered with bounds=" + bounds.toString() + " and totalData=" - + totalData); - } - - // drop to bottom of graph from current location - mPathFill.lineTo(lastX, height); - mPathFill.lineTo(0, height); - - mMax = totalData; - - if (ESTIMATE_ENABLED) { - // build estimated data - mPathEstimate.moveTo(lastX, lastY); - - final long now = System.currentTimeMillis(); - final long bucketDuration = mStats.getBucketDuration(); - - // long window is average over two weeks - entry = mStats.getValues(lastTime - WEEK_IN_MILLIS * 2, lastTime, now, entry); - final long longWindow = (entry.rxBytes + entry.txBytes) * bucketDuration - / entry.bucketDuration; - - long futureTime = 0; - while (lastX < width) { - futureTime += bucketDuration; - - // short window is day average last week - final long lastWeekTime = lastTime - WEEK_IN_MILLIS + (futureTime % WEEK_IN_MILLIS); - entry = mStats.getValues(lastWeekTime - DAY_IN_MILLIS, lastWeekTime, now, entry); - final long shortWindow = (entry.rxBytes + entry.txBytes) * bucketDuration - / entry.bucketDuration; - - totalData += (longWindow * 7 + shortWindow * 3) / 10; - - lastX = mHoriz.convertToPoint(lastTime + futureTime); - lastY = mVert.convertToPoint(totalData); - - mPathEstimate.lineTo(lastX, lastY); - } - - mMaxEstimate = totalData; - } - - invalidate(); - } - - public void setEndTime(long endTime) { - mEndTime = endTime; - } - - public void setEstimateVisible(boolean estimateVisible) { - mEstimateVisible = ESTIMATE_ENABLED ? estimateVisible : false; - invalidate(); - } - - public long getMaxEstimate() { - return mMaxEstimate; - } - - public long getMaxVisible() { - final long maxVisible = mEstimateVisible ? mMaxEstimate : mMax; - if (maxVisible <= 0 && mStats != null) { - // haven't generated path yet; fall back to raw data - final NetworkStatsHistory.Entry entry = mStats.getValues(mStart, mEnd, null); - return entry.rxBytes + entry.txBytes; - } else { - return maxVisible; - } - } - - @Override - protected void onDraw(Canvas canvas) { - int save; - - if (!mPathValid) { - generatePath(); - } - - if (mEstimateVisible) { - save = canvas.save(); - canvas.clipRect(0, 0, getWidth(), getHeight()); - canvas.drawPath(mPathEstimate, mPaintEstimate); - canvas.restoreToCount(save); - } - - final Paint paintFill = mSecondary ? mPaintFillSecondary : mPaintFill; - - save = canvas.save(); - canvas.clipRect(mSafeRegion, 0, getWidth(), getHeight() - mSafeRegion); - canvas.drawPath(mPathFill, paintFill); - canvas.restoreToCount(save); - } -} diff --git a/src/com/android/settings/widget/ChartView.java b/src/com/android/settings/widget/ChartView.java index 30284bc384b..768a7173013 100644 --- a/src/com/android/settings/widget/ChartView.java +++ b/src/com/android/settings/widget/ChartView.java @@ -30,8 +30,8 @@ import com.android.settings.R; /** * Container for two-dimensional chart, drawn with a combination of - * {@link ChartGridView}, {@link ChartNetworkSeriesView} and {@link ChartSweepView} - * children. The entire chart uses {@link ChartAxis} to map between raw values + * {@link ChartGridView} and {@link ChartSweepView} children. The entire chart uses + * {@link ChartAxis} to map between raw values * and screen coordinates. */ public class ChartView extends FrameLayout { @@ -112,13 +112,7 @@ public class ChartView extends FrameLayout { parentRect.set(mContent); - if (child instanceof ChartNetworkSeriesView) { - // series are always laid out to fill entire graph area - // TODO: handle scrolling for series larger than content area - Gravity.apply(params.gravity, width, height, parentRect, childRect); - child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom); - - } else if (child instanceof ChartGridView) { + if (child instanceof ChartGridView) { // Grid uses some extra room for labels Gravity.apply(params.gravity, width, height, parentRect, childRect); child.layout(childRect.left, childRect.top, childRect.right,