| /* | |
| * Copyright (C) 2016 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.datausage; | |
| import android.content.Context; | |
| 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.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; | |
| private NetworkStatsHistory mNetwork; | |
| private int mSecondaryColor; | |
| private int mSeriesColor; | |
| public ChartDataUsagePreference(Context context, AttributeSet attrs) { | |
| super(context, attrs); | |
| 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); | |
| UsageView chart = (UsageView) holder.findViewById(R.id.data_usage); | |
| if (mNetwork == null) return; | |
| int top = getTop(); | |
| chart.clearPaths(); | |
| chart.configureGraph(toInt(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 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 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; | |
| points.put(toInt(startTime - mStart + 1), (int) (totalData / RESOLUTION)); | |
| points.put(toInt(endTime - mStart), (int) (totalData / RESOLUTION)); | |
| } | |
| if (points.size() > 1) { | |
| chart.addPath(points); | |
| } | |
| } | |
| private int toInt(long l) { | |
| // Don't need that much resolution on these times. | |
| return (int) (l / (1000 * 60)); | |
| } | |
| 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(); | |
| } | |
| public void setVisibleRange(long start, long end) { | |
| mStart = start; | |
| mEnd = end; | |
| notifyChanged(); | |
| } | |
| public long getInspectStart() { | |
| return mStart; | |
| } | |
| public long getInspectEnd() { | |
| return mEnd; | |
| } | |
| public void setNetworkStats(NetworkStatsHistory network) { | |
| mNetwork = network; | |
| notifyChanged(); | |
| } | |
| public void setColors(int seriesColor, int secondaryColor) { | |
| mSeriesColor = seriesColor; | |
| mSecondaryColor = secondaryColor; | |
| notifyChanged(); | |
| } | |
| } |