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