QS: Cellular usage warning marker + policy cycle.
Add warning marker to graph from policy, and use the cycle day from policy to determine the usage period. Change-Id: I31711eea6a0bf54ad0eb5841d2aa9b8e5927ed58 (cherry picked from commit b5e88019cd69d9320639b6736fabf7f407444967)
This commit is contained in:
@@ -44,6 +44,7 @@
|
||||
<color name="qs_detail_empty">#24B0BEC5</color><!-- 14% blue grey 200-->
|
||||
<color name="data_usage_secondary">#99FFFFFF</color><!-- 60% white -->
|
||||
<color name="data_usage_graph_track">#33FFFFFF</color><!-- 20% white -->
|
||||
<color name="data_usage_graph_warning">#FFFFFFFF</color>
|
||||
<color name="status_bar_clock_color">#33FFFFFF</color>
|
||||
|
||||
<!-- Tint color for the content on the notification overflow card. -->
|
||||
|
||||
@@ -572,6 +572,8 @@
|
||||
<string name="quick_settings_cellular_detail_data_used"><xliff:g id="data_used" example="2.0 GB">%s</xliff:g> used</string>
|
||||
<!-- QuickSettings: Cellular detail panel, data limit format string [CHAR LIMIT=NONE] -->
|
||||
<string name="quick_settings_cellular_detail_data_limit"><xliff:g id="data_limit" example="2.0 GB">%s</xliff:g> limit</string>
|
||||
<!-- QuickSettings: Cellular detail panel, data warning format string [CHAR LIMIT=NONE] -->
|
||||
<string name="quick_settings_cellular_detail_data_warning"><xliff:g id="data_limit" example="2.0 GB">%s</xliff:g> warning</string>
|
||||
|
||||
<!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
|
||||
<string name="recents_empty_message">No recent apps</string>
|
||||
|
||||
@@ -28,34 +28,34 @@ import com.android.systemui.R;
|
||||
|
||||
public class DataUsageGraph extends View {
|
||||
|
||||
private final int mBackgroundColor;
|
||||
private final int mTrackColor;
|
||||
private final int mUsageColor;
|
||||
private final int mOverlimitColor;
|
||||
private final int mWarningColor;
|
||||
private final int mMarkerWidth;
|
||||
private final RectF mTmpRect = new RectF();
|
||||
private final Paint mTmpPaint = new Paint();
|
||||
|
||||
private long mMaxLevel = 1;
|
||||
private long mLimitLevel;
|
||||
private long mWarningLevel;
|
||||
private long mUsageLevel;
|
||||
private long mMaxLevel;
|
||||
|
||||
public DataUsageGraph(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
final Resources res = context.getResources();
|
||||
mBackgroundColor = res.getColor(R.color.system_primary_color);
|
||||
mTrackColor = res.getColor(R.color.data_usage_graph_track);
|
||||
mUsageColor = res.getColor(R.color.system_accent_color);
|
||||
mOverlimitColor = res.getColor(R.color.system_warning_color);
|
||||
mWarningColor = res.getColor(R.color.data_usage_graph_warning);
|
||||
mMarkerWidth = res.getDimensionPixelSize(R.dimen.data_usage_graph_marker_width);
|
||||
}
|
||||
|
||||
public void setLevels(long maxLevel, long limitLevel, long warningLevel, long usageLevel) {
|
||||
mMaxLevel = Math.max(maxLevel, 1);
|
||||
mLimitLevel = limitLevel;
|
||||
mWarningLevel = warningLevel;
|
||||
mUsageLevel = usageLevel;
|
||||
public void setLevels(long limitLevel, long warningLevel, long usageLevel) {
|
||||
mLimitLevel = Math.max(0, limitLevel);
|
||||
mWarningLevel = Math.max(0, warningLevel);
|
||||
mUsageLevel = Math.max(0, usageLevel);
|
||||
mMaxLevel = Math.max(Math.max(Math.max(mLimitLevel, mWarningLevel), mUsageLevel), 1);
|
||||
postInvalidate();
|
||||
}
|
||||
|
||||
@@ -68,21 +68,22 @@ public class DataUsageGraph extends View {
|
||||
final int w = getWidth();
|
||||
final int h = getHeight();
|
||||
|
||||
// draw track
|
||||
r.set(0, 0, w, h);
|
||||
p.setColor(mTrackColor);
|
||||
canvas.drawRect(r, p);
|
||||
|
||||
final boolean hasLimit = mLimitLevel > 0;
|
||||
final boolean overLimit = hasLimit && mUsageLevel > mLimitLevel;
|
||||
|
||||
final long maxLevel = hasLimit ? Math.max(mUsageLevel, mLimitLevel) : mMaxLevel;
|
||||
final long usageLevel = hasLimit ? Math.min(mUsageLevel, mLimitLevel) : mUsageLevel;
|
||||
float usageRight = w * (usageLevel / (float) maxLevel);
|
||||
final boolean overLimit = mLimitLevel > 0 && mUsageLevel > mLimitLevel;
|
||||
float usageRight = w * (mUsageLevel / (float) mMaxLevel);
|
||||
if (overLimit) {
|
||||
usageRight -= (mMarkerWidth / 2);
|
||||
usageRight = Math.min(usageRight, w - mMarkerWidth * 2);
|
||||
usageRight = Math.max(usageRight, mMarkerWidth);
|
||||
// compute the gap
|
||||
usageRight = w * (mLimitLevel / (float) mMaxLevel) - (mMarkerWidth / 2);
|
||||
usageRight = Math.min(Math.max(usageRight, mMarkerWidth), w - mMarkerWidth * 2);
|
||||
|
||||
// draw overlimit
|
||||
r.set(usageRight + mMarkerWidth, 0, w, h);
|
||||
p.setColor(mOverlimitColor);
|
||||
canvas.drawRect(r, p);
|
||||
} else {
|
||||
// draw track
|
||||
r.set(0, 0, w, h);
|
||||
p.setColor(mTrackColor);
|
||||
canvas.drawRect(r, p);
|
||||
}
|
||||
|
||||
// draw usage
|
||||
@@ -90,16 +91,11 @@ public class DataUsageGraph extends View {
|
||||
p.setColor(mUsageColor);
|
||||
canvas.drawRect(r, p);
|
||||
|
||||
if (overLimit) {
|
||||
// draw gap
|
||||
r.set(usageRight, 0, usageRight + mMarkerWidth, h);
|
||||
p.setColor(mBackgroundColor);
|
||||
canvas.drawRect(r, p);
|
||||
|
||||
// draw overlimit
|
||||
r.set(usageRight + mMarkerWidth, 0, w, h);
|
||||
p.setColor(mOverlimitColor);
|
||||
canvas.drawRect(r, p);
|
||||
}
|
||||
// draw warning marker
|
||||
float warningLeft = w * (mWarningLevel / (float) mMaxLevel) - mMarkerWidth / 2;
|
||||
warningLeft = Math.min(Math.max(warningLeft, 0), w - mMarkerWidth);
|
||||
r.set(warningLeft, 0, warningLeft + mMarkerWidth, h);
|
||||
p.setColor(mWarningColor);
|
||||
canvas.drawRect(r, p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,21 +216,27 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
|
||||
final DataUsageInfo info = mController.getDataUsageInfo();
|
||||
if (info == null) return v;
|
||||
final Resources res = mContext.getResources();
|
||||
int titleId;
|
||||
long bytes;
|
||||
final int titleId;
|
||||
final long bytes;
|
||||
int usageColor = R.color.system_accent_color;
|
||||
String top = null, bottom = null;
|
||||
if (info.limitLevel <= 0) { // no limit
|
||||
final String top;
|
||||
String bottom = null;
|
||||
if (info.usageLevel < info.warningLevel || info.limitLevel <= 0) {
|
||||
// under warning, or no limit
|
||||
titleId = R.string.quick_settings_cellular_detail_data_usage;
|
||||
bytes = info.usageLevel;
|
||||
} else if (info.usageLevel <= info.limitLevel) { // under limit
|
||||
top = res.getString(R.string.quick_settings_cellular_detail_data_warning,
|
||||
formatBytes(info.warningLevel));
|
||||
} else if (info.usageLevel <= info.limitLevel) {
|
||||
// over warning, under limit
|
||||
titleId = R.string.quick_settings_cellular_detail_remaining_data;
|
||||
bytes = info.limitLevel - info.usageLevel;
|
||||
top = res.getString(R.string.quick_settings_cellular_detail_data_used,
|
||||
formatBytes(info.usageLevel));
|
||||
bottom = res.getString(R.string.quick_settings_cellular_detail_data_limit,
|
||||
formatBytes(info.limitLevel));
|
||||
} else { // over limit
|
||||
} else {
|
||||
// over limit
|
||||
titleId = R.string.quick_settings_cellular_detail_over_limit;
|
||||
bytes = info.usageLevel - info.limitLevel;
|
||||
top = res.getString(R.string.quick_settings_cellular_detail_data_used,
|
||||
@@ -246,7 +252,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
|
||||
usage.setText(formatBytes(bytes));
|
||||
usage.setTextColor(res.getColor(usageColor));
|
||||
final DataUsageGraph graph = (DataUsageGraph) v.findViewById(R.id.usage_graph);
|
||||
graph.setLevels(info.maxLevel, info.limitLevel, info.warningLevel, info.usageLevel);
|
||||
graph.setLevels(info.limitLevel, info.warningLevel, info.usageLevel);
|
||||
final TextView carrier = (TextView) v.findViewById(R.id.usage_carrier_text);
|
||||
carrier.setText(info.carrier);
|
||||
final TextView period = (TextView) v.findViewById(R.id.usage_period_text);
|
||||
|
||||
@@ -20,6 +20,8 @@ import static android.net.ConnectivityManager.TYPE_MOBILE;
|
||||
import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
|
||||
import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
|
||||
import static android.telephony.TelephonyManager.SIM_STATE_READY;
|
||||
import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
|
||||
import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
@@ -33,19 +35,23 @@ import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.format.DateUtils;
|
||||
import android.text.format.Time;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.systemui.statusbar.policy.NetworkController.DataUsageInfo;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
public class MobileDataController {
|
||||
private static final String TAG = "MobileDataController";
|
||||
private static final boolean DEBUG = true;
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
private static final SimpleDateFormat MMM_D = new SimpleDateFormat("MMM d");
|
||||
private static final long DEFAULT_WARNING_LEVEL = 2L * 1024 * 1024 * 1024;
|
||||
private static final int FIELDS = FIELD_RX_BYTES | FIELD_TX_BYTES;
|
||||
private static final StringBuilder PERIOD_BUILDER = new StringBuilder(50);
|
||||
private static final java.util.Formatter PERIOD_FORMATTER = new java.util.Formatter(
|
||||
PERIOD_BUILDER, Locale.getDefault());
|
||||
|
||||
private final Context mContext;
|
||||
private final TelephonyManager mTelephonyManager;
|
||||
@@ -87,6 +93,13 @@ public class MobileDataController {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Time addMonth(Time t, int months) {
|
||||
final Time rt = new Time(t);
|
||||
rt.set(t.monthDay, t.month + months, t.year);
|
||||
rt.normalize(false);
|
||||
return rt;
|
||||
}
|
||||
|
||||
public DataUsageInfo getDataUsageInfo() {
|
||||
final String subscriberId = getActiveSubscriberId(mContext);
|
||||
if (subscriberId == null) {
|
||||
@@ -101,9 +114,28 @@ public class MobileDataController {
|
||||
try {
|
||||
final NetworkStatsHistory history = mSession.getHistoryForNetwork(template, FIELDS);
|
||||
final long now = System.currentTimeMillis();
|
||||
// period = last 4 wks for now
|
||||
final long start = now - DateUtils.WEEK_IN_MILLIS * 4;
|
||||
final long end = now;
|
||||
final long start, end;
|
||||
if (policy != null && policy.cycleDay > 0) {
|
||||
// period = determined from cycleDay
|
||||
if (DEBUG) Log.d(TAG, "Cycle day=" + policy.cycleDay + " tz="
|
||||
+ policy.cycleTimezone);
|
||||
final Time nowTime = new Time(policy.cycleTimezone);
|
||||
nowTime.setToNow();
|
||||
final Time policyTime = new Time(nowTime);
|
||||
policyTime.set(policy.cycleDay, policyTime.month, policyTime.year);
|
||||
policyTime.normalize(false);
|
||||
if (nowTime.after(policyTime)) {
|
||||
start = policyTime.toMillis(false);
|
||||
end = addMonth(policyTime, 1).toMillis(false);
|
||||
} else {
|
||||
start = addMonth(policyTime, -1).toMillis(false);
|
||||
end = policyTime.toMillis(false);
|
||||
}
|
||||
} else {
|
||||
// period = last 4 wks
|
||||
end = now;
|
||||
start = now - DateUtils.WEEK_IN_MILLIS * 4;
|
||||
}
|
||||
final long callStart = System.currentTimeMillis();
|
||||
final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null);
|
||||
final long callEnd = System.currentTimeMillis();
|
||||
@@ -115,12 +147,13 @@ public class MobileDataController {
|
||||
}
|
||||
final long totalBytes = entry.rxBytes + entry.txBytes;
|
||||
final DataUsageInfo usage = new DataUsageInfo();
|
||||
usage.maxLevel = (long) (totalBytes / .4);
|
||||
usage.usageLevel = totalBytes;
|
||||
usage.period = MMM_D.format(new Date(start)) + " - " + MMM_D.format(new Date(end));
|
||||
usage.period = formatDateRange(start, end);
|
||||
if (policy != null) {
|
||||
usage.limitLevel = policy.limitBytes > 0 ? policy.limitBytes : 0;
|
||||
usage.warningLevel = policy.warningBytes > 0 ? policy.warningBytes : 0;
|
||||
} else {
|
||||
usage.warningLevel = DEFAULT_WARNING_LEVEL;
|
||||
}
|
||||
return usage;
|
||||
} catch (RemoteException e) {
|
||||
@@ -178,6 +211,15 @@ public class MobileDataController {
|
||||
return actualSubscriberId;
|
||||
}
|
||||
|
||||
private String formatDateRange(long start, long end) {
|
||||
final int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH;
|
||||
synchronized (PERIOD_BUILDER) {
|
||||
PERIOD_BUILDER.setLength(0);
|
||||
return DateUtils.formatDateRange(mContext, PERIOD_FORMATTER, start, end, flags, null)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
void onMobileDataEnabled(boolean enabled);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,6 @@ public interface NetworkController {
|
||||
public static class DataUsageInfo {
|
||||
public String carrier;
|
||||
public String period;
|
||||
public long maxLevel;
|
||||
public long limitLevel;
|
||||
public long warningLevel;
|
||||
public long usageLevel;
|
||||
|
||||
Reference in New Issue
Block a user