summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/layout/data_usage_chart.xml11
-rw-r--r--res/layout/data_usage_cycles.xml4
-rw-r--r--res/layout/data_usage_detail.xml74
-rw-r--r--res/layout/data_usage_header.xml8
-rw-r--r--res/layout/data_usage_item.xml4
-rw-r--r--res/layout/data_usage_summary.xml17
-rw-r--r--res/layout/manage_apps_tab_content.xml8
-rw-r--r--res/layout/preference.xml9
-rw-r--r--res/layout/tab_indicator_thin_holo.xml33
-rw-r--r--res/menu/data_usage.xml45
-rw-r--r--res/values/attrs.xml7
-rwxr-xr-xres/values/dimens.xml4
-rw-r--r--res/values/strings.xml8
-rw-r--r--src/com/android/settings/DataUsageSummary.java109
-rw-r--r--src/com/android/settings/Settings.java12
-rw-r--r--src/com/android/settings/widget/ChartNetworkSeriesView.java9
-rw-r--r--src/com/android/settings/widget/ChartSweepView.java7
-rw-r--r--src/com/android/settings/widget/ChartView.java32
-rw-r--r--src/com/android/settings/widget/DataUsageChartView.java3
-rw-r--r--src/com/android/settings/widget/PieChartView.java202
20 files changed, 455 insertions, 151 deletions
diff --git a/res/layout/data_usage_chart.xml b/res/layout/data_usage_chart.xml
index c1f6c27..4dae248 100644
--- a/res/layout/data_usage_chart.xml
+++ b/res/layout/data_usage_chart.xml
@@ -19,8 +19,13 @@
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
android:id="@+id/chart"
android:layout_width="match_parent"
- android:layout_height="220dip"
- android:padding="16dip">
+ android:layout_height="@dimen/data_usage_chart_height"
+ android:paddingLeft="@*android:dimen/preference_item_padding_side"
+ android:paddingRight="@*android:dimen/preference_item_padding_side"
+ android:paddingTop="16dip"
+ android:paddingBottom="16dip"
+ settings:optimalWidth="@dimen/data_usage_chart_optimalWidth"
+ settings:optimalWidthWeight="0.4">
<com.android.settings.widget.ChartGridView
android:id="@+id/grid"
@@ -48,7 +53,7 @@
android:layout_gravity="left|bottom"
settings:strokeColor="#d88d3a"
settings:fillColor="#c0ba7f3e"
- settings:fillColorSecondary="#0000" />
+ settings:fillColorSecondary="#60ba7f3e" />
<com.android.settings.widget.ChartSweepView
android:id="@+id/sweep_warning"
diff --git a/res/layout/data_usage_cycles.xml b/res/layout/data_usage_cycles.xml
index 225fb4b..459ef6e 100644
--- a/res/layout/data_usage_cycles.xml
+++ b/res/layout/data_usage_cycles.xml
@@ -19,8 +19,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:paddingLeft="16dip"
- android:paddingRight="16dip">
+ android:paddingLeft="@*android:dimen/preference_item_padding_side"
+ android:paddingRight="@*android:dimen/preference_item_padding_side">
<TextView
android:layout_width="wrap_content"
diff --git a/res/layout/data_usage_detail.xml b/res/layout/data_usage_detail.xml
index 8d0c0cc..639fcf5 100644
--- a/res/layout/data_usage_detail.xml
+++ b/res/layout/data_usage_detail.xml
@@ -17,29 +17,75 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/app_detail"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:orientation="vertical">
- <ImageView
- android:id="@+id/app_icon"
- android:layout_width="48dip"
- android:layout_height="48dip"
- android:layout_marginLeft="16dip"
- android:scaleType="centerInside" />
-
<LinearLayout
- android:id="@+id/app_titles"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginLeft="16dip"
- android:layout_marginTop="8dip"
- android:orientation="vertical" />
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@*android:dimen/preference_item_padding_side"
+ android:layout_marginRight="@*android:dimen/preference_item_padding_side"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginRight="@*android:dimen/preference_item_padding_inner"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/app_icon"
+ android:layout_width="48dip"
+ android:layout_height="48dip"
+ android:scaleType="centerInside" />
+
+ <LinearLayout
+ android:id="@+id/app_titles"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:orientation="vertical" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:textColor="#d88d3a"
+ android:text="@string/data_usage_label_foreground" />
+ <TextView
+ android:id="@+id/app_foreground"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="#d88d3a" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:text="@string/data_usage_label_background" />
+ <TextView
+ android:id="@+id/app_background"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+ <com.android.settings.widget.PieChartView
+ android:id="@+id/app_pie_chart"
+ android:layout_width="160dip"
+ android:layout_height="160dip" />
+
+ </LinearLayout>
<Button
android:id="@+id/app_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="16dip"
+ android:layout_marginLeft="@*android:dimen/preference_item_padding_side"
+ android:layout_marginRight="@*android:dimen/preference_item_padding_side"
+ android:layout_marginTop="16dip"
+ android:layout_marginBottom="16dip"
android:text="@string/data_usage_app_settings" />
<LinearLayout
diff --git a/res/layout/data_usage_header.xml b/res/layout/data_usage_header.xml
index 528fc34..ba41c88 100644
--- a/res/layout/data_usage_header.xml
+++ b/res/layout/data_usage_header.xml
@@ -39,8 +39,8 @@
android:id="@+id/usage_summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingLeft="16dip"
- android:paddingRight="16dip"
+ android:paddingLeft="@*android:dimen/preference_item_padding_side"
+ android:paddingRight="@*android:dimen/preference_item_padding_side"
android:paddingTop="8dip"
android:paddingBottom="8dip"
android:singleLine="true"
@@ -52,8 +52,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
- android:paddingLeft="16dip"
- android:paddingRight="16dip"
+ android:paddingLeft="@*android:dimen/preference_item_padding_side"
+ android:paddingRight="@*android:dimen/preference_item_padding_side"
android:paddingTop="8dip"
android:paddingBottom="8dip"
android:text="@string/data_usage_empty"
diff --git a/res/layout/data_usage_item.xml b/res/layout/data_usage_item.xml
index b41d486..d5c2e7f 100644
--- a/res/layout/data_usage_item.xml
+++ b/res/layout/data_usage_item.xml
@@ -17,8 +17,8 @@
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingLeft="16dip"
- android:paddingRight="16dip"
+ android:paddingLeft="@*android:dimen/preference_item_padding_side"
+ android:paddingRight="@*android:dimen/preference_item_padding_side"
android:paddingTop="8dip"
android:paddingBottom="8dip"
android:columnCount="3">
diff --git a/res/layout/data_usage_summary.xml b/res/layout/data_usage_summary.xml
index 7e68143..d59e0d6 100644
--- a/res/layout/data_usage_summary.xml
+++ b/res/layout/data_usage_summary.xml
@@ -25,11 +25,20 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <TabWidget
- android:id="@android:id/tabs"
- android:orientation="horizontal"
+ <HorizontalScrollView
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:scrollbars="none">
+
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ style="?android:attr/tabWidgetStyle" />
+
+ </HorizontalScrollView>
<!-- give an empty content area to make tabhost happy -->
<FrameLayout
diff --git a/res/layout/manage_apps_tab_content.xml b/res/layout/manage_apps_tab_content.xml
index 0391a9d..b8cee87 100644
--- a/res/layout/manage_apps_tab_content.xml
+++ b/res/layout/manage_apps_tab_content.xml
@@ -37,10 +37,10 @@
<TabWidget
android:id="@android:id/tabs"
- android:orientation="horizontal"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- />
+ android:orientation="horizontal"
+ style="?android:attr/tabWidgetStyle" />
</HorizontalScrollView>
@@ -48,7 +48,7 @@
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="0dip"
- android:layout_weight="1"/>
+ android:layout_weight="1" />
</LinearLayout>
</TabHost>
diff --git a/res/layout/preference.xml b/res/layout/preference.xml
index 06d8f24..aef21a1 100644
--- a/res/layout/preference.xml
+++ b/res/layout/preference.xml
@@ -19,17 +19,16 @@
android:layout_height="wrap_content"
android:minHeight="48dip"
android:gravity="center_vertical"
+ android:paddingLeft="@*android:dimen/preference_item_padding_side"
android:paddingRight="?android:attr/scrollbarSize"
android:background="?android:attr/selectableItemBackground">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="15dip"
- android:layout_marginRight="6dip"
- android:layout_marginTop="6dip"
- android:layout_marginBottom="6dip"
- android:layout_weight="1">
+ android:layout_weight="1"
+ android:paddingTop="6dip"
+ android:paddingBottom="6dip">
<TextView
android:id="@+android:id/title"
diff --git a/res/layout/tab_indicator_thin_holo.xml b/res/layout/tab_indicator_thin_holo.xml
deleted file mode 100644
index e4c4652..0000000
--- a/res/layout/tab_indicator_thin_holo.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?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.
--->
-
-<RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="0dp"
- android:layout_height="48dp"
- android:layout_weight="1"
- android:background="@*android:drawable/tab_indicator_holo">
-
- <TextView
- android:id="@android:id/title"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
-</RelativeLayout>
diff --git a/res/menu/data_usage.xml b/res/menu/data_usage.xml
index 24b0de4..4e938aa 100644
--- a/res/menu/data_usage.xml
+++ b/res/menu/data_usage.xml
@@ -16,30 +16,23 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
- android:id="@+id/action_settings"
- android:icon="@drawable/ic_sysbar_quicksettings"
- android:showAsAction="always">
- <menu>
- <item
- android:id="@+id/data_usage_menu_roaming"
- android:title="@string/data_usage_menu_roaming"
- android:checkable="true" />
- <item
- android:id="@+id/data_usage_menu_restrict_background"
- android:title="@string/data_usage_menu_restrict_background"
- android:checkable="true" />
- <item
- android:id="@+id/data_usage_menu_split_4g"
- android:title="@string/data_usage_menu_split_4g"
- android:checkable="true" />
- <item
- android:id="@+id/data_usage_menu_show_wifi"
- android:title="@string/data_usage_menu_show_wifi"
- android:checkable="true" />
- <item
- android:id="@+id/data_usage_menu_show_ethernet"
- android:title="@string/data_usage_menu_show_ethernet"
- android:checkable="true" />
- </menu>
- </item>
+ android:id="@+id/data_usage_menu_roaming"
+ android:title="@string/data_usage_menu_roaming"
+ android:checkable="true" />
+ <item
+ android:id="@+id/data_usage_menu_restrict_background"
+ android:title="@string/data_usage_menu_restrict_background"
+ android:checkable="true" />
+ <item
+ android:id="@+id/data_usage_menu_split_4g"
+ android:title="@string/data_usage_menu_split_4g"
+ android:checkable="true" />
+ <item
+ android:id="@+id/data_usage_menu_show_wifi"
+ android:title="@string/data_usage_menu_show_wifi"
+ android:checkable="true" />
+ <item
+ android:id="@+id/data_usage_menu_show_ethernet"
+ android:title="@string/data_usage_menu_show_ethernet"
+ android:checkable="true" />
</menu>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 6c63d13..684811c 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -50,6 +50,13 @@
<attr name="minTickWidth" format="dimension" />
</declare-styleable>
+ <declare-styleable name="ChartView">
+ <!-- optimal width of the chart -->
+ <attr name="optimalWidth" format="dimension" />
+ <!-- how to weight extra space beyond optimal width -->
+ <attr name="optimalWidthWeight" format="float" />
+ </declare-styleable>
+
<declare-styleable name="ChartSweepView">
<attr name="sweepDrawable" format="reference" />
<attr name="followAxis">
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 5394743..4b576eb 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -17,7 +17,6 @@
<resources>
<dimen name="device_memory_usage_button_width">16dip</dimen>
<dimen name="device_memory_usage_button_height">32dip</dimen>
- <dimen name="data_usage_chart_height">220dip</dimen>
<dimen name="action_bar_switch_padding">16dip</dimen>
<dimen name="app_icon_size">56dip</dimen>
@@ -28,4 +27,7 @@
<dimen name="content_margin_left">16dip</dimen>
<dimen name="description_margin_top">26dip</dimen>
<dimen name="description_margin_sides">40dip</dimen>
+
+ <dimen name="data_usage_chart_height">220dip</dimen>
+ <dimen name="data_usage_chart_optimalWidth">440dip</dimen>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a91e6df..658e6fd 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3392,7 +3392,7 @@ found in the list of installed applications.</string>
<!-- Title for checkbox menu option to restrict background data usage. [CHAR LIMIT=32] -->
<string name="data_usage_menu_restrict_background">Restrict background data</string>
<!-- Title for checkbox menu option to show 4G mobile data usage separate from other mobile data usage. [CHAR LIMIT=32] -->
- <string name="data_usage_menu_split_4g">Split 4G usage</string>
+ <string name="data_usage_menu_split_4g">Separate 4G usage</string>
<!-- Title for checkbox menu option to show Wi-Fi data usage. [CHAR LIMIT=32] -->
<string name="data_usage_menu_show_wifi">Show Wi-Fi usage</string>
<!-- Title for checkbox menu option to show Ethernet data usage. [CHAR LIMIT=32] -->
@@ -3403,6 +3403,10 @@ found in the list of installed applications.</string>
<string name="data_usage_pick_cycle_day">Day of month to reset data usage cycle:</string>
<!-- Label shown when no applications used data during selected time period. [CHAR LIMIT=48] -->
<string name="data_usage_empty">No applications used data during this period.</string>
+ <!-- Label for data usage occuring while application in foreground. [CHAR LIMIT=48] -->
+ <string name="data_usage_label_foreground">Foreground</string>
+ <!-- Label for data usage occuring while application in background. [CHAR LIMIT=48] -->
+ <string name="data_usage_label_background">Background</string>
<!-- Checkbox label that will disable mobile network data connection when user-defined limit is reached. [CHAR LIMIT=32] -->
<string name="data_usage_disable_mobile_limit">Disable mobile data at limit</string>
@@ -3471,7 +3475,7 @@ found in the list of installed applications.</string>
<!-- 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>
<!-- 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> on <xliff:g id="range" example="Jul 1 - Jul 31">%2$s</xliff:g></string>
+ <string name="data_usage_total_during_range"><xliff:g id="range" example="Jul 1 - Jul 31">%2$s</xliff:g>: <xliff:g id="total" example="128KB">%1$s</xliff:g> used</string>
<!-- Button at the bottom of the CryptKeeper screen to make an emergency call. -->
<string name="cryptkeeper_emergency_call">Emergency call</string>
diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java
index bccc5a5..a95ab3f 100644
--- a/src/com/android/settings/DataUsageSummary.java
+++ b/src/com/android/settings/DataUsageSummary.java
@@ -25,6 +25,8 @@ import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.SET_FOREGROUND;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
@@ -60,6 +62,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
+import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.INetworkPolicyManager;
@@ -83,6 +86,7 @@ import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Formatter;
import android.util.Log;
+import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -119,6 +123,7 @@ import com.android.settings.net.NetworkPolicyEditor;
import com.android.settings.net.SummaryForAllUidLoader;
import com.android.settings.widget.DataUsageChartView;
import com.android.settings.widget.DataUsageChartView.DataUsageChartListener;
+import com.android.settings.widget.PieChartView;
import com.google.android.collect.Lists;
import java.util.ArrayList;
@@ -196,6 +201,9 @@ public class DataUsageSummary extends Fragment {
private View mAppDetail;
private ImageView mAppIcon;
private ViewGroup mAppTitles;
+ private PieChartView mAppPieChart;
+ private TextView mAppForeground;
+ private TextView mAppBackground;
private Button mAppSettings;
private LinearLayout mAppSwitches;
@@ -216,6 +224,8 @@ public class DataUsageSummary extends Fragment {
private NetworkStatsHistory mHistory;
private NetworkStatsHistory mDetailHistory;
+ private NetworkStatsHistory mDetailHistoryDefault;
+ private NetworkStatsHistory mDetailHistoryForeground;
private String mCurrentTab = null;
private String mIntentTab = null;
@@ -301,6 +311,9 @@ public class DataUsageSummary extends Fragment {
mAppDetail = mHeader.findViewById(R.id.app_detail);
mAppIcon = (ImageView) mAppDetail.findViewById(R.id.app_icon);
mAppTitles = (ViewGroup) mAppDetail.findViewById(R.id.app_titles);
+ mAppPieChart = (PieChartView) mAppDetail.findViewById(R.id.app_pie_chart);
+ mAppForeground = (TextView) mAppDetail.findViewById(R.id.app_foreground);
+ mAppBackground = (TextView) mAppDetail.findViewById(R.id.app_background);
mAppSwitches = (LinearLayout) mAppDetail.findViewById(R.id.app_switches);
mAppSettings = (Button) mAppDetail.findViewById(R.id.app_settings);
@@ -539,12 +552,8 @@ public class DataUsageSummary extends Fragment {
* Build {@link TabSpec} with thin indicator, and empty content.
*/
private TabSpec buildTabSpec(String tag, int titleRes) {
- final LayoutInflater inflater = LayoutInflater.from(mTabWidget.getContext());
- final View indicator = inflater.inflate(
- R.layout.tab_indicator_thin_holo, mTabWidget, false);
- final TextView title = (TextView) indicator.findViewById(android.R.id.title);
- title.setText(titleRes);
- return mTabHost.newTabSpec(tag).setIndicator(indicator).setContent(mEmptyTabContent);
+ return mTabHost.newTabSpec(tag).setIndicator(getText(titleRes)).setContent(
+ mEmptyTabContent);
}
private OnTabChangeListener mTabListener = new OnTabChangeListener() {
@@ -658,6 +667,10 @@ public class DataUsageSummary extends Fragment {
mAppDetail.setVisibility(View.GONE);
mCycleAdapter.setChangeVisible(true);
+ mDetailHistory = null;
+ mDetailHistoryDefault = null;
+ mDetailHistoryForeground = null;
+
// hide detail stats when not in detail mode
mChart.bindDetailNetworkStats(null);
return;
@@ -697,15 +710,20 @@ public class DataUsageSummary extends Fragment {
try {
// load stats for current uid and template
- // TODO: read template from extras
- mDetailHistory = mStatsService.getHistoryForUid(
- mTemplate, mUid, TAG_NONE, FIELD_RX_BYTES | FIELD_TX_BYTES);
+ mDetailHistoryDefault = mStatsService.getHistoryForUid(
+ mTemplate, mUid, SET_DEFAULT, TAG_NONE, FIELD_RX_BYTES | FIELD_TX_BYTES);
+ mDetailHistoryForeground = mStatsService.getHistoryForUid(
+ mTemplate, mUid, SET_FOREGROUND, TAG_NONE, FIELD_RX_BYTES | FIELD_TX_BYTES);
} catch (RemoteException e) {
// since we can't do much without history, and we don't want to
// leave with half-baked UI, we bail hard.
throw new RuntimeException("problem reading network stats", e);
}
+ mDetailHistory = new NetworkStatsHistory(mDetailHistoryForeground.getBucketDuration());
+ mDetailHistory.recordEntireHistory(mDetailHistoryDefault);
+ mDetailHistory.recordEntireHistory(mDetailHistoryForeground);
+
// bind chart to historical stats
mChart.bindDetailNetworkStats(mDetailHistory);
@@ -1012,14 +1030,28 @@ public class DataUsageSummary extends Fragment {
final long now = System.currentTimeMillis();
final Context context = getActivity();
- final NetworkStatsHistory.Entry entry;
- if (isAppDetailMode()) {
- if (mDetailHistory != null) {
- entry = mDetailHistory.getValues(start, end, now, null);
- } else {
- entry = null;
- }
+ NetworkStatsHistory.Entry entry = null;
+ if (isAppDetailMode() && mDetailHistory != null) {
+ // bind foreground/background to piechart and labels
+ entry = mDetailHistoryDefault.getValues(start, end, now, entry);
+ final long defaultBytes = entry.rxBytes + entry.txBytes;
+ entry = mDetailHistoryForeground.getValues(start, end, now, entry);
+ final long foregroundBytes = entry.rxBytes + entry.txBytes;
+
+ mAppPieChart.setOriginAngle(175);
+
+ mAppPieChart.removeAllSlices();
+ mAppPieChart.addSlice(foregroundBytes, Color.parseColor("#d88d3a"));
+ mAppPieChart.addSlice(defaultBytes, Color.parseColor("#666666"));
+
+ mAppPieChart.generatePath();
+
+ mAppBackground.setText(Formatter.formatFileSize(context, defaultBytes));
+ mAppForeground.setText(Formatter.formatFileSize(context, foregroundBytes));
+
+ // and finally leave with summary data for label below
+ entry = mDetailHistory.getValues(start, end, now, null);
getLoaderManager().destroyLoader(LOADER_SUMMARY);
@@ -1206,31 +1238,38 @@ public class DataUsageSummary extends Fragment {
public void bindStats(NetworkStats stats) {
mItems.clear();
- if (stats != null) {
- final AppUsageItem systemItem = new AppUsageItem();
- systemItem.uid = android.os.Process.SYSTEM_UID;
-
- NetworkStats.Entry entry = null;
- for (int i = 0; i < stats.size(); i++) {
- 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();
- item.uid = entry.uid;
- item.total = entry.rxBytes + entry.txBytes;
+ final AppUsageItem systemItem = new AppUsageItem();
+ systemItem.uid = android.os.Process.SYSTEM_UID;
+
+ final SparseArray<AppUsageItem> knownUids = new SparseArray<AppUsageItem>();
+
+ NetworkStats.Entry entry = null;
+ final int size = stats != null ? stats.size() : 0;
+ for (int i = 0; i < size; i++) {
+ entry = stats.getValues(i, entry);
+
+ final int uid = entry.uid;
+ final boolean isApp = uid >= android.os.Process.FIRST_APPLICATION_UID
+ && uid <= android.os.Process.LAST_APPLICATION_UID;
+ if (isApp || uid == TrafficStats.UID_REMOVED) {
+ AppUsageItem item = knownUids.get(uid);
+ if (item == null) {
+ item = new AppUsageItem();
+ item.uid = uid;
+ knownUids.put(uid, item);
mItems.add(item);
- } else {
- systemItem.total += entry.rxBytes + entry.txBytes;
}
- }
- if (systemItem.total > 0) {
- mItems.add(systemItem);
+ item.total += entry.rxBytes + entry.txBytes;
+ } else {
+ systemItem.total += entry.rxBytes + entry.txBytes;
}
}
+ if (systemItem.total > 0) {
+ mItems.add(systemItem);
+ }
+
Collections.sort(mItems);
mLargest = (mItems.size() > 0) ? mItems.get(0).total : 0;
notifyDataSetChanged();
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 272c0d1..2572cef 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -63,7 +63,7 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler {
private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
"com.android.settings.PARENT_FRAGMENT_CLASS";
- private static final String EXTRA_THEME = "settings:theme";
+ private static final String EXTRA_CLEAR_UI_OPTIONS = "settings:remove_ui_options";
private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
@@ -82,9 +82,9 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler {
@Override
protected void onCreate(Bundle savedInstanceState) {
- final int theme = getIntent().getIntExtra(
- EXTRA_THEME, android.R.style.Theme_Holo);
- setTheme(theme);
+ if (getIntent().getBooleanExtra(EXTRA_CLEAR_UI_OPTIONS, false)) {
+ getWindow().setUiOptions(0);
+ }
getMetaData();
mInLocalHeaderSwitch = true;
@@ -288,12 +288,12 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler {
Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
titleRes, shortTitleRes);
- // some fragments would like a custom activity theme
+ // some fragments want to avoid split actionbar
if (DataUsageSummary.class.getName().equals(fragmentName) ||
PowerUsageSummary.class.getName().equals(fragmentName) ||
AccountSyncSettings.class.getName().equals(fragmentName) ||
UserDictionarySettings.class.getName().equals(fragmentName)) {
- intent.putExtra(EXTRA_THEME, android.R.style.Theme_Holo);
+ intent.putExtra(EXTRA_CLEAR_UI_OPTIONS, true);
}
intent.setClass(this, SubSettings.class);
diff --git a/src/com/android/settings/widget/ChartNetworkSeriesView.java b/src/com/android/settings/widget/ChartNetworkSeriesView.java
index 481f7cc..f0ccc1b 100644
--- a/src/com/android/settings/widget/ChartNetworkSeriesView.java
+++ b/src/com/android/settings/widget/ChartNetworkSeriesView.java
@@ -105,7 +105,7 @@ public class ChartNetworkSeriesView extends View {
public void setChartColor(int stroke, int fill, int fillSecondary) {
mPaintStroke = new Paint();
- mPaintStroke.setStrokeWidth(6.0f);
+ mPaintStroke.setStrokeWidth(4.0f * getResources().getDisplayMetrics().density);
mPaintStroke.setColor(stroke);
mPaintStroke.setStyle(Style.STROKE);
mPaintStroke.setAntiAlias(true);
@@ -165,7 +165,10 @@ public class ChartNetworkSeriesView extends View {
mPathEstimate.reset();
// bail when not enough stats to render
- if (mStats == null || mStats.size() < 2) return;
+ if (mStats == null || mStats.size() < 2) {
+ invalidate();
+ return;
+ }
final int width = getWidth();
final int height = getHeight();
@@ -263,6 +266,8 @@ public class ChartNetworkSeriesView extends View {
}
mMaxEstimate = totalData;
+
+ invalidate();
}
public void setEndTime(long endTime) {
diff --git a/src/com/android/settings/widget/ChartSweepView.java b/src/com/android/settings/widget/ChartSweepView.java
index d5e8de8..81aeb84 100644
--- a/src/com/android/settings/widget/ChartSweepView.java
+++ b/src/com/android/settings/widget/ChartSweepView.java
@@ -32,7 +32,6 @@ import android.util.AttributeSet;
import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.View;
-import android.widget.FrameLayout;
import com.android.settings.R;
import com.google.common.base.Preconditions;
@@ -41,7 +40,7 @@ import com.google.common.base.Preconditions;
* Sweep across a {@link ChartView} at a specific {@link ChartAxis} value, which
* a user can drag.
*/
-public class ChartSweepView extends FrameLayout {
+public class ChartSweepView extends View {
private Drawable mSweep;
private Rect mSweepPadding = new Rect();
@@ -78,7 +77,7 @@ public class ChartSweepView extends FrameLayout {
private MotionEvent mTracking;
public ChartSweepView(Context context) {
- this(context, null, 0);
+ this(context, null);
}
public ChartSweepView(Context context, AttributeSet attrs) {
@@ -101,8 +100,6 @@ public class ChartSweepView extends FrameLayout {
a.recycle();
- setClipToPadding(false);
- setClipChildren(false);
setWillNotDraw(false);
}
diff --git a/src/com/android/settings/widget/ChartView.java b/src/com/android/settings/widget/ChartView.java
index a5b8b09..e3a658a 100644
--- a/src/com/android/settings/widget/ChartView.java
+++ b/src/com/android/settings/widget/ChartView.java
@@ -19,12 +19,16 @@ package com.android.settings.widget;
import static com.google.common.base.Preconditions.checkNotNull;
import android.content.Context;
+import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
+import android.view.ViewDebug;
import android.widget.FrameLayout;
+import com.android.settings.R;
+
/**
* Container for two-dimensional chart, drawn with a combination of
* {@link ChartGridView}, {@link ChartNetworkSeriesView} and {@link ChartSweepView}
@@ -41,6 +45,10 @@ public class ChartView extends FrameLayout {
ChartAxis mHoriz;
ChartAxis mVert;
+ @ViewDebug.ExportedProperty
+ private int mOptimalWidth = -1;
+ private float mOptimalWidthWeight = 0;
+
private Rect mContent = new Rect();
public ChartView(Context context) {
@@ -54,6 +62,12 @@ public class ChartView extends FrameLayout {
public ChartView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.ChartView, defStyle, 0);
+ setOptimalWidth(a.getDimensionPixelSize(R.styleable.ChartView_optimalWidth, -1),
+ a.getFloat(R.styleable.ChartView_optimalWidthWeight, 0));
+ a.recycle();
+
setClipToPadding(false);
setClipChildren(false);
}
@@ -63,6 +77,24 @@ public class ChartView extends FrameLayout {
mVert = checkNotNull(vert, "missing vert");
}
+ public void setOptimalWidth(int optimalWidth, float optimalWidthWeight) {
+ mOptimalWidth = optimalWidth;
+ mOptimalWidthWeight = optimalWidthWeight;
+ requestLayout();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ final int slack = getMeasuredWidth() - mOptimalWidth;
+ if (mOptimalWidth > 0 && slack > 0) {
+ final int targetWidth = (int) (mOptimalWidth + (slack * mOptimalWidthWeight));
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mContent.set(getPaddingLeft(), getPaddingTop(), r - l - getPaddingRight(),
diff --git a/src/com/android/settings/widget/DataUsageChartView.java b/src/com/android/settings/widget/DataUsageChartView.java
index a1c92e1..f6ae5a0 100644
--- a/src/com/android/settings/widget/DataUsageChartView.java
+++ b/src/com/android/settings/widget/DataUsageChartView.java
@@ -226,8 +226,6 @@ public class DataUsageChartView extends ChartView {
mDetailSeries.generatePath();
mGrid.invalidate();
- mSeries.invalidate();
- mDetailSeries.invalidate();
// since we just changed axis, make sweep recalculate its value
if (activeSweep != null) {
@@ -362,7 +360,6 @@ public class DataUsageChartView extends ChartView {
requestLayout();
mSeries.generatePath();
- mSeries.invalidate();
updateVertAxisBounds(null);
updateEstimateVisible();
diff --git a/src/com/android/settings/widget/PieChartView.java b/src/com/android/settings/widget/PieChartView.java
new file mode 100644
index 0000000..85d45a2
--- /dev/null
+++ b/src/com/android/settings/widget/PieChartView.java
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.widget;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.graphics.Path.Direction;
+import android.graphics.RadialGradient;
+import android.graphics.RectF;
+import android.graphics.Shader.TileMode;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+
+/**
+ * Pie chart with multiple items.
+ */
+public class PieChartView extends View {
+ public static final String TAG = "PieChartView";
+ public static final boolean LOGD = true;
+
+ private ArrayList<Slice> mSlices = Lists.newArrayList();
+
+ private int mOriginAngle;
+
+ private Paint mPaintPrimary = new Paint();
+ private Paint mPaintShadow = new Paint();
+
+ private Path mPathSide = new Path();
+ private Path mPathSideShadow = new Path();
+
+ private Path mPathShadow = new Path();
+
+ private int mSideWidth;
+
+ public class Slice {
+ public long value;
+
+ public Path pathPrimary = new Path();
+ public Path pathShadow = new Path();
+
+ public Paint paintPrimary;
+
+ public Slice(long value, int color) {
+ this.value = value;
+ this.paintPrimary = buildFillPaint(color, getResources());
+ }
+ }
+
+ public PieChartView(Context context) {
+ this(context, null);
+ }
+
+ public PieChartView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public PieChartView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ mPaintPrimary = buildFillPaint(Color.parseColor("#666666"), getResources());
+
+ mPaintShadow.setColor(Color.BLACK);
+ mPaintShadow.setStyle(Style.STROKE);
+ mPaintShadow.setStrokeWidth(3f * getResources().getDisplayMetrics().density);
+ mPaintShadow.setAntiAlias(true);
+
+ mSideWidth = (int) (20 * getResources().getDisplayMetrics().density);
+
+ setWillNotDraw(false);
+ }
+
+ private static Paint buildFillPaint(int color, Resources res) {
+ final Paint paint = new Paint();
+
+ paint.setColor(color);
+ paint.setStyle(Style.FILL_AND_STROKE);
+ paint.setAntiAlias(true);
+
+ final int width = (int) (280 * res.getDisplayMetrics().density);
+ paint.setShader(new RadialGradient(0, 0, width, color, darken(color), TileMode.MIRROR));
+
+ return paint;
+ }
+
+ public void setOriginAngle(int originAngle) {
+ mOriginAngle = originAngle;
+ }
+
+ public void addSlice(long value, int color) {
+ mSlices.add(new Slice(value, color));
+ }
+
+ public void removeAllSlices() {
+ mSlices.clear();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ generatePath();
+ }
+
+ public void generatePath() {
+ if (LOGD) Log.d(TAG, "generatePath()");
+
+ long total = 0;
+ for (Slice slice : mSlices) {
+ slice.pathPrimary.reset();
+ slice.pathShadow.reset();
+ total += slice.value;
+ }
+
+ mPathSide.reset();
+ mPathSideShadow.reset();
+ mPathShadow.reset();
+
+ // bail when not enough stats to render
+ if (total == 0) {
+ invalidate();
+ return;
+ }
+
+ final int width = getWidth();
+ final int height = getHeight();
+
+ final RectF rect = new RectF(0, 0, width, height);
+
+ mPathSide.addOval(rect, Direction.CW);
+ mPathSideShadow.addOval(rect, Direction.CW);
+ mPathShadow.addOval(rect, Direction.CW);
+
+ int startAngle = mOriginAngle;
+ for (Slice slice : mSlices) {
+ final int sweepAngle = (int) (slice.value * 360 / total);
+
+ slice.pathPrimary.moveTo(rect.centerX(), rect.centerY());
+ slice.pathPrimary.arcTo(rect, startAngle, sweepAngle);
+ slice.pathPrimary.lineTo(rect.centerX(), rect.centerY());
+
+ slice.pathShadow.moveTo(rect.centerX(), rect.centerY());
+ slice.pathShadow.arcTo(rect, startAngle, 0);
+ slice.pathShadow.moveTo(rect.centerX(), rect.centerY());
+ slice.pathShadow.arcTo(rect, startAngle + sweepAngle, 0);
+
+ startAngle += sweepAngle;
+ }
+
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+
+ canvas.translate(getWidth() * 0.25f, getHeight() * -0.05f);
+ canvas.rotate(-40, getWidth() * 0.5f, getHeight());
+ canvas.scale(0.7f, 1.0f, getWidth(), getHeight());
+
+ canvas.save();
+ canvas.translate(-mSideWidth, 0);
+ canvas.drawPath(mPathSide, mPaintPrimary);
+ canvas.drawPath(mPathSideShadow, mPaintShadow);
+ canvas.restore();
+
+ for (Slice slice : mSlices) {
+ canvas.drawPath(slice.pathPrimary, slice.paintPrimary);
+ canvas.drawPath(slice.pathShadow, mPaintShadow);
+ }
+ canvas.drawPath(mPathShadow, mPaintShadow);
+ }
+
+ public static int darken(int color) {
+ float[] hsv = new float[3];
+ Color.colorToHSV(color, hsv);
+ hsv[2] /= 2;
+ hsv[1] /= 2;
+ return Color.HSVToColor(hsv);
+ }
+
+}