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:
Jeff Sharkey
2011-08-04 21:17:23 -07:00
parent ce919e40c9
commit d39c6e4083
11 changed files with 183 additions and 57 deletions

View File

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

View 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" />

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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