1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.settings.datausage; 16 17 import android.content.Context; 18 import android.content.res.TypedArray; 19 import android.net.NetworkPolicy; 20 import android.net.NetworkStatsHistory; 21 import android.net.TrafficStats; 22 import android.support.v7.preference.Preference; 23 import android.support.v7.preference.PreferenceViewHolder; 24 import android.text.SpannableStringBuilder; 25 import android.text.TextUtils; 26 import android.text.format.Formatter; 27 import android.text.style.ForegroundColorSpan; 28 import android.util.AttributeSet; 29 import android.util.SparseIntArray; 30 import com.android.settings.R; 31 import com.android.settings.Utils; 32 import com.android.settingslib.graph.UsageView; 33 34 public class ChartDataUsagePreference extends Preference { 35 36 // The resolution we show on the graph so that we can squash things down to ints. 37 // Set to half a meg for now. 38 private static final long RESOLUTION = TrafficStats.MB_IN_BYTES / 2; 39 40 private final int mWarningColor; 41 private final int mLimitColor; 42 43 private NetworkPolicy mPolicy; 44 private long mStart; 45 private long mEnd; 46 private NetworkStatsHistory mNetwork; 47 private int mSecondaryColor; 48 private int mSeriesColor; 49 ChartDataUsagePreference(Context context, AttributeSet attrs)50 public ChartDataUsagePreference(Context context, AttributeSet attrs) { 51 super(context, attrs); 52 setSelectable(false); 53 // TODO: Resource. 54 mLimitColor = 0xfff4511e; 55 TypedArray a = context.getTheme().obtainStyledAttributes( 56 new int[]{android.R.attr.textColorSecondary}); 57 mWarningColor = a.getColor(0, 0); 58 setLayoutResource(R.layout.data_usage_graph); 59 } 60 61 @Override onBindViewHolder(PreferenceViewHolder holder)62 public void onBindViewHolder(PreferenceViewHolder holder) { 63 super.onBindViewHolder(holder); 64 UsageView chart = (UsageView) holder.findViewById(R.id.data_usage); 65 if (mNetwork == null) return; 66 67 int top = getTop(); 68 chart.clearPaths(); 69 chart.configureGraph(toInt(mEnd - mStart), top, false, false); 70 calcPoints(chart); 71 chart.setBottomLabels(new CharSequence[] { 72 Utils.formatDateRange(getContext(), mStart, mStart), 73 Utils.formatDateRange(getContext(), mEnd, mEnd), 74 }); 75 76 bindNetworkPolicy(chart, mPolicy, top); 77 } 78 getTop()79 public int getTop() { 80 NetworkStatsHistory.Entry entry = null; 81 long totalData = 0; 82 final int start = mNetwork.getIndexBefore(mStart); 83 final int end = mNetwork.getIndexAfter(mEnd); 84 85 for (int i = start; i <= end; i++) { 86 entry = mNetwork.getValues(i, entry); 87 88 // increment by current bucket total 89 totalData += entry.rxBytes + entry.txBytes; 90 } 91 long policyMax = mPolicy != null ? Math.max(mPolicy.limitBytes, mPolicy.warningBytes) : 0; 92 return (int) (Math.max(totalData, policyMax) / RESOLUTION); 93 } 94 calcPoints(UsageView chart)95 private void calcPoints(UsageView chart) { 96 SparseIntArray points = new SparseIntArray(); 97 NetworkStatsHistory.Entry entry = null; 98 99 long totalData = 0; 100 101 final int start = mNetwork.getIndexAfter(mStart); 102 final int end = mNetwork.getIndexAfter(mEnd); 103 if (start < 0) return; 104 105 points.put(0, 0); 106 for (int i = start; i <= end; i++) { 107 entry = mNetwork.getValues(i, entry); 108 109 final long startTime = entry.bucketStart; 110 final long endTime = startTime + entry.bucketDuration; 111 112 // increment by current bucket total 113 totalData += entry.rxBytes + entry.txBytes; 114 115 points.put(toInt(startTime - mStart + 1), (int) (totalData / RESOLUTION)); 116 points.put(toInt(endTime - mStart), (int) (totalData / RESOLUTION)); 117 } 118 if (points.size() > 1) { 119 chart.addPath(points); 120 } 121 } 122 toInt(long l)123 private int toInt(long l) { 124 // Don't need that much resolution on these times. 125 return (int) (l / (1000 * 60)); 126 } 127 bindNetworkPolicy(UsageView chart, NetworkPolicy policy, int top)128 private void bindNetworkPolicy(UsageView chart, NetworkPolicy policy, int top) { 129 CharSequence[] labels = new CharSequence[3]; 130 int middleVisibility = 0; 131 int topVisibility = 0; 132 if (policy == null) { 133 return; 134 } 135 136 if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) { 137 topVisibility = mLimitColor; 138 labels[2] = getLabel(policy.limitBytes, R.string.data_usage_sweep_limit, mLimitColor); 139 } 140 141 if (policy.warningBytes != NetworkPolicy.WARNING_DISABLED) { 142 chart.setDividerLoc((int) (policy.warningBytes / RESOLUTION)); 143 float weight = policy.warningBytes / RESOLUTION / (float) top; 144 float above = 1 - weight; 145 chart.setSideLabelWeights(above, weight); 146 middleVisibility = mWarningColor; 147 labels[1] = getLabel(policy.warningBytes, R.string.data_usage_sweep_warning, 148 mWarningColor); 149 } 150 151 chart.setSideLabels(labels); 152 chart.setDividerColors(middleVisibility, topVisibility); 153 } 154 getLabel(long bytes, int str, int mLimitColor)155 private CharSequence getLabel(long bytes, int str, int mLimitColor) { 156 Formatter.BytesResult result = Formatter.formatBytes(getContext().getResources(), 157 bytes, Formatter.FLAG_SHORTER); 158 CharSequence label = TextUtils.expandTemplate(getContext().getText(str), 159 result.value, result.units); 160 return new SpannableStringBuilder().append(label, new ForegroundColorSpan(mLimitColor), 0); 161 } 162 setNetworkPolicy(NetworkPolicy policy)163 public void setNetworkPolicy(NetworkPolicy policy) { 164 mPolicy = policy; 165 notifyChanged(); 166 } 167 setVisibleRange(long start, long end)168 public void setVisibleRange(long start, long end) { 169 mStart = start; 170 mEnd = end; 171 notifyChanged(); 172 } 173 getInspectStart()174 public long getInspectStart() { 175 return mStart; 176 } 177 getInspectEnd()178 public long getInspectEnd() { 179 return mEnd; 180 } 181 setNetworkStats(NetworkStatsHistory network)182 public void setNetworkStats(NetworkStatsHistory network) { 183 mNetwork = network; 184 notifyChanged(); 185 } 186 setColors(int seriesColor, int secondaryColor)187 public void setColors(int seriesColor, int secondaryColor) { 188 mSeriesColor = seriesColor; 189 mSecondaryColor = secondaryColor; 190 notifyChanged(); 191 } 192 } 193