Data usage app icons and details, chart labels.
Add app icons into both summary list and details pane. Also show list of all applications merged under a UID. Draw dates on chart axis, and avoid flashing policy sweeps when switching networks in detail mode. Bug: 5087283, 5038812 Change-Id: I1dcd03ca85b517f8726452af8a46b4be9b3d20f1
This commit is contained in:
@@ -1185,7 +1185,8 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity android:name="Settings$DataUsageSummaryActivity"
|
<activity android:name="Settings$DataUsageSummaryActivity"
|
||||||
android:label="@string/data_usage_summary_title">
|
android:label="@string/data_usage_summary_title"
|
||||||
|
android:uiOptions="none">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
22
res/layout/data_usage_app_title.xml
Normal file
22
res/layout/data_usage_app_title.xml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2011 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
@@ -30,7 +30,7 @@
|
|||||||
settings:primaryDrawable="@drawable/data_grid_primary"
|
settings:primaryDrawable="@drawable/data_grid_primary"
|
||||||
settings:secondaryDrawable="@drawable/data_grid_secondary"
|
settings:secondaryDrawable="@drawable/data_grid_secondary"
|
||||||
settings:borderDrawable="@drawable/data_grid_border"
|
settings:borderDrawable="@drawable/data_grid_border"
|
||||||
settings:labelColor="#24aae1" />
|
settings:labelColor="#667bb5" />
|
||||||
|
|
||||||
<com.android.settings.widget.ChartNetworkSeriesView
|
<com.android.settings.widget.ChartNetworkSeriesView
|
||||||
android:id="@+id/series"
|
android:id="@+id/series"
|
||||||
|
@@ -20,17 +20,20 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<ImageView
|
||||||
android:id="@+id/app_title"
|
android:id="@+id/app_icon"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="48dip"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="48dip"
|
||||||
android:layout_marginLeft="16dip" />
|
android:layout_marginLeft="16dip"
|
||||||
|
android:scaleType="centerInside" />
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/app_subtitle"
|
android:id="@+id/app_titles"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginLeft="16dip" />
|
android:layout_marginLeft="16dip"
|
||||||
|
android:layout_marginTop="8dip"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/app_settings"
|
android:id="@+id/app_settings"
|
||||||
|
@@ -43,6 +43,8 @@
|
|||||||
android:paddingRight="16dip"
|
android:paddingRight="16dip"
|
||||||
android:paddingTop="8dip"
|
android:paddingTop="8dip"
|
||||||
android:paddingBottom="8dip"
|
android:paddingBottom="8dip"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="marquee"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@@ -21,7 +21,15 @@
|
|||||||
android:paddingRight="16dip"
|
android:paddingRight="16dip"
|
||||||
android:paddingTop="8dip"
|
android:paddingTop="8dip"
|
||||||
android:paddingBottom="8dip"
|
android:paddingBottom="8dip"
|
||||||
android:columnCount="2">
|
android:columnCount="3">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@android:id/icon"
|
||||||
|
android:layout_width="48dip"
|
||||||
|
android:layout_height="48dip"
|
||||||
|
android:layout_rowSpan="2"
|
||||||
|
android:layout_marginRight="8dip"
|
||||||
|
android:scaleType="centerInside" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@android:id/title"
|
android:id="@android:id/title"
|
||||||
|
@@ -3465,7 +3465,7 @@ found in the list of installed applications.</string>
|
|||||||
<!-- Combination of total network bytes sent and received by an application. [CHAR LIMIT=NONE] -->
|
<!-- Combination of total network bytes sent and received by an application. [CHAR LIMIT=NONE] -->
|
||||||
<string name="data_usage_received_sent"><xliff:g id="received" example="128KB">%1$s</xliff:g> received, <xliff:g id="sent" example="1.3GB">%2$s</xliff:g> sent</string>
|
<string name="data_usage_received_sent"><xliff:g id="received" example="128KB">%1$s</xliff:g> received, <xliff:g id="sent" example="1.3GB">%2$s</xliff:g> sent</string>
|
||||||
<!-- Label displaying total network data transferred during a specific time period. [CHAR LIMIT=64] -->
|
<!-- Label displaying total network data transferred during a specific time period. [CHAR LIMIT=64] -->
|
||||||
<string name="data_usage_total_during_range">Data usage: <xliff:g id="total" example="128KB">%1$s</xliff:g> between <xliff:g id="range" example="Jul 1 - Jul 31">%2$s</xliff:g></string>
|
<string name="data_usage_total_during_range">Data usage: <xliff:g id="total" example="128KB">%1$s</xliff:g> on <xliff:g id="range" example="Jul 1 - Jul 31">%2$s</xliff:g></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>
|
||||||
|
@@ -37,6 +37,9 @@ import static android.net.NetworkTemplate.buildTemplateMobile3gLower;
|
|||||||
import static android.net.NetworkTemplate.buildTemplateMobile4g;
|
import static android.net.NetworkTemplate.buildTemplateMobile4g;
|
||||||
import static android.net.NetworkTemplate.buildTemplateMobileAll;
|
import static android.net.NetworkTemplate.buildTemplateMobileAll;
|
||||||
import static android.net.NetworkTemplate.buildTemplateWifi;
|
import static android.net.NetworkTemplate.buildTemplateWifi;
|
||||||
|
import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
|
||||||
|
import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
|
||||||
|
import static android.text.format.Time.TIMEZONE_UTC;
|
||||||
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
|
|
||||||
import android.animation.LayoutTransition;
|
import android.animation.LayoutTransition;
|
||||||
@@ -57,6 +60,7 @@ 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.content.res.Resources;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.INetworkPolicyManager;
|
import android.net.INetworkPolicyManager;
|
||||||
import android.net.INetworkStatsService;
|
import android.net.INetworkStatsService;
|
||||||
@@ -78,7 +82,6 @@ import android.telephony.TelephonyManager;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.text.format.Formatter;
|
import android.text.format.Formatter;
|
||||||
import android.text.format.Time;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -97,6 +100,7 @@ import android.widget.Button;
|
|||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.CompoundButton;
|
import android.widget.CompoundButton;
|
||||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.NumberPicker;
|
import android.widget.NumberPicker;
|
||||||
@@ -190,8 +194,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
private TextView mEmpty;
|
private TextView mEmpty;
|
||||||
|
|
||||||
private View mAppDetail;
|
private View mAppDetail;
|
||||||
private TextView mAppTitle;
|
private ImageView mAppIcon;
|
||||||
private TextView mAppSubtitle;
|
private ViewGroup mAppTitles;
|
||||||
private Button mAppSettings;
|
private Button mAppSettings;
|
||||||
|
|
||||||
private LinearLayout mAppSwitches;
|
private LinearLayout mAppSwitches;
|
||||||
@@ -295,8 +299,8 @@ public class DataUsageSummary extends Fragment {
|
|||||||
{
|
{
|
||||||
// bind app detail controls
|
// bind app detail controls
|
||||||
mAppDetail = mHeader.findViewById(R.id.app_detail);
|
mAppDetail = mHeader.findViewById(R.id.app_detail);
|
||||||
mAppTitle = (TextView) mAppDetail.findViewById(R.id.app_title);
|
mAppIcon = (ImageView) mAppDetail.findViewById(R.id.app_icon);
|
||||||
mAppSubtitle = (TextView) mAppDetail.findViewById(R.id.app_subtitle);
|
mAppTitles = (ViewGroup) mAppDetail.findViewById(R.id.app_titles);
|
||||||
mAppSwitches = (LinearLayout) mAppDetail.findViewById(R.id.app_switches);
|
mAppSwitches = (LinearLayout) mAppDetail.findViewById(R.id.app_switches);
|
||||||
|
|
||||||
mAppSettings = (Button) mAppDetail.findViewById(R.id.app_settings);
|
mAppSettings = (Button) mAppDetail.findViewById(R.id.app_settings);
|
||||||
@@ -643,6 +647,10 @@ public class DataUsageSummary extends Fragment {
|
|||||||
* depending on {@link #isAppDetailMode()}.
|
* depending on {@link #isAppDetailMode()}.
|
||||||
*/
|
*/
|
||||||
private void updateAppDetail() {
|
private void updateAppDetail() {
|
||||||
|
final Context context = getActivity();
|
||||||
|
final PackageManager pm = context.getPackageManager();
|
||||||
|
final LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||||
|
|
||||||
if (isAppDetailMode()) {
|
if (isAppDetailMode()) {
|
||||||
mAppDetail.setVisibility(View.VISIBLE);
|
mAppDetail.setVisibility(View.VISIBLE);
|
||||||
mCycleAdapter.setChangeVisible(false);
|
mCycleAdapter.setChangeVisible(false);
|
||||||
@@ -658,8 +666,18 @@ public class DataUsageSummary extends Fragment {
|
|||||||
// remove warning/limit sweeps while in detail mode
|
// remove warning/limit sweeps while in detail mode
|
||||||
mChart.bindNetworkPolicy(null);
|
mChart.bindNetworkPolicy(null);
|
||||||
|
|
||||||
final PackageManager pm = getActivity().getPackageManager();
|
// show icon and all labels appearing under this app
|
||||||
mAppTitle.setText(pm.getNameForUid(mUid));
|
final UidDetail detail = resolveDetailForUid(context, mUid);
|
||||||
|
mAppIcon.setImageDrawable(detail.icon);
|
||||||
|
|
||||||
|
mAppTitles.removeAllViews();
|
||||||
|
if (detail.detailLabels != null) {
|
||||||
|
for (CharSequence label : detail.detailLabels) {
|
||||||
|
mAppTitles.addView(inflateAppTitle(inflater, mAppTitles, label));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mAppTitles.addView(inflateAppTitle(inflater, mAppTitles, detail.label));
|
||||||
|
}
|
||||||
|
|
||||||
// enable settings button when package provides it
|
// enable settings button when package provides it
|
||||||
// TODO: target torwards entire UID instead of just first package
|
// TODO: target torwards entire UID instead of just first package
|
||||||
@@ -693,7 +711,6 @@ public class DataUsageSummary extends Fragment {
|
|||||||
|
|
||||||
updateDetailData();
|
updateDetailData();
|
||||||
|
|
||||||
final Context context = getActivity();
|
|
||||||
if (NetworkPolicyManager.isUidValidForPolicy(context, mUid) && !getRestrictBackground()
|
if (NetworkPolicyManager.isUidValidForPolicy(context, mUid) && !getRestrictBackground()
|
||||||
&& isBandwidthControlEnabled()) {
|
&& isBandwidthControlEnabled()) {
|
||||||
mAppRestrictView.setVisibility(View.VISIBLE);
|
mAppRestrictView.setVisibility(View.VISIBLE);
|
||||||
@@ -814,7 +831,9 @@ public class DataUsageSummary extends Fragment {
|
|||||||
if (isNetworkPolicyModifiable()) {
|
if (isNetworkPolicyModifiable()) {
|
||||||
mDisableAtLimitView.setVisibility(View.VISIBLE);
|
mDisableAtLimitView.setVisibility(View.VISIBLE);
|
||||||
mDisableAtLimit.setChecked(policy != null && policy.limitBytes != LIMIT_DISABLED);
|
mDisableAtLimit.setChecked(policy != null && policy.limitBytes != LIMIT_DISABLED);
|
||||||
|
if (!isAppDetailMode()) {
|
||||||
mChart.bindNetworkPolicy(policy);
|
mChart.bindNetworkPolicy(policy);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// controls are disabled; don't bind warning/limit sweeps
|
// controls are disabled; don't bind warning/limit sweeps
|
||||||
@@ -998,11 +1017,6 @@ public class DataUsageSummary extends Fragment {
|
|||||||
if (isAppDetailMode()) {
|
if (isAppDetailMode()) {
|
||||||
if (mDetailHistory != null) {
|
if (mDetailHistory != null) {
|
||||||
entry = mDetailHistory.getValues(start, end, now, null);
|
entry = mDetailHistory.getValues(start, end, now, null);
|
||||||
|
|
||||||
mAppSubtitle.setText(
|
|
||||||
getString(R.string.data_usage_received_sent,
|
|
||||||
Formatter.formatFileSize(context, entry.rxBytes),
|
|
||||||
Formatter.formatFileSize(context, entry.txBytes)));
|
|
||||||
} else {
|
} else {
|
||||||
entry = null;
|
entry = null;
|
||||||
}
|
}
|
||||||
@@ -1015,12 +1029,11 @@ public class DataUsageSummary extends Fragment {
|
|||||||
// kick off loader for detailed stats
|
// kick off loader for detailed stats
|
||||||
getLoaderManager().restartLoader(LOADER_SUMMARY,
|
getLoaderManager().restartLoader(LOADER_SUMMARY,
|
||||||
SummaryForAllUidLoader.buildArgs(mTemplate, start, end), mSummaryForAllUid);
|
SummaryForAllUidLoader.buildArgs(mTemplate, start, end), mSummaryForAllUid);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final long totalBytes = entry != null ? entry.rxBytes + entry.txBytes : 0;
|
final long totalBytes = entry != null ? entry.rxBytes + entry.txBytes : 0;
|
||||||
final String totalPhrase = Formatter.formatFileSize(context, totalBytes);
|
final String totalPhrase = Formatter.formatFileSize(context, totalBytes);
|
||||||
final String rangePhrase = formatDateRange(context, start, end, null);
|
final String rangePhrase = formatDateRange(context, start, end, false);
|
||||||
|
|
||||||
mUsageSummary.setText(
|
mUsageSummary.setText(
|
||||||
getString(R.string.data_usage_total_during_range, totalPhrase, rangePhrase));
|
getString(R.string.data_usage_total_during_range, totalPhrase, rangePhrase));
|
||||||
@@ -1104,7 +1117,7 @@ public class DataUsageSummary extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public CycleItem(Context context, long start, long end) {
|
public CycleItem(Context context, long start, long end) {
|
||||||
this.label = formatDateRange(context, start, end, Time.TIMEZONE_UTC);
|
this.label = formatDateRange(context, start, end, true);
|
||||||
this.start = start;
|
this.start = start;
|
||||||
this.end = end;
|
this.end = end;
|
||||||
}
|
}
|
||||||
@@ -1119,14 +1132,11 @@ public class DataUsageSummary extends Fragment {
|
|||||||
private static final java.util.Formatter sFormatter = new java.util.Formatter(
|
private static final java.util.Formatter sFormatter = new java.util.Formatter(
|
||||||
sBuilder, Locale.getDefault());
|
sBuilder, Locale.getDefault());
|
||||||
|
|
||||||
private static String formatDateRange(Context context, long start, long end, String timezone) {
|
public static String formatDateRange(Context context, long start, long end, boolean utcTime) {
|
||||||
synchronized (sBuilder) {
|
final int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH;
|
||||||
int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH;
|
final String timezone = utcTime ? TIMEZONE_UTC : null;
|
||||||
if (Time.getJulianDay(start, 0) == Time.getJulianDay(end, 0)) {
|
|
||||||
// when times are on same day, include time detail
|
|
||||||
flags |= DateUtils.FORMAT_SHOW_TIME;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
synchronized (sBuilder) {
|
||||||
sBuilder.setLength(0);
|
sBuilder.setLength(0);
|
||||||
return DateUtils
|
return DateUtils
|
||||||
.formatDateRange(context, sFormatter, start, end, flags, timezone).toString();
|
.formatDateRange(context, sFormatter, start, end, flags, timezone).toString();
|
||||||
@@ -1250,13 +1260,17 @@ public class DataUsageSummary extends Fragment {
|
|||||||
|
|
||||||
final Context context = parent.getContext();
|
final Context context = parent.getContext();
|
||||||
|
|
||||||
|
final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
|
||||||
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
|
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
|
||||||
final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
|
final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
|
||||||
final ProgressBar progress = (ProgressBar) convertView.findViewById(
|
final ProgressBar progress = (ProgressBar) convertView.findViewById(
|
||||||
android.R.id.progress);
|
android.R.id.progress);
|
||||||
|
|
||||||
final AppUsageItem item = mItems.get(position);
|
final AppUsageItem item = mItems.get(position);
|
||||||
title.setText(resolveLabelForUid(context, item.uid));
|
final UidDetail detail = resolveDetailForUid(context, item.uid);
|
||||||
|
|
||||||
|
icon.setImageDrawable(detail.icon);
|
||||||
|
title.setText(detail.label);
|
||||||
summary.setText(Formatter.formatFileSize(context, item.total));
|
summary.setText(Formatter.formatFileSize(context, item.total));
|
||||||
|
|
||||||
final int percentTotal = mLargest != 0 ? (int) (item.total * 100 / mLargest) : 0;
|
final int percentTotal = mLargest != 0 ? (int) (item.total * 100 / mLargest) : 0;
|
||||||
@@ -1536,48 +1550,66 @@ public class DataUsageSummary extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class UidDetail {
|
||||||
|
public CharSequence label;
|
||||||
|
public CharSequence[] detailLabels;
|
||||||
|
public Drawable icon;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve best descriptive label for the given UID.
|
* Resolve best descriptive label for the given UID.
|
||||||
*/
|
*/
|
||||||
public static CharSequence resolveLabelForUid(Context context, int uid) {
|
public static UidDetail resolveDetailForUid(Context context, int uid) {
|
||||||
final Resources res = context.getResources();
|
final Resources res = context.getResources();
|
||||||
final PackageManager pm = context.getPackageManager();
|
final PackageManager pm = context.getPackageManager();
|
||||||
|
|
||||||
|
final UidDetail detail = new UidDetail();
|
||||||
|
detail.label = pm.getNameForUid(uid);
|
||||||
|
detail.icon = pm.getDefaultActivityIcon();
|
||||||
|
|
||||||
// handle special case labels
|
// handle special case labels
|
||||||
switch (uid) {
|
switch (uid) {
|
||||||
case android.os.Process.SYSTEM_UID:
|
case android.os.Process.SYSTEM_UID:
|
||||||
return res.getText(R.string.process_kernel_label);
|
detail.label = res.getString(R.string.process_kernel_label);
|
||||||
|
detail.icon = pm.getDefaultActivityIcon();
|
||||||
|
return detail;
|
||||||
case TrafficStats.UID_REMOVED:
|
case TrafficStats.UID_REMOVED:
|
||||||
return res.getText(R.string.data_usage_uninstalled_apps);
|
detail.label = res.getString(R.string.data_usage_uninstalled_apps);
|
||||||
|
detail.icon = pm.getDefaultActivityIcon();
|
||||||
|
return detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise fall back to using packagemanager labels
|
// 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;
|
||||||
|
|
||||||
CharSequence label = pm.getNameForUid(uid);
|
|
||||||
try {
|
try {
|
||||||
if (length == 1) {
|
if (length == 1) {
|
||||||
final ApplicationInfo info = pm.getApplicationInfo(packageNames[0], 0);
|
final ApplicationInfo info = pm.getApplicationInfo(packageNames[0], 0);
|
||||||
label = info.loadLabel(pm);
|
detail.label = info.loadLabel(pm).toString();
|
||||||
|
detail.icon = info.loadIcon(pm);
|
||||||
} else if (length > 1) {
|
} else if (length > 1) {
|
||||||
for (String packageName : packageNames) {
|
detail.detailLabels = new CharSequence[length];
|
||||||
final PackageInfo info = pm.getPackageInfo(packageName, 0);
|
for (int i = 0; i < length; i++) {
|
||||||
if (info.sharedUserLabel != 0) {
|
final String packageName = packageNames[i];
|
||||||
label = pm.getText(packageName, info.sharedUserLabel, info.applicationInfo);
|
final PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);
|
||||||
if (!TextUtils.isEmpty(label)) {
|
final ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0);
|
||||||
break;
|
|
||||||
}
|
detail.detailLabels[i] = appInfo.loadLabel(pm).toString();
|
||||||
|
if (packageInfo.sharedUserLabel != 0) {
|
||||||
|
detail.label = pm.getText(packageName, packageInfo.sharedUserLabel,
|
||||||
|
packageInfo.applicationInfo).toString();
|
||||||
|
detail.icon = appInfo.loadIcon(pm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (NameNotFoundException e) {
|
} catch (NameNotFoundException e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TextUtils.isEmpty(label)) {
|
if (TextUtils.isEmpty(detail.label)) {
|
||||||
label = Integer.toString(uid);
|
detail.label = Integer.toString(uid);
|
||||||
}
|
}
|
||||||
return label;
|
return detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1652,6 +1684,14 @@ public class DataUsageSummary extends Fragment {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static View inflateAppTitle(
|
||||||
|
LayoutInflater inflater, ViewGroup root, CharSequence label) {
|
||||||
|
final TextView view = (TextView) inflater.inflate(
|
||||||
|
R.layout.data_usage_app_title, root, false);
|
||||||
|
view.setText(label);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set {@link android.R.id#title} for a preference view inflated with
|
* Set {@link android.R.id#title} for a preference view inflated with
|
||||||
* {@link #inflatePreference(LayoutInflater, ViewGroup, View)}.
|
* {@link #inflatePreference(LayoutInflater, ViewGroup, View)}.
|
||||||
|
@@ -17,12 +17,20 @@
|
|||||||
package com.android.settings.widget;
|
package com.android.settings.widget;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.text.Layout;
|
||||||
|
import android.text.StaticLayout;
|
||||||
|
import android.text.TextPaint;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.util.TypedValue;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.android.settings.DataUsageSummary;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
@@ -32,14 +40,16 @@ import com.google.common.base.Preconditions;
|
|||||||
*/
|
*/
|
||||||
public class ChartGridView extends View {
|
public class ChartGridView extends View {
|
||||||
|
|
||||||
// TODO: eventually teach about drawing chart labels
|
|
||||||
|
|
||||||
private ChartAxis mHoriz;
|
private ChartAxis mHoriz;
|
||||||
private ChartAxis mVert;
|
private ChartAxis mVert;
|
||||||
|
|
||||||
private Drawable mPrimary;
|
private Drawable mPrimary;
|
||||||
private Drawable mSecondary;
|
private Drawable mSecondary;
|
||||||
private Drawable mBorder;
|
private Drawable mBorder;
|
||||||
|
private int mLabelColor;
|
||||||
|
|
||||||
|
private Layout mLayoutStart;
|
||||||
|
private Layout mLayoutEnd;
|
||||||
|
|
||||||
public ChartGridView(Context context) {
|
public ChartGridView(Context context) {
|
||||||
this(context, null, 0);
|
this(context, null, 0);
|
||||||
@@ -60,7 +70,7 @@ public class ChartGridView extends View {
|
|||||||
mPrimary = a.getDrawable(R.styleable.ChartGridView_primaryDrawable);
|
mPrimary = a.getDrawable(R.styleable.ChartGridView_primaryDrawable);
|
||||||
mSecondary = a.getDrawable(R.styleable.ChartGridView_secondaryDrawable);
|
mSecondary = a.getDrawable(R.styleable.ChartGridView_secondaryDrawable);
|
||||||
mBorder = a.getDrawable(R.styleable.ChartGridView_borderDrawable);
|
mBorder = a.getDrawable(R.styleable.ChartGridView_borderDrawable);
|
||||||
// TODO: eventually read labelColor
|
mLabelColor = a.getColor(R.styleable.ChartGridView_labelColor, Color.RED);
|
||||||
|
|
||||||
a.recycle();
|
a.recycle();
|
||||||
}
|
}
|
||||||
@@ -70,6 +80,13 @@ public class ChartGridView extends View {
|
|||||||
mVert = Preconditions.checkNotNull(vert, "missing vert");
|
mVert = Preconditions.checkNotNull(vert, "missing vert");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setBounds(long start, long end) {
|
||||||
|
final Context context = getContext();
|
||||||
|
mLayoutStart = makeLayout(DataUsageSummary.formatDateRange(context, start, start, true));
|
||||||
|
mLayoutEnd = makeLayout(DataUsageSummary.formatDateRange(context, end, end, true));
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDraw(Canvas canvas) {
|
protected void onDraw(Canvas canvas) {
|
||||||
final int width = getWidth();
|
final int width = getWidth();
|
||||||
@@ -98,5 +115,38 @@ public class ChartGridView extends View {
|
|||||||
|
|
||||||
mBorder.setBounds(0, 0, width, height);
|
mBorder.setBounds(0, 0, width, height);
|
||||||
mBorder.draw(canvas);
|
mBorder.draw(canvas);
|
||||||
|
|
||||||
|
final int padding = mLayoutStart.getHeight() / 8;
|
||||||
|
|
||||||
|
final Layout start = mLayoutStart;
|
||||||
|
if (start != null) {
|
||||||
|
canvas.save();
|
||||||
|
canvas.translate(0, height + padding);
|
||||||
|
start.draw(canvas);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
final Layout end = mLayoutEnd;
|
||||||
|
if (end != null) {
|
||||||
|
canvas.save();
|
||||||
|
canvas.translate(width - end.getWidth(), height + padding);
|
||||||
|
end.draw(canvas);
|
||||||
|
canvas.restore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Layout makeLayout(CharSequence text) {
|
||||||
|
final Resources res = getResources();
|
||||||
|
final TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
paint.density = res.getDisplayMetrics().density;
|
||||||
|
paint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale);
|
||||||
|
paint.setColor(mLabelColor);
|
||||||
|
paint.setTextSize(
|
||||||
|
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10, res.getDisplayMetrics()));
|
||||||
|
|
||||||
|
return new StaticLayout(text, paint,
|
||||||
|
(int) Math.ceil(Layout.getDesiredWidth(text, paint)),
|
||||||
|
Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@@ -29,7 +29,6 @@ import android.text.Layout.Alignment;
|
|||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.TextPaint;
|
import android.text.TextPaint;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
|
||||||
import android.util.MathUtils;
|
import android.util.MathUtils;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@@ -343,6 +343,7 @@ public class DataUsageChartView extends ChartView {
|
|||||||
*/
|
*/
|
||||||
public void setVisibleRange(long visibleStart, long visibleEnd) {
|
public void setVisibleRange(long visibleStart, long visibleEnd) {
|
||||||
mHoriz.setBounds(visibleStart, visibleEnd);
|
mHoriz.setBounds(visibleStart, visibleEnd);
|
||||||
|
mGrid.setBounds(visibleStart, visibleEnd);
|
||||||
|
|
||||||
final long validStart = Math.max(visibleStart, getStatsStart());
|
final long validStart = Math.max(visibleStart, getStatsStart());
|
||||||
final long validEnd = Math.min(visibleEnd, getStatsEnd());
|
final long validEnd = Math.min(visibleEnd, getStatsEnd());
|
||||||
|
Reference in New Issue
Block a user