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.net.NetworkPolicy; 19 import android.net.NetworkStatsHistory; 20 import android.net.TrafficStats; 21 import android.support.v7.preference.Preference; 22 import android.support.v7.preference.PreferenceViewHolder; 23 import android.text.SpannableStringBuilder; 24 import android.text.TextUtils; 25 import android.text.format.Formatter; 26 import android.text.style.ForegroundColorSpan; 27 import android.util.AttributeSet; 28 import android.util.SparseIntArray; 29 import com.android.settings.R; 30 import com.android.settings.Utils; 31 import com.android.settings.graph.UsageView; 32 33 public class ChartDataUsagePreference extends Preference { 34 35 // The resolution we show on the graph so that we can squash things down to ints. 36 // Set to half a meg for now. 37 private static final long RESOLUTION = TrafficStats.MB_IN_BYTES / 2; 38 39 private final int mWarningColor; 40 private final int mLimitColor; 41 42 private NetworkPolicy mPolicy; 43 private long mStart; 44 private long mEnd; 45 private NetworkStatsHistory mNetwork; 46 private int mSecondaryColor; 47 private int mSeriesColor; 48 49 public ChartDataUsagePreference(Context context, AttributeSet attrs) { 50 super(context, attrs); 51 setSelectable(false); 52 mLimitColor = Utils.getColorAttr(context, android.R.attr.colorError); 53 mWarningColor = Utils.getColorAttr(context, android.R.attr.textColorSecondary); 54 setLayoutResource(R.layout.data_usage_graph); 55 } 56 57 @Override 58 public void onBindViewHolder(PreferenceViewHolder holder) { 59 super.onBindViewHolder(holder); 60 UsageView chart = (UsageView) holder.findViewById(R.id.data_usage); 61 if (mNetwork == null) return; 62 63 int top = getTop(); 64 chart.clearPaths(); 65 chart.configureGraph(toInt(mEnd - mStart), top); 66 calcPoints(chart); 67 chart.setBottomLabels(new CharSequence[] { 68 Utils.formatDateRange(getContext(), mStart, mStart), 69 Utils.formatDateRange(getContext(), mEnd, mEnd), 70 }); 71 72 bindNetworkPolicy(chart, mPolicy, top); 73 } 74 75 public int getTop() { 76 NetworkStatsHistory.Entry entry = null; 77 long totalData = 0; 78 final int start = mNetwork.getIndexBefore(mStart); 79 final int end = mNetwork.getIndexAfter(mEnd); 80 81 for (int i = start; i <= end; i++) { 82 entry = mNetwork.getValues(i, entry); 83 84 // increment by current bucket total 85 totalData += entry.rxBytes + entry.txBytes; 86 } 87 long policyMax = mPolicy != null ? Math.max(mPolicy.limitBytes, mPolicy.warningBytes) : 0; 88 return (int) (Math.max(totalData, policyMax) / RESOLUTION); 89 } 90 91 private void calcPoints(UsageView chart) { 92 SparseIntArray points = new SparseIntArray(); 93 NetworkStatsHistory.Entry entry = null; 94 95 long totalData = 0; 96 97 final int start = mNetwork.getIndexAfter(mStart); 98 final int end = mNetwork.getIndexAfter(mEnd); 99 if (start < 0) return; 100 101 points.put(0, 0); 102 for (int i = start; i <= end; i++) { 103 entry = mNetwork.getValues(i, entry); 104 105 final long startTime = entry.bucketStart; 106 final long endTime = startTime + entry.bucketDuration; 107 108 // increment by current bucket total 109 totalData += entry.rxBytes + entry.txBytes; 110 111 points.put(toInt(startTime - mStart + 1), (int) (totalData / RESOLUTION)); 112 points.put(toInt(endTime - mStart), (int) (totalData / RESOLUTION)); 113 } 114 if (points.size() > 1) { 115 chart.addPath(points); 116 } 117 } 118 119 private int toInt(long l) { 120 // Don't need that much resolution on these times. 121 return (int) (l / (1000 * 60)); 122 } 123 124 private void bindNetworkPolicy(UsageView chart, NetworkPolicy policy, int top) { 125 CharSequence[] labels = new CharSequence[3]; 126 int middleVisibility = 0; 127 int topVisibility = 0; 128 if (policy == null) { 129 return; 130 } 131 132 if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) { 133 topVisibility = mLimitColor; 134 labels[2] = getLabel(policy.limitBytes, R.string.data_usage_sweep_limit, mLimitColor); 135 } 136 137 if (policy.warningBytes != NetworkPolicy.WARNING_DISABLED) { 138 chart.setDividerLoc((int) (policy.warningBytes / RESOLUTION)); 139 float weight = policy.warningBytes / RESOLUTION / (float) top; 140 float above = 1 - weight; 141 chart.setSideLabelWeights(above, weight); 142 middleVisibility = mWarningColor; 143 labels[1] = getLabel(policy.warningBytes, R.string.data_usage_sweep_warning, 144 mWarningColor); 145 } 146 147 chart.setSideLabels(labels); 148 chart.setDividerColors(middleVisibility, topVisibility); 149 } 150 151 private CharSequence getLabel(long bytes, int str, int mLimitColor) { 152 Formatter.BytesResult result = Formatter.formatBytes(getContext().getResources(), 153 bytes, Formatter.FLAG_SHORTER); 154 CharSequence label = TextUtils.expandTemplate(getContext().getText(str), 155 result.value, result.units); 156 return new SpannableStringBuilder().append(label, new ForegroundColorSpan(mLimitColor), 0); 157 } 158 159 public void setNetworkPolicy(NetworkPolicy policy) { 160 mPolicy = policy; 161 notifyChanged(); 162 } 163 164 public void setVisibleRange(long start, long end) { 165 mStart = start; 166 mEnd = end; 167 notifyChanged(); 168 } 169 170 public long getInspectStart() { 171 return mStart; 172 } 173 174 public long getInspectEnd() { 175 return mEnd; 176 } 177 178 public void setNetworkStats(NetworkStatsHistory network) { 179 mNetwork = network; 180 notifyChanged(); 181 } 182 183 public void setColors(int seriesColor, int secondaryColor) { 184 mSeriesColor = seriesColor; 185 mSecondaryColor = secondaryColor; 186 notifyChanged(); 187 } 188 } 189