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:
John Spurlock
2014-07-13 16:07:57 -04:00
parent 1e6eb17a22
commit d11a19b8ea
6 changed files with 95 additions and 49 deletions

View File

@@ -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. -->

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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;