diff --git a/res/layout/battery_usage_graph.xml b/res/layout/battery_usage_graph.xml index ddf7d9330a1..79a64a9fd47 100644 --- a/res/layout/battery_usage_graph.xml +++ b/res/layout/battery_usage_graph.xml @@ -41,7 +41,7 @@ + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 6a1ab9c6793..221b61e1168 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5088,9 +5088,9 @@ If you restrict background cellular data, some apps and services won\u2019t work unless you\u2019re connected to Wi\u2011Fi.\n\nThis setting affects all users on this phone. - ^1 ^2\nwarning + ^1 ^2\nwarning - ^1 ^2\nlimit + ^1 ^2\nlimit diff --git a/src/com/android/settings/datausage/ChartDataUsagePreference.java b/src/com/android/settings/datausage/ChartDataUsagePreference.java index f328cf6ea33..63cde648eb4 100644 --- a/src/com/android/settings/datausage/ChartDataUsagePreference.java +++ b/src/com/android/settings/datausage/ChartDataUsagePreference.java @@ -15,18 +15,31 @@ package com.android.settings.datausage; import android.content.Context; -import android.graphics.Color; +import android.content.res.TypedArray; import android.net.NetworkPolicy; import android.net.NetworkStatsHistory; +import android.net.TrafficStats; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceViewHolder; +import android.text.SpannableStringBuilder; +import android.text.TextUtils; +import android.text.format.Formatter; +import android.text.style.ForegroundColorSpan; import android.util.AttributeSet; +import android.util.SparseIntArray; import com.android.settings.R; -import com.android.settings.widget.ChartDataUsageView; -import com.android.settings.widget.ChartNetworkSeriesView; +import com.android.settings.Utils; +import com.android.settingslib.graph.UsageView; public class ChartDataUsagePreference extends Preference { + // The resolution we show on the graph so that we can squash things down to ints. + // Set to half a meg for now. + private static final long RESOLUTION = TrafficStats.MB_IN_BYTES / 2; + + private final int mWarningColor; + private final int mLimitColor; + private NetworkPolicy mPolicy; private long mStart; private long mEnd; @@ -36,21 +49,123 @@ public class ChartDataUsagePreference extends Preference { public ChartDataUsagePreference(Context context, AttributeSet attrs) { super(context, attrs); - setLayoutResource(R.layout.data_usage_chart); + setSelectable(false); + // TODO: Resource. + mLimitColor = 0xfff4511e; + TypedArray a = context.getTheme().obtainStyledAttributes( + new int[]{android.R.attr.textColorSecondary}); + mWarningColor = a.getColor(0, 0); + setLayoutResource(R.layout.data_usage_graph); } @Override public void onBindViewHolder(PreferenceViewHolder holder) { super.onBindViewHolder(holder); - ChartDataUsageView chart = (ChartDataUsageView) holder.itemView; - chart.setVisibleRange(mStart, mEnd); - chart.bindNetworkPolicy(mPolicy); - chart.bindNetworkStats(mNetwork); - ChartNetworkSeriesView series = (ChartNetworkSeriesView) holder.findViewById(R.id.series); - series.setChartColor(Color.BLACK, mSeriesColor, mSecondaryColor); + UsageView chart = (UsageView) holder.findViewById(R.id.data_usage); + if (mNetwork == null) return; + + int top = getTop(); + chart.clearPaths(); + chart.configureGraph((int) (mEnd - mStart), top, false, false); + calcPoints(chart); + chart.setBottomLabels(new CharSequence[] { + Utils.formatDateRange(getContext(), mStart, mStart), + Utils.formatDateRange(getContext(), mEnd, mEnd), + }); + + bindNetworkPolicy(chart, mPolicy, top); } - public void bindNetworkPolicy(NetworkPolicy policy) { + public int getTop() { + NetworkStatsHistory.Entry entry = null; + long totalData = 0; + final int start = mNetwork.getIndexBefore(mStart); + final int end = mNetwork.getIndexAfter(mEnd); + + for (int i = start; i <= end; i++) { + entry = mNetwork.getValues(i, entry); + + // increment by current bucket total + totalData += entry.rxBytes + entry.txBytes; + } + long policyMax = mPolicy != null ? Math.max(mPolicy.limitBytes, mPolicy.warningBytes) : 0; + return (int) (Math.max(totalData, policyMax) / RESOLUTION); + } + + private void calcPoints(UsageView chart) { + SparseIntArray points = new SparseIntArray(); + NetworkStatsHistory.Entry entry = null; + + long lastTime = -1; + long totalData = 0; + + final int start = mNetwork.getIndexAfter(mStart); + final int end = mNetwork.getIndexAfter(mEnd); + if (start < 0) return; + + points.put(0, 0); + for (int i = start; i <= end; i++) { + entry = mNetwork.getValues(i, entry); + + final long startTime = entry.bucketStart; + final long endTime = startTime + entry.bucketDuration; + + // increment by current bucket total + totalData += entry.rxBytes + entry.txBytes; + + if (lastTime != startTime) { + if (points.size() > 1) { + chart.addPath(points); + } + points.clear(); + } + + points.put((int) (startTime - mStart + 1), (int) (totalData / RESOLUTION)); + points.put((int) (endTime - mStart), (int) (totalData / RESOLUTION)); + + lastTime = endTime; + } + if (points.size() > 1) { + chart.addPath(points); + } + } + + private void bindNetworkPolicy(UsageView chart, NetworkPolicy policy, int top) { + CharSequence[] labels = new CharSequence[3]; + int middleVisibility = 0; + int topVisibility = 0; + if (policy == null) { + return; + } + + if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) { + topVisibility = mLimitColor; + labels[2] = getLabel(policy.limitBytes, R.string.data_usage_sweep_limit, mLimitColor); + } + + if (policy.warningBytes != NetworkPolicy.WARNING_DISABLED) { + chart.setDividerLoc((int) (policy.warningBytes / RESOLUTION)); + float weight = policy.warningBytes / RESOLUTION / (float) top; + float above = 1 - weight; + chart.setSideLabelWeights(above, weight); + middleVisibility = mWarningColor; + labels[1] = getLabel(policy.warningBytes, R.string.data_usage_sweep_warning, + mWarningColor); + } + + chart.setSideLabels(labels); + chart.setDividerColors(middleVisibility, topVisibility); + } + + private CharSequence getLabel(long bytes, int str, int mLimitColor) { + Formatter.BytesResult result = Formatter.formatBytes(getContext().getResources(), + bytes, Formatter.FLAG_SHORTER); + CharSequence label = TextUtils.expandTemplate(getContext().getText(str), + result.value, result.units); + return new SpannableStringBuilder().append(label, new ForegroundColorSpan(mLimitColor), 0); + } + + public void setNetworkPolicy(NetworkPolicy policy) { mPolicy = policy; notifyChanged(); } @@ -69,7 +184,7 @@ public class ChartDataUsagePreference extends Preference { return mEnd; } - public void bindNetworkStats(NetworkStatsHistory network) { + public void setNetworkStats(NetworkStatsHistory network) { mNetwork = network; notifyChanged(); } diff --git a/src/com/android/settings/datausage/DataUsageList.java b/src/com/android/settings/datausage/DataUsageList.java index b32ea01b0b6..7ac81f58bad 100644 --- a/src/com/android/settings/datausage/DataUsageList.java +++ b/src/com/android/settings/datausage/DataUsageList.java @@ -255,7 +255,7 @@ public class DataUsageList extends DataUsageBase { final NetworkPolicy policy = services.mPolicyEditor.getPolicy(mTemplate); //SUB SELECT if (isNetworkPolicyModifiable(policy, mSubId) && isMobileDataAvailable(mSubId)) { - mChart.bindNetworkPolicy(policy); + mChart.setNetworkPolicy(policy); mHeader.findViewById(R.id.filter_settings).setVisibility(View.VISIBLE); mHeader.findViewById(R.id.filter_settings).setOnClickListener( new View.OnClickListener() { @@ -269,7 +269,7 @@ public class DataUsageList extends DataUsageBase { }); } else { // controls are disabled; don't bind warning/limit sweeps - mChart.bindNetworkPolicy(null); + mChart.setNetworkPolicy(null); mHeader.findViewById(R.id.filter_settings).setVisibility(View.GONE); } @@ -521,7 +521,7 @@ public class DataUsageList extends DataUsageBase { public void onLoadFinished(Loader loader, ChartData data) { setLoading(false, true); mChartData = data; - mChart.bindNetworkStats(mChartData.network); + mChart.setNetworkStats(mChartData.network); // calcuate policy cycles based on available data updatePolicy(true); @@ -530,7 +530,7 @@ public class DataUsageList extends DataUsageBase { @Override public void onLoaderReset(Loader loader) { mChartData = null; - mChart.bindNetworkStats(null); + mChart.setNetworkStats(null); } };