Data usage app labels and system clustering.

Cluster all non-applications under single "Android OS" label, and
correctly label uninstalled applications.  Match API changes that now
return correct historical usage around current time.

Bug: 4975314, 4691901
Change-Id: Icec1c54ff3404e1525878516b0a438f757dcb758
This commit is contained in:
Jeff Sharkey
2011-07-12 20:20:46 -07:00
parent ebae659fc7
commit 518bc9df8b
3 changed files with 66 additions and 54 deletions

View File

@@ -3427,6 +3427,9 @@ found in the list of installed applications.</string>
<!-- Label displaying current network data usage limit threshold. [CHAR LIMIT=18] --> <!-- Label displaying current network data usage limit threshold. [CHAR LIMIT=18] -->
<string name="data_usage_sweep_limit"><font size="21"><xliff:g id="number" example="128">^1</xliff:g></font> <font size="9"><xliff:g id="unit" example="KB">^2</xliff:g></font>\n<font size="12">limit</font></string> <string name="data_usage_sweep_limit"><font size="21"><xliff:g id="number" example="128">^1</xliff:g></font> <font size="9"><xliff:g id="unit" example="KB">^2</xliff:g></font>\n<font size="12">limit</font></string>
<!-- Title of data usage item that represents all uninstalled applications. [CHAR LIMIT=48] -->
<string name="data_usage_uninstalled_apps">Removed apps</string>
<!-- Button at the bottom of the CryptKeeper screen to make an emergency call. --> <!-- Button at the bottom of the CryptKeeper screen to make an emergency call. -->
<string name="cryptkeeper_emergency_call">Emergency call</string> <string name="cryptkeeper_emergency_call">Emergency call</string>
<!-- Button at the bottom of the CryptKeeper screen that lets the user return to a call --> <!-- Button at the bottom of the CryptKeeper screen that lets the user return to a call -->

View File

@@ -48,6 +48,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.INetworkPolicyManager; import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService; import android.net.INetworkStatsService;
@@ -56,6 +57,7 @@ import android.net.NetworkPolicyManager;
import android.net.NetworkStats; import android.net.NetworkStats;
import android.net.NetworkStatsHistory; import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate; import android.net.NetworkTemplate;
import android.net.TrafficStats;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.RemoteException; import android.os.RemoteException;
@@ -105,7 +107,6 @@ import com.android.settings.widget.DataUsageChartView.DataUsageChartListener;
import com.google.android.collect.Lists; import com.google.android.collect.Lists;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Locale; import java.util.Locale;
@@ -736,27 +737,6 @@ public class DataUsageSummary extends Fragment {
} }
} }
/**
* Return full time bounds (earliest and latest time recorded) of the given
* {@link NetworkStatsHistory}.
*/
public static long[] getHistoryBounds(NetworkStatsHistory history) {
final long currentTime = System.currentTimeMillis();
long start = currentTime;
long end = currentTime;
NetworkStatsHistory.Entry entry = null;
if (history.size() > 0) {
entry = history.getValues(0, entry);
start = entry.bucketStart;
entry = history.getValues(history.size() - 1, entry);
end = entry.bucketStart + entry.bucketDuration;
}
return new long[] { start, end };
}
/** /**
* Rebuild {@link #mCycleAdapter} based on {@link NetworkPolicy#cycleDay} * Rebuild {@link #mCycleAdapter} based on {@link NetworkPolicy#cycleDay}
* and available {@link NetworkStatsHistory} data. Always selects the newest * and available {@link NetworkStatsHistory} data. Always selects the newest
@@ -766,11 +746,15 @@ public class DataUsageSummary extends Fragment {
mCycleAdapter.clear(); mCycleAdapter.clear();
final Context context = mCycleSpinner.getContext(); final Context context = mCycleSpinner.getContext();
long historyStart = mHistory.getStart();
long historyEnd = mHistory.getEnd();
final long[] bounds = getHistoryBounds(mHistory); if (historyStart == Long.MAX_VALUE || historyEnd == Long.MIN_VALUE) {
final long historyStart = bounds[0]; historyStart = System.currentTimeMillis();
final long historyEnd = bounds[1]; historyEnd = System.currentTimeMillis();
}
boolean hasCycles = false;
if (policy != null) { if (policy != null) {
// find the next cycle boundary // find the next cycle boundary
long cycleEnd = computeNextCycleBoundary(historyEnd, policy); long cycleEnd = computeNextCycleBoundary(historyEnd, policy);
@@ -784,23 +768,24 @@ public class DataUsageSummary extends Fragment {
+ historyStart); + historyStart);
mCycleAdapter.add(new CycleItem(context, cycleStart, cycleEnd)); mCycleAdapter.add(new CycleItem(context, cycleStart, cycleEnd));
cycleEnd = cycleStart; cycleEnd = cycleStart;
hasCycles = true;
// TODO: remove this guard once we have better testing // TODO: remove this guard once we have better testing
if (guardCount++ > 50) { if (guardCount++ > 50) {
Log.wtf(TAG, "stuck generating ranges for bounds=" + Arrays.toString(bounds) Log.wtf(TAG, "stuck generating ranges for historyStart=" + historyStart
+ " and policy=" + policy); + ", historyEnd=" + historyEnd + " and policy=" + policy);
} }
} }
// one last cycle entry to modify policy cycle day // one last cycle entry to modify policy cycle day
mCycleAdapter.setChangePossible(true); mCycleAdapter.setChangePossible(true);
}
} else { if (!hasCycles) {
// no valid cycle; show all data // no valid cycles; show all data
// TODO: offer simple ranges like "last week" etc // TODO: offer simple ranges like "last week" etc
mCycleAdapter.add(new CycleItem(context, historyStart, historyEnd)); mCycleAdapter.add(new CycleItem(context, historyStart, historyEnd));
mCycleAdapter.setChangePossible(false); mCycleAdapter.setChangePossible(false);
} }
// force pick the current cycle (first item) // force pick the current cycle (first item)
@@ -889,8 +874,7 @@ public class DataUsageSummary extends Fragment {
// update chart to show selected cycle, and update detail data // update chart to show selected cycle, and update detail data
// to match updated sweep bounds. // to match updated sweep bounds.
final long[] bounds = getHistoryBounds(mHistory); mChart.setVisibleRange(cycle.start, cycle.end, mHistory.getEnd());
mChart.setVisibleRange(cycle.start, cycle.end, bounds[1]);
updateDetailData(); updateDetailData();
} }
@@ -911,23 +895,25 @@ public class DataUsageSummary extends Fragment {
private void updateDetailData() { private void updateDetailData() {
if (LOGD) Log.d(TAG, "updateDetailData()"); if (LOGD) Log.d(TAG, "updateDetailData()");
final long start = mChart.getInspectStart();
final long end = mChart.getInspectEnd();
if (isAppDetailMode()) { if (isAppDetailMode()) {
if (mDetailHistory != null) { if (mDetailHistory != null) {
final Context context = mChart.getContext(); final Context context = mChart.getContext();
final long[] range = mChart.getInspectRange(); final long now = System.currentTimeMillis();
final long[] total = mDetailHistory.getTotalData(range[0], range[1], null); final NetworkStatsHistory.Entry entry = mDetailHistory.getValues(
final long totalCombined = total[0] + total[1]; start, end, now, null);
mAppSubtitle.setText(Formatter.formatFileSize(context, totalCombined)); final long total = entry.rxBytes + entry.txBytes;
mAppSubtitle.setText(Formatter.formatFileSize(context, total));
} }
getLoaderManager().destroyLoader(LOADER_SUMMARY); getLoaderManager().destroyLoader(LOADER_SUMMARY);
} else { } else {
// kick off loader for detailed stats // kick off loader for detailed stats
final long[] range = mChart.getInspectRange();
getLoaderManager().restartLoader(LOADER_SUMMARY, getLoaderManager().restartLoader(LOADER_SUMMARY,
SummaryForAllUidLoader.buildArgs(mTemplate, range[0], range[1]), SummaryForAllUidLoader.buildArgs(mTemplate, start, end), mSummaryForAllUid);
mSummaryForAllUid);
} }
} }
@@ -1085,13 +1071,27 @@ public class DataUsageSummary extends Fragment {
mItems.clear(); mItems.clear();
if (stats != null) { if (stats != null) {
final AppUsageItem systemItem = new AppUsageItem();
systemItem.uid = android.os.Process.SYSTEM_UID;
NetworkStats.Entry entry = null; NetworkStats.Entry entry = null;
for (int i = 0; i < stats.size(); i++) { for (int i = 0; i < stats.size(); i++) {
entry = stats.getValues(i, entry); entry = stats.getValues(i, entry);
final boolean isApp = entry.uid >= android.os.Process.FIRST_APPLICATION_UID
&& entry.uid <= android.os.Process.LAST_APPLICATION_UID;
if (isApp || entry.uid == TrafficStats.UID_REMOVED) {
final AppUsageItem item = new AppUsageItem(); final AppUsageItem item = new AppUsageItem();
item.uid = entry.uid; item.uid = entry.uid;
item.total = entry.rxBytes + entry.txBytes; item.total = entry.rxBytes + entry.txBytes;
mItems.add(item); mItems.add(item);
} else {
systemItem.total += entry.rxBytes + entry.txBytes;
}
}
if (systemItem.total > 0) {
mItems.add(systemItem);
} }
} }
@@ -1122,13 +1122,12 @@ public class DataUsageSummary extends Fragment {
} }
final Context context = parent.getContext(); final Context context = parent.getContext();
final PackageManager pm = context.getPackageManager();
final TextView text1 = (TextView) convertView.findViewById(android.R.id.text1); final TextView text1 = (TextView) convertView.findViewById(android.R.id.text1);
final TextView text2 = (TextView) convertView.findViewById(android.R.id.text2); final TextView text2 = (TextView) convertView.findViewById(android.R.id.text2);
final AppUsageItem item = mItems.get(position); final AppUsageItem item = mItems.get(position);
text1.setText(resolveLabelForUid(pm, item.uid)); text1.setText(resolveLabelForUid(context, item.uid));
text2.setText(Formatter.formatFileSize(context, item.total)); text2.setText(Formatter.formatFileSize(context, item.total));
return convertView; return convertView;
@@ -1470,7 +1469,19 @@ public class DataUsageSummary extends Fragment {
/** /**
* Resolve best descriptive label for the given UID. * Resolve best descriptive label for the given UID.
*/ */
public static CharSequence resolveLabelForUid(PackageManager pm, int uid) { public static CharSequence resolveLabelForUid(Context context, int uid) {
final Resources res = context.getResources();
final PackageManager pm = context.getPackageManager();
// handle special case labels
switch (uid) {
case android.os.Process.SYSTEM_UID:
return res.getText(R.string.process_kernel_label);
case TrafficStats.UID_REMOVED:
return res.getText(R.string.data_usage_uninstalled_apps);
}
// otherwise fall back to using packagemanager labels
final String[] packageNames = pm.getPackagesForUid(uid); final String[] packageNames = pm.getPackagesForUid(uid);
final int length = packageNames != null ? packageNames.length : 0; final int length = packageNames != null ? packageNames.length : 0;

View File

@@ -206,14 +206,12 @@ public class DataUsageChartView extends ChartView {
} }
} }
/** public long getInspectStart() {
* Return current inspection range (start and end time) based on internal return mSweepLeft.getValue();
* {@link ChartSweepView} positions. }
*/
public long[] getInspectRange() { public long getInspectEnd() {
final long start = mSweepLeft.getValue(); return mSweepRight.getValue();
final long end = mSweepRight.getValue();
return new long[] { start, end };
} }
public long getWarningBytes() { public long getWarningBytes() {