summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/drawable-hdpi/data_sweep_left_activated.9.pngbin851 -> 857 bytes
-rw-r--r--res/drawable-hdpi/data_sweep_left_default.9.pngbin790 -> 795 bytes
-rw-r--r--res/drawable-hdpi/data_sweep_limit_activated.9.pngbin711 -> 707 bytes
-rw-r--r--res/drawable-hdpi/data_sweep_limit_default.9.pngbin833 -> 838 bytes
-rw-r--r--res/drawable-hdpi/data_sweep_right_activated.9.pngbin766 -> 767 bytes
-rw-r--r--res/drawable-hdpi/data_sweep_right_default.9.pngbin799 -> 806 bytes
-rw-r--r--res/drawable-hdpi/data_sweep_warning_activated.9.pngbin813 -> 816 bytes
-rw-r--r--res/drawable-hdpi/data_sweep_warning_default.9.pngbin847 -> 850 bytes
-rw-r--r--res/drawable-mdpi/data_sweep_left_activated.9.pngbin568 -> 565 bytes
-rw-r--r--res/drawable-mdpi/data_sweep_left_default.9.pngbin526 -> 524 bytes
-rw-r--r--res/drawable-mdpi/data_sweep_limit_activated.9.pngbin563 -> 551 bytes
-rw-r--r--res/drawable-mdpi/data_sweep_limit_default.9.pngbin591 -> 554 bytes
-rw-r--r--res/drawable-mdpi/data_sweep_right_activated.9.pngbin572 -> 575 bytes
-rw-r--r--res/drawable-mdpi/data_sweep_right_default.9.pngbin535 -> 533 bytes
-rw-r--r--res/drawable-mdpi/data_sweep_warning_activated.9.pngbin621 -> 616 bytes
-rw-r--r--res/drawable-mdpi/data_sweep_warning_default.9.pngbin616 -> 581 bytes
-rw-r--r--res/drawable-xhdpi/data_sweep_left_activated.9.pngbin1519 -> 1520 bytes
-rw-r--r--res/drawable-xhdpi/data_sweep_left_default.9.pngbin1461 -> 1464 bytes
-rw-r--r--res/drawable-xhdpi/data_sweep_limit_activated.9.pngbin1434 -> 1410 bytes
-rw-r--r--res/drawable-xhdpi/data_sweep_limit_default.9.pngbin1473 -> 1400 bytes
-rw-r--r--res/drawable-xhdpi/data_sweep_right_activated.9.pngbin1683 -> 1687 bytes
-rw-r--r--res/drawable-xhdpi/data_sweep_right_default.9.pngbin1481 -> 1489 bytes
-rw-r--r--res/drawable-xhdpi/data_sweep_warning_activated.9.pngbin1547 -> 1566 bytes
-rw-r--r--res/drawable-xhdpi/data_sweep_warning_default.9.pngbin1557 -> 1480 bytes
-rw-r--r--res/drawable/data_sweep_left.xml4
-rw-r--r--res/drawable/data_sweep_limit.xml4
-rw-r--r--res/drawable/data_sweep_right.xml4
-rw-r--r--res/drawable/data_sweep_warning.xml4
-rw-r--r--res/layout/data_usage_chart.xml14
-rw-r--r--res/layout/data_usage_detail.xml66
-rw-r--r--res/layout/data_usage_header.xml5
-rw-r--r--src/com/android/settings/DataUsageAppDetail.java309
-rw-r--r--src/com/android/settings/DataUsageSummary.java342
-rw-r--r--src/com/android/settings/net/NetworkPolicyEditor.java10
-rw-r--r--src/com/android/settings/widget/ChartNetworkSeriesView.java15
-rw-r--r--src/com/android/settings/widget/ChartSweepView.java85
-rw-r--r--src/com/android/settings/widget/ChartView.java23
-rw-r--r--src/com/android/settings/widget/DataUsageChartView.java57
38 files changed, 481 insertions, 461 deletions
diff --git a/res/drawable-hdpi/data_sweep_left_activated.9.png b/res/drawable-hdpi/data_sweep_left_activated.9.png
index e91ccf5..28efd35 100644
--- a/res/drawable-hdpi/data_sweep_left_activated.9.png
+++ b/res/drawable-hdpi/data_sweep_left_activated.9.png
Binary files differ
diff --git a/res/drawable-hdpi/data_sweep_left_default.9.png b/res/drawable-hdpi/data_sweep_left_default.9.png
index 76f33a5..4b6f2df 100644
--- a/res/drawable-hdpi/data_sweep_left_default.9.png
+++ b/res/drawable-hdpi/data_sweep_left_default.9.png
Binary files differ
diff --git a/res/drawable-hdpi/data_sweep_limit_activated.9.png b/res/drawable-hdpi/data_sweep_limit_activated.9.png
index 4744037..59de0d3 100644
--- a/res/drawable-hdpi/data_sweep_limit_activated.9.png
+++ b/res/drawable-hdpi/data_sweep_limit_activated.9.png
Binary files differ
diff --git a/res/drawable-hdpi/data_sweep_limit_default.9.png b/res/drawable-hdpi/data_sweep_limit_default.9.png
index dea3a0b..d7f3a88 100644
--- a/res/drawable-hdpi/data_sweep_limit_default.9.png
+++ b/res/drawable-hdpi/data_sweep_limit_default.9.png
Binary files differ
diff --git a/res/drawable-hdpi/data_sweep_right_activated.9.png b/res/drawable-hdpi/data_sweep_right_activated.9.png
index afb15d6..ccd7ff9 100644
--- a/res/drawable-hdpi/data_sweep_right_activated.9.png
+++ b/res/drawable-hdpi/data_sweep_right_activated.9.png
Binary files differ
diff --git a/res/drawable-hdpi/data_sweep_right_default.9.png b/res/drawable-hdpi/data_sweep_right_default.9.png
index 9d3808f..1179fde 100644
--- a/res/drawable-hdpi/data_sweep_right_default.9.png
+++ b/res/drawable-hdpi/data_sweep_right_default.9.png
Binary files differ
diff --git a/res/drawable-hdpi/data_sweep_warning_activated.9.png b/res/drawable-hdpi/data_sweep_warning_activated.9.png
index 81a7aa8..9ecd28b 100644
--- a/res/drawable-hdpi/data_sweep_warning_activated.9.png
+++ b/res/drawable-hdpi/data_sweep_warning_activated.9.png
Binary files differ
diff --git a/res/drawable-hdpi/data_sweep_warning_default.9.png b/res/drawable-hdpi/data_sweep_warning_default.9.png
index e2485fe..ec2b9df 100644
--- a/res/drawable-hdpi/data_sweep_warning_default.9.png
+++ b/res/drawable-hdpi/data_sweep_warning_default.9.png
Binary files differ
diff --git a/res/drawable-mdpi/data_sweep_left_activated.9.png b/res/drawable-mdpi/data_sweep_left_activated.9.png
index 39111d4..fc6764a 100644
--- a/res/drawable-mdpi/data_sweep_left_activated.9.png
+++ b/res/drawable-mdpi/data_sweep_left_activated.9.png
Binary files differ
diff --git a/res/drawable-mdpi/data_sweep_left_default.9.png b/res/drawable-mdpi/data_sweep_left_default.9.png
index 139ed1e..31343e7 100644
--- a/res/drawable-mdpi/data_sweep_left_default.9.png
+++ b/res/drawable-mdpi/data_sweep_left_default.9.png
Binary files differ
diff --git a/res/drawable-mdpi/data_sweep_limit_activated.9.png b/res/drawable-mdpi/data_sweep_limit_activated.9.png
index 64d539a..b01d5f0 100644
--- a/res/drawable-mdpi/data_sweep_limit_activated.9.png
+++ b/res/drawable-mdpi/data_sweep_limit_activated.9.png
Binary files differ
diff --git a/res/drawable-mdpi/data_sweep_limit_default.9.png b/res/drawable-mdpi/data_sweep_limit_default.9.png
index db41d66..a59649a 100644
--- a/res/drawable-mdpi/data_sweep_limit_default.9.png
+++ b/res/drawable-mdpi/data_sweep_limit_default.9.png
Binary files differ
diff --git a/res/drawable-mdpi/data_sweep_right_activated.9.png b/res/drawable-mdpi/data_sweep_right_activated.9.png
index 2fba366..5314538 100644
--- a/res/drawable-mdpi/data_sweep_right_activated.9.png
+++ b/res/drawable-mdpi/data_sweep_right_activated.9.png
Binary files differ
diff --git a/res/drawable-mdpi/data_sweep_right_default.9.png b/res/drawable-mdpi/data_sweep_right_default.9.png
index 533f165..cc3b586 100644
--- a/res/drawable-mdpi/data_sweep_right_default.9.png
+++ b/res/drawable-mdpi/data_sweep_right_default.9.png
Binary files differ
diff --git a/res/drawable-mdpi/data_sweep_warning_activated.9.png b/res/drawable-mdpi/data_sweep_warning_activated.9.png
index 6813526..ed44d4d 100644
--- a/res/drawable-mdpi/data_sweep_warning_activated.9.png
+++ b/res/drawable-mdpi/data_sweep_warning_activated.9.png
Binary files differ
diff --git a/res/drawable-mdpi/data_sweep_warning_default.9.png b/res/drawable-mdpi/data_sweep_warning_default.9.png
index 65ab32f..760ea18 100644
--- a/res/drawable-mdpi/data_sweep_warning_default.9.png
+++ b/res/drawable-mdpi/data_sweep_warning_default.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/data_sweep_left_activated.9.png b/res/drawable-xhdpi/data_sweep_left_activated.9.png
index 83883be..ff9631e 100644
--- a/res/drawable-xhdpi/data_sweep_left_activated.9.png
+++ b/res/drawable-xhdpi/data_sweep_left_activated.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/data_sweep_left_default.9.png b/res/drawable-xhdpi/data_sweep_left_default.9.png
index 968825b..2e0651c 100644
--- a/res/drawable-xhdpi/data_sweep_left_default.9.png
+++ b/res/drawable-xhdpi/data_sweep_left_default.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/data_sweep_limit_activated.9.png b/res/drawable-xhdpi/data_sweep_limit_activated.9.png
index de988ae..ae02388 100644
--- a/res/drawable-xhdpi/data_sweep_limit_activated.9.png
+++ b/res/drawable-xhdpi/data_sweep_limit_activated.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/data_sweep_limit_default.9.png b/res/drawable-xhdpi/data_sweep_limit_default.9.png
index 2c9b534..7391148 100644
--- a/res/drawable-xhdpi/data_sweep_limit_default.9.png
+++ b/res/drawable-xhdpi/data_sweep_limit_default.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/data_sweep_right_activated.9.png b/res/drawable-xhdpi/data_sweep_right_activated.9.png
index 25508b5..81c1a3c 100644
--- a/res/drawable-xhdpi/data_sweep_right_activated.9.png
+++ b/res/drawable-xhdpi/data_sweep_right_activated.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/data_sweep_right_default.9.png b/res/drawable-xhdpi/data_sweep_right_default.9.png
index 7363cd7..94a9f61 100644
--- a/res/drawable-xhdpi/data_sweep_right_default.9.png
+++ b/res/drawable-xhdpi/data_sweep_right_default.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/data_sweep_warning_activated.9.png b/res/drawable-xhdpi/data_sweep_warning_activated.9.png
index 2da464b..0a2d2b1 100644
--- a/res/drawable-xhdpi/data_sweep_warning_activated.9.png
+++ b/res/drawable-xhdpi/data_sweep_warning_activated.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/data_sweep_warning_default.9.png b/res/drawable-xhdpi/data_sweep_warning_default.9.png
index c7a7b29..d5f6044 100644
--- a/res/drawable-xhdpi/data_sweep_warning_default.9.png
+++ b/res/drawable-xhdpi/data_sweep_warning_default.9.png
Binary files differ
diff --git a/res/drawable/data_sweep_left.xml b/res/drawable/data_sweep_left.xml
index 739a74e..cb801a0 100644
--- a/res/drawable/data_sweep_left.xml
+++ b/res/drawable/data_sweep_left.xml
@@ -17,6 +17,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
- <item android:state_activated="true" android:drawable="@drawable/data_sweep_left_activated" />
- <item android:state_activated="false" android:drawable="@drawable/data_sweep_left_default" />
+ <item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_left_activated" />
+ <item android:drawable="@drawable/data_sweep_left_default" />
</selector>
diff --git a/res/drawable/data_sweep_limit.xml b/res/drawable/data_sweep_limit.xml
index 29ecec8..378b0aa 100644
--- a/res/drawable/data_sweep_limit.xml
+++ b/res/drawable/data_sweep_limit.xml
@@ -17,6 +17,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
- <item android:state_activated="true" android:drawable="@drawable/data_sweep_limit_activated" />
- <item android:state_activated="false" android:drawable="@drawable/data_sweep_limit_default" />
+ <item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_limit_activated" />
+ <item android:drawable="@drawable/data_sweep_limit_default" />
</selector>
diff --git a/res/drawable/data_sweep_right.xml b/res/drawable/data_sweep_right.xml
index 1a11469..a75a1b2 100644
--- a/res/drawable/data_sweep_right.xml
+++ b/res/drawable/data_sweep_right.xml
@@ -17,6 +17,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
- <item android:state_activated="true" android:drawable="@drawable/data_sweep_right_activated" />
- <item android:state_activated="false" android:drawable="@drawable/data_sweep_right_default" />
+ <item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_right_activated" />
+ <item android:drawable="@drawable/data_sweep_right_default" />
</selector>
diff --git a/res/drawable/data_sweep_warning.xml b/res/drawable/data_sweep_warning.xml
index 5cafe06..001d0c5 100644
--- a/res/drawable/data_sweep_warning.xml
+++ b/res/drawable/data_sweep_warning.xml
@@ -17,6 +17,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
- <item android:state_activated="true" android:drawable="@drawable/data_sweep_warning_activated" />
- <item android:state_activated="false" android:drawable="@drawable/data_sweep_warning_default" />
+ <item android:state_activated="true" android:state_enabled="true" android:drawable="@drawable/data_sweep_warning_activated" />
+ <item android:drawable="@drawable/data_sweep_warning_default" />
</selector>
diff --git a/res/layout/data_usage_chart.xml b/res/layout/data_usage_chart.xml
index 5fd640f..199a38e 100644
--- a/res/layout/data_usage_chart.xml
+++ b/res/layout/data_usage_chart.xml
@@ -17,6 +17,7 @@
<com.android.settings.widget.DataUsageChartView
xmlns:android="http://schemas.android.com/apk/res/android"
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">
@@ -40,11 +41,19 @@
settings:fillColor="#c050ade5"
settings:fillColorSecondary="#88566abc" />
+ <com.android.settings.widget.ChartNetworkSeriesView
+ android:id="@+id/detail_series"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="left|bottom"
+ settings:strokeColor="#d88d3a"
+ settings:fillColor="#c0ba7f3e"
+ settings:fillColorSecondary="#0000" />
+
<com.android.settings.widget.ChartSweepView
android:id="@+id/sweep_left"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_gravity="center_horizontal"
settings:sweepDrawable="@drawable/data_sweep_left"
settings:followAxis="horizontal"
settings:showLabel="false" />
@@ -53,7 +62,6 @@
android:id="@+id/sweep_right"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_gravity="center_horizontal"
settings:sweepDrawable="@drawable/data_sweep_right"
settings:followAxis="horizontal"
settings:showLabel="false" />
@@ -62,7 +70,6 @@
android:id="@+id/sweep_limit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
settings:sweepDrawable="@drawable/data_sweep_limit"
settings:followAxis="vertical"
settings:showLabel="true" />
@@ -71,7 +78,6 @@
android:id="@+id/sweep_warning"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
settings:sweepDrawable="@drawable/data_sweep_warning"
settings:followAxis="vertical"
settings:showLabel="true" />
diff --git a/res/layout/data_usage_detail.xml b/res/layout/data_usage_detail.xml
index 9415b3f..2c8e490 100644
--- a/res/layout/data_usage_detail.xml
+++ b/res/layout/data_usage_detail.xml
@@ -14,43 +14,35 @@
limitations under the License.
-->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+<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="match_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/app_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="16dip" />
+
+ <TextView
+ android:id="@+id/app_subtitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="16dip" />
+
+ <Button
+ android:id="@+id/app_settings"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dip"
+ android:text="@string/data_usage_app_settings" />
+
<LinearLayout
+ android:id="@+id/app_switches"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <FrameLayout
- android:id="@+id/chart_container"
- android:layout_width="match_parent"
- android:layout_height="233dip" />
-
- <TextView
- android:id="@android:id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="16dip" />
-
- <TextView
- android:id="@android:id/text1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="16dip" />
-
- <Button
- android:id="@+id/data_usage_app_settings"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="16dip"
- android:text="@string/data_usage_app_settings" />
-
- <LinearLayout
- android:id="@+id/switches"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" />
-
- </LinearLayout>
-</ScrollView>
+ android:layout_height="wrap_content"
+ android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/res/layout/data_usage_header.xml b/res/layout/data_usage_header.xml
index 8e6f054..3f4ca5b 100644
--- a/res/layout/data_usage_header.xml
+++ b/res/layout/data_usage_header.xml
@@ -20,7 +20,7 @@
android:orientation="vertical">
<LinearLayout
- android:id="@+id/switches"
+ android:id="@+id/network_switches"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
@@ -48,4 +48,7 @@
</LinearLayout>
+ <include layout="@layout/data_usage_chart" />
+ <include layout="@layout/data_usage_detail" />
+
</LinearLayout>
diff --git a/src/com/android/settings/DataUsageAppDetail.java b/src/com/android/settings/DataUsageAppDetail.java
deleted file mode 100644
index 6294ad3..0000000
--- a/src/com/android/settings/DataUsageAppDetail.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * 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;
-
-import static android.net.NetworkPolicyManager.POLICY_NONE;
-import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
-import static com.android.settings.DataUsageSummary.getHistoryBounds;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.Fragment;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.graphics.Color;
-import android.net.INetworkPolicyManager;
-import android.net.INetworkStatsService;
-import android.net.NetworkPolicyManager;
-import android.net.NetworkStats;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkTemplate;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.preference.CheckBoxPreference;
-import android.preference.Preference;
-import android.text.format.DateUtils;
-import android.text.format.Formatter;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.settings.widget.DataUsageChartView;
-import com.android.settings.widget.DataUsageChartView.DataUsageChartListener;
-
-public class DataUsageAppDetail extends Fragment {
- private static final String TAG = "DataUsage";
- private static final boolean LOGD = true;
-
- public static final String EXTRA_UID = "uid";
- public static final String EXTRA_NETWORK_TEMPLATE = "networkTemplate";
-
- private int mUid;
- private NetworkTemplate mTemplate;
-
- private Intent mAppSettingsIntent;
-
- private static final String TAG_CONFIRM_RESTRICT = "confirmRestrict";
-
- private INetworkStatsService mStatsService;
- private INetworkPolicyManager mPolicyService;
-
- private CheckBoxPreference mRestrictBackground;
- private View mRestrictBackgroundView;
-
- private FrameLayout mChartContainer;
- private TextView mTitle;
- private TextView mText1;
- private Button mAppSettings;
- private LinearLayout mSwitches;
-
- private DataUsageChartView mChart;
- private NetworkStatsHistory mHistory;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- mStatsService = INetworkStatsService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
- mPolicyService = INetworkPolicyManager.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
-
- final Context context = inflater.getContext();
- final View view = inflater.inflate(R.layout.data_usage_detail, container, false);
-
- mChartContainer = (FrameLayout) view.findViewById(R.id.chart_container);
- mTitle = (TextView) view.findViewById(android.R.id.title);
- mText1 = (TextView) view.findViewById(android.R.id.text1);
- mAppSettings = (Button) view.findViewById(R.id.data_usage_app_settings);
- mSwitches = (LinearLayout) view.findViewById(R.id.switches);
-
- mRestrictBackground = new CheckBoxPreference(context);
- mRestrictBackground.setTitle(R.string.data_usage_app_restrict_background);
- mRestrictBackground.setSummary(R.string.data_usage_app_restrict_background_summary);
-
- // kick refresh once to force-create views
- refreshPreferenceViews();
-
- mSwitches.addView(mRestrictBackgroundView);
- mRestrictBackgroundView.setOnClickListener(mRestrictBackgroundListener);
-
- mAppSettings.setOnClickListener(mAppSettingsListener);
-
- mChart = new DataUsageChartView(context);
- mChartContainer.addView(mChart);
-
- mChart.setListener(mChartListener);
- mChart.setChartColor(Color.parseColor("#d88d3a"), Color.parseColor("#c0ba7f3e"),
- Color.parseColor("#88566abc"));
-
- return view;
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- updateBody();
- }
-
- private void updateBody() {
- final PackageManager pm = getActivity().getPackageManager();
-
- mUid = getArguments().getInt(EXTRA_UID);
- mTemplate = getArguments().getParcelable(EXTRA_NETWORK_TEMPLATE);
-
- mTitle.setText(pm.getNameForUid(mUid));
-
- // enable settings button when package provides it
- // TODO: target torwards entire UID instead of just first package
- final String[] packageNames = pm.getPackagesForUid(mUid);
- if (packageNames != null && packageNames.length > 0) {
- mAppSettingsIntent = new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE);
- mAppSettingsIntent.setPackage(packageNames[0]);
- mAppSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
-
- final boolean matchFound = pm.resolveActivity(mAppSettingsIntent, 0) != null;
- mAppSettings.setEnabled(matchFound);
-
- } else {
- mAppSettingsIntent = null;
- mAppSettings.setEnabled(false);
- }
-
- try {
- // load stats for current uid and template
- // TODO: read template from extras
- mHistory = mStatsService.getHistoryForUid(mTemplate, mUid, NetworkStats.TAG_NONE);
- } 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);
- }
-
- // bind chart to historical stats
- mChart.bindNetworkStats(mHistory);
-
- // show entire history known
- final long[] bounds = getHistoryBounds(mHistory);
- mChart.setVisibleRange(bounds[0], bounds[1] + DateUtils.WEEK_IN_MILLIS, bounds[1]);
- updateDetailData();
-
- final Context context = getActivity();
- if (NetworkPolicyManager.isUidValidForPolicy(context, mUid)) {
- mRestrictBackgroundView.setVisibility(View.VISIBLE);
-
- final int uidPolicy;
- try {
- uidPolicy = mPolicyService.getUidPolicy(mUid);
- } catch (RemoteException e) {
- // since we can't do much without policy, we bail hard.
- throw new RuntimeException("problem reading network policy", e);
- }
-
- // update policy checkbox
- final boolean restrictBackground = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
- mRestrictBackground.setChecked(restrictBackground);
-
- // kick preference views so they rebind from changes above
- refreshPreferenceViews();
-
- } else {
- mRestrictBackgroundView.setVisibility(View.GONE);
- }
- }
-
- private void updateDetailData() {
- if (LOGD) Log.d(TAG, "updateDetailData()");
-
- final Context context = mChart.getContext();
- final long[] range = mChart.getInspectRange();
- final long[] total = mHistory.getTotalData(range[0], range[1], null);
- final long totalCombined = total[0] + total[1];
- mText1.setText(Formatter.formatFileSize(context, totalCombined));
- }
-
- private void setRestrictBackground(boolean restrictBackground) {
- if (LOGD) Log.d(TAG, "setRestrictBackground()");
- try {
- mPolicyService.setUidPolicy(
- mUid, restrictBackground ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
- } catch (RemoteException e) {
- throw new RuntimeException("unable to save policy", e);
- }
-
- mRestrictBackground.setChecked(restrictBackground);
- refreshPreferenceViews();
- }
-
- /**
- * Force rebind of hijacked {@link Preference} views.
- */
- private void refreshPreferenceViews() {
- mRestrictBackgroundView = mRestrictBackground.getView(mRestrictBackgroundView, mSwitches);
- }
-
- private DataUsageChartListener mChartListener = new DataUsageChartListener() {
- /** {@inheritDoc} */
- public void onInspectRangeChanged() {
- if (LOGD) Log.d(TAG, "onInspectRangeChanged()");
- updateDetailData();
- }
-
- /** {@inheritDoc} */
- public void onWarningChanged() {
- // ignored
- }
-
- /** {@inheritDoc} */
- public void onLimitChanged() {
- // ignored
- }
- };
-
- private OnClickListener mAppSettingsListener = new OnClickListener() {
- /** {@inheritDoc} */
- public void onClick(View v) {
- // TODO: target torwards entire UID instead of just first package
- startActivity(mAppSettingsIntent);
- }
- };
-
- private OnClickListener mRestrictBackgroundListener = new OnClickListener() {
- /** {@inheritDoc} */
- public void onClick(View v) {
- final boolean restrictBackground = !mRestrictBackground.isChecked();
-
- if (restrictBackground) {
- // enabling restriction; show confirmation dialog which
- // eventually calls setRestrictBackground() once user confirms.
- ConfirmRestrictFragment.show(DataUsageAppDetail.this);
- } else {
- setRestrictBackground(false);
- }
- }
- };
-
- /**
- * Dialog to request user confirmation before setting
- * {@link #POLICY_REJECT_METERED_BACKGROUND}.
- */
- public static class ConfirmRestrictFragment extends DialogFragment {
- public static void show(DataUsageAppDetail parent) {
- final ConfirmRestrictFragment dialog = new ConfirmRestrictFragment();
- dialog.setTargetFragment(parent, 0);
- dialog.show(parent.getFragmentManager(), TAG_CONFIRM_RESTRICT);
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- final Context context = getActivity();
-
- final AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.data_usage_app_restrict_dialog_title);
- builder.setMessage(R.string.data_usage_app_restrict_dialog);
-
- builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- final DataUsageAppDetail target = (DataUsageAppDetail) getTargetFragment();
- if (target != null) {
- target.setRestrictBackground(true);
- }
- }
- });
- builder.setNegativeButton(android.R.string.cancel, null);
-
- return builder.create();
- }
- }
-
-}
diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java
index 692c753..098f57a 100644
--- a/src/com/android/settings/DataUsageSummary.java
+++ b/src/com/android/settings/DataUsageSummary.java
@@ -21,6 +21,8 @@ import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicyManager.ACTION_DATA_USAGE_LIMIT;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
+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.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
@@ -29,10 +31,12 @@ import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
import static android.net.NetworkTemplate.MATCH_WIFI;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import android.animation.LayoutTransition;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.Fragment;
+import android.app.FragmentTransaction;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -54,7 +58,6 @@ import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.preference.Preference;
-import android.preference.PreferenceActivity;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.text.format.DateUtils;
@@ -66,12 +69,14 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
+import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
@@ -106,8 +111,6 @@ public class DataUsageSummary extends Fragment {
private static final String TAG = "DataUsage";
private static final boolean LOGD = true;
- private static final int TEMPLATE_INVALID = -1;
-
private static final String TAB_3G = "3g";
private static final String TAB_4G = "4g";
private static final String TAB_MOBILE = "mobile";
@@ -116,6 +119,8 @@ public class DataUsageSummary extends Fragment {
private static final String TAG_CONFIRM_LIMIT = "confirmLimit";
private static final String TAG_CYCLE_EDITOR = "cycleEditor";
private static final String TAG_POLICY_LIMIT = "policyLimit";
+ private static final String TAG_CONFIRM_RESTRICT = "confirmRestrict";
+ private static final String TAG_APP_DETAILS = "appDetails";
private static final long KB_IN_BYTES = 1024;
private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
@@ -135,25 +140,41 @@ public class DataUsageSummary extends Fragment {
private ListView mListView;
private DataUsageAdapter mAdapter;
- private View mHeader;
- private LinearLayout mSwitches;
+ private ViewGroup mHeader;
+ private LinearLayout mNetworkSwitches;
private Switch mDataEnabled;
- private CheckBox mDisableAtLimit;
private View mDataEnabledView;
+ private CheckBox mDisableAtLimit;
private View mDisableAtLimitView;
- private DataUsageChartView mChart;
-
private Spinner mCycleSpinner;
private CycleAdapter mCycleAdapter;
+ private DataUsageChartView mChart;
+
+ private View mAppDetail;
+ private TextView mAppTitle;
+ private TextView mAppSubtitle;
+ private Button mAppSettings;
+
+ private LinearLayout mAppSwitches;
+ private CheckBox mAppRestrict;
+ private View mAppRestrictView;
+
private boolean mShowWifi = false;
private NetworkTemplate mTemplate = null;
+ private static final int UID_NONE = -1;
+ private int mUid = UID_NONE;
+
+ private Intent mAppSettingsIntent;
+
private NetworkPolicyEditor mPolicyEditor;
+
private NetworkStatsHistory mHistory;
+ private NetworkStatsHistory mDetailHistory;
private String mIntentTab = null;
@@ -194,30 +215,57 @@ public class DataUsageSummary extends Fragment {
mTabHost.setup();
mTabHost.setOnTabChangedListener(mTabListener);
- mHeader = inflater.inflate(R.layout.data_usage_header, mListView, false);
+ mHeader = (ViewGroup) inflater.inflate(R.layout.data_usage_header, mListView, false);
mListView.addHeaderView(mHeader, null, false);
- mDataEnabled = new Switch(inflater.getContext());
- mDataEnabledView = inflatePreference(inflater, mSwitches, mDataEnabled);
- mDataEnabled.setOnCheckedChangeListener(mDataEnabledListener);
+ {
+ // bind network switches
+ mNetworkSwitches = (LinearLayout) mHeader.findViewById(R.id.network_switches);
- mDisableAtLimit = new CheckBox(inflater.getContext());
- mDisableAtLimit.setClickable(false);
- mDisableAtLimitView = inflatePreference(inflater, mSwitches, mDisableAtLimit);
- mDisableAtLimitView.setOnClickListener(mDisableAtLimitListener);
+ mDataEnabled = new Switch(inflater.getContext());
+ mDataEnabledView = inflatePreference(inflater, mNetworkSwitches, mDataEnabled);
+ mDataEnabled.setOnCheckedChangeListener(mDataEnabledListener);
+ mNetworkSwitches.addView(mDataEnabledView);
- mSwitches = (LinearLayout) mHeader.findViewById(R.id.switches);
- mSwitches.addView(mDataEnabledView);
- mSwitches.addView(mDisableAtLimitView);
+ mDisableAtLimit = new CheckBox(inflater.getContext());
+ mDisableAtLimit.setClickable(false);
+ mDisableAtLimitView = inflatePreference(inflater, mNetworkSwitches, mDisableAtLimit);
+ mDisableAtLimitView.setOnClickListener(mDisableAtLimitListener);
+ mNetworkSwitches.addView(mDisableAtLimitView);
+ }
+ // bind cycle dropdown
mCycleSpinner = (Spinner) mHeader.findViewById(R.id.cycles);
mCycleAdapter = new CycleAdapter(context);
mCycleSpinner.setAdapter(mCycleAdapter);
mCycleSpinner.setOnItemSelectedListener(mCycleListener);
- mChart = (DataUsageChartView) inflater.inflate(R.layout.data_usage_chart, mListView, false);
+ mChart = (DataUsageChartView) mHeader.findViewById(R.id.chart);
mChart.setListener(mChartListener);
- mListView.addHeaderView(mChart, null, false);
+
+ {
+ // bind app detail controls
+ mAppDetail = view.findViewById(R.id.app_detail);
+ mAppTitle = (TextView) view.findViewById(R.id.app_title);
+ mAppSubtitle = (TextView) view.findViewById(R.id.app_subtitle);
+ mAppSwitches = (LinearLayout) view.findViewById(R.id.app_switches);
+
+ mAppSettings = (Button) view.findViewById(R.id.app_settings);
+ mAppSettings.setOnClickListener(mAppSettingsListener);
+
+ mAppRestrict = new CheckBox(inflater.getContext());
+ mAppRestrict.setClickable(false);
+ mAppRestrictView = inflatePreference(inflater, mAppSwitches, mAppRestrict);
+ setPreferenceTitle(mAppRestrictView, R.string.data_usage_app_restrict_background);
+ setPreferenceSummary(
+ mAppRestrictView, R.string.data_usage_app_restrict_background_summary);
+ mAppRestrictView.setOnClickListener(mAppRestrictListener);
+ mAppSwitches.addView(mAppRestrictView);
+ }
+
+ // TODO: tweak these transitions
+ final LayoutTransition transition = new LayoutTransition();
+ mHeader.setLayoutTransition(transition);
mAdapter = new DataUsageAdapter();
mListView.setOnItemClickListener(mListListener);
@@ -433,6 +481,7 @@ public class DataUsageSummary extends Fragment {
mChart.bindNetworkStats(mHistory);
updatePolicy(true);
+ updateAppDetail();
// force scroll to top of body
mListView.smoothScrollToPosition(0);
@@ -440,6 +489,84 @@ public class DataUsageSummary extends Fragment {
mBinding = false;
}
+ private boolean isAppDetailMode() {
+ return mUid != UID_NONE;
+ }
+
+ /**
+ * Update UID details panels to match {@link #mUid}, showing or hiding them
+ * depending on {@link #isAppDetailMode()}.
+ */
+ private void updateAppDetail() {
+ if (isAppDetailMode()) {
+ mAppDetail.setVisibility(View.VISIBLE);
+ } else {
+ mAppDetail.setVisibility(View.GONE);
+
+ // hide detail stats when not in detail mode
+ mChart.bindDetailNetworkStats(null);
+ return;
+ }
+
+ // remove warning/limit sweeps while in detail mode
+ mChart.bindNetworkPolicy(null);
+
+ final PackageManager pm = getActivity().getPackageManager();
+ mAppTitle.setText(pm.getNameForUid(mUid));
+
+ // enable settings button when package provides it
+ // TODO: target torwards entire UID instead of just first package
+ final String[] packageNames = pm.getPackagesForUid(mUid);
+ if (packageNames != null && packageNames.length > 0) {
+ mAppSettingsIntent = new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE);
+ mAppSettingsIntent.setPackage(packageNames[0]);
+ mAppSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
+
+ final boolean matchFound = pm.resolveActivity(mAppSettingsIntent, 0) != null;
+ mAppSettings.setEnabled(matchFound);
+
+ } else {
+ mAppSettingsIntent = null;
+ mAppSettings.setEnabled(false);
+ }
+
+ try {
+ // load stats for current uid and template
+ // TODO: read template from extras
+ mDetailHistory = mStatsService.getHistoryForUid(mTemplate, mUid, NetworkStats.TAG_NONE);
+ } 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);
+ }
+
+ // bind chart to historical stats
+ mChart.bindDetailNetworkStats(mDetailHistory);
+
+ updateDetailData();
+
+ final Context context = getActivity();
+ if (NetworkPolicyManager.isUidValidForPolicy(context, mUid)) {
+ mAppRestrictView.setVisibility(View.VISIBLE);
+
+ final int uidPolicy;
+ try {
+ uidPolicy = mPolicyService.getUidPolicy(mUid);
+ } catch (RemoteException e) {
+ // since we can't do much without policy, we bail hard.
+ throw new RuntimeException("problem reading network policy", e);
+ }
+
+ // update policy checkbox
+ final boolean restrictBackground = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
+ mAppRestrict.setChecked(restrictBackground);
+
+ } else {
+ mAppRestrictView.setVisibility(View.GONE);
+ }
+
+ }
+
private void setPolicyCycleDay(int cycleDay) {
if (LOGD) Log.d(TAG, "setPolicyCycleDay()");
mPolicyEditor.setPolicyCycleDay(mTemplate, cycleDay);
@@ -458,11 +585,30 @@ public class DataUsageSummary extends Fragment {
updatePolicy(false);
}
+ private void setAppRestrictBackground(boolean restrictBackground) {
+ if (LOGD) Log.d(TAG, "setRestrictBackground()");
+ try {
+ mPolicyService.setUidPolicy(
+ mUid, restrictBackground ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
+ } catch (RemoteException e) {
+ throw new RuntimeException("unable to save policy", e);
+ }
+
+ mAppRestrict.setChecked(restrictBackground);
+ }
+
/**
* Update chart sweeps and cycle list to reflect {@link NetworkPolicy} for
* current {@link #mTemplate}.
*/
private void updatePolicy(boolean refreshCycle) {
+ if (isAppDetailMode()) {
+ mNetworkSwitches.setVisibility(View.GONE);
+ // we fall through to update cycle list for detail mode
+ } else {
+ mNetworkSwitches.setVisibility(View.VISIBLE);
+ }
+
final NetworkPolicy policy = mPolicyEditor.getPolicy(mTemplate);
// reflect policy limit in checkbox
@@ -572,18 +718,34 @@ public class DataUsageSummary extends Fragment {
}
};
+ private View.OnClickListener mAppRestrictListener = new View.OnClickListener() {
+ /** {@inheritDoc} */
+ public void onClick(View v) {
+ final boolean restrictBackground = !mAppRestrict.isChecked();
+
+ if (restrictBackground) {
+ // enabling restriction; show confirmation dialog which
+ // eventually calls setRestrictBackground() once user confirms.
+ ConfirmRestrictFragment.show(DataUsageSummary.this);
+ } else {
+ setAppRestrictBackground(false);
+ }
+ }
+ };
+
+ private OnClickListener mAppSettingsListener = new OnClickListener() {
+ /** {@inheritDoc} */
+ public void onClick(View v) {
+ // TODO: target torwards entire UID instead of just first package
+ startActivity(mAppSettingsIntent);
+ }
+ };
+
private OnItemClickListener mListListener = new OnItemClickListener() {
/** {@inheritDoc} */
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final AppUsageItem app = (AppUsageItem) parent.getItemAtPosition(position);
-
- final Bundle args = new Bundle();
- args.putParcelable(DataUsageAppDetail.EXTRA_NETWORK_TEMPLATE, mTemplate);
- args.putInt(DataUsageAppDetail.EXTRA_UID, app.uid);
-
- final PreferenceActivity activity = (PreferenceActivity) getActivity();
- activity.startPreferencePanel(DataUsageAppDetail.class.getName(), args,
- R.string.data_usage_summary_title, null, null, 0);
+ AppDetailsFragment.show(DataUsageSummary.this, app.uid);
}
};
@@ -621,12 +783,30 @@ public class DataUsageSummary extends Fragment {
};
/**
- * Update {@link #mAdapter} with sorted list of applications data usage,
- * based on current inspection from {@link #mChart}.
+ * Update details based on {@link #mChart} inspection range depending on
+ * current mode. In network mode, updates {@link #mAdapter} with sorted list
+ * of applications data usage, and when {@link #isAppDetailMode()} update
+ * app details.
*/
private void updateDetailData() {
if (LOGD) Log.d(TAG, "updateDetailData()");
+ if (isAppDetailMode()) {
+ if (mDetailHistory != null) {
+ final Context context = mChart.getContext();
+ final long[] range = mChart.getInspectRange();
+ final long[] total = mDetailHistory.getTotalData(range[0], range[1], null);
+ final long totalCombined = total[0] + total[1];
+ mAppSubtitle.setText(Formatter.formatFileSize(context, totalCombined));
+ }
+
+ // clear any existing app list details
+ mAdapter.bindStats(null);
+
+ return;
+ }
+
+ // otherwise kick off task to update list
new AsyncTask<Void, Void, NetworkStats>() {
@Override
protected NetworkStats doInBackground(Void... params) {
@@ -753,15 +933,20 @@ public class DataUsageSummary extends Fragment {
public static class DataUsageAdapter extends BaseAdapter {
private ArrayList<AppUsageItem> mItems = Lists.newArrayList();
+ /**
+ * Bind the given {@link NetworkStats}, or {@code null} to clear list.
+ */
public void bindStats(NetworkStats stats) {
mItems.clear();
- for (int i = 0; i < stats.size; i++) {
- final long total = stats.rx[i] + stats.tx[i];
- final AppUsageItem item = new AppUsageItem();
- item.uid = stats.uid[i];
- item.total = total;
- mItems.add(item);
+ if (stats != null) {
+ for (int i = 0; i < stats.size; i++) {
+ final long total = stats.rx[i] + stats.tx[i];
+ final AppUsageItem item = new AppUsageItem();
+ item.uid = stats.uid[i];
+ item.total = total;
+ mItems.add(item);
+ }
}
Collections.sort(mItems);
@@ -806,6 +991,44 @@ public class DataUsageSummary extends Fragment {
}
/**
+ * Empty {@link Fragment} that controls display of UID details in
+ * {@link DataUsageSummary}.
+ */
+ public static class AppDetailsFragment extends Fragment {
+ public static final String EXTRA_UID = "uid";
+
+ public static void show(DataUsageSummary parent, int uid) {
+ final Bundle args = new Bundle();
+ args.putInt(EXTRA_UID, uid);
+
+ final AppDetailsFragment fragment = new AppDetailsFragment();
+ fragment.setArguments(args);
+ fragment.setTargetFragment(parent, 0);
+
+ final FragmentTransaction ft = parent.getFragmentManager().beginTransaction();
+ ft.add(fragment, TAG_APP_DETAILS);
+ ft.addToBackStack(TAG_APP_DETAILS);
+ ft.commit();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ final DataUsageSummary target = (DataUsageSummary) getTargetFragment();
+ target.mUid = getArguments().getInt(EXTRA_UID);
+ target.updateBody();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ final DataUsageSummary target = (DataUsageSummary) getTargetFragment();
+ target.mUid = UID_NONE;
+ target.updateBody();
+ }
+ }
+
+ /**
* Dialog to request user confirmation before setting
* {@link NetworkPolicy#limitBytes}.
*/
@@ -976,11 +1199,44 @@ public class DataUsageSummary extends Fragment {
}
/**
+ * Dialog to request user confirmation before setting
+ * {@link #POLICY_REJECT_METERED_BACKGROUND}.
+ */
+ public static class ConfirmRestrictFragment extends DialogFragment {
+ public static void show(DataUsageSummary parent) {
+ final ConfirmRestrictFragment dialog = new ConfirmRestrictFragment();
+ dialog.setTargetFragment(parent, 0);
+ dialog.show(parent.getFragmentManager(), TAG_CONFIRM_RESTRICT);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Context context = getActivity();
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.data_usage_app_restrict_dialog_title);
+ builder.setMessage(R.string.data_usage_app_restrict_dialog);
+
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ final DataUsageSummary target = (DataUsageSummary) getTargetFragment();
+ if (target != null) {
+ target.setAppRestrictBackground(true);
+ }
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, null);
+
+ return builder.create();
+ }
+ }
+
+ /**
* Compute default tab that should be selected, based on
* {@link NetworkPolicyManager#EXTRA_NETWORK_TEMPLATE} extra.
*/
private static String computeTabFromIntent(Intent intent) {
- final int networkTemplate = intent.getIntExtra(EXTRA_NETWORK_TEMPLATE, TEMPLATE_INVALID);
+ final int networkTemplate = intent.getIntExtra(EXTRA_NETWORK_TEMPLATE, MATCH_MOBILE_ALL);
switch (networkTemplate) {
case MATCH_MOBILE_3G_LOWER:
return TAB_3G;
@@ -1083,4 +1339,14 @@ public class DataUsageSummary extends Fragment {
title.setText(resId);
}
+ /**
+ * Set {@link android.R.id#summary} for a preference view inflated with
+ * {@link #inflatePreference(LayoutInflater, ViewGroup, View)}.
+ */
+ private static void setPreferenceSummary(View parent, int resId) {
+ final TextView summary = (TextView) parent.findViewById(android.R.id.summary);
+ summary.setVisibility(View.VISIBLE);
+ summary.setText(resId);
+ }
+
}
diff --git a/src/com/android/settings/net/NetworkPolicyEditor.java b/src/com/android/settings/net/NetworkPolicyEditor.java
index c50a490..61c2550 100644
--- a/src/com/android/settings/net/NetworkPolicyEditor.java
+++ b/src/com/android/settings/net/NetworkPolicyEditor.java
@@ -16,6 +16,8 @@
package com.android.settings.net;
+import static android.net.NetworkPolicy.LIMIT_DISABLED;
+import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
@@ -51,6 +53,14 @@ public class NetworkPolicyEditor {
final NetworkPolicy[] policies = mPolicyService.getNetworkPolicies();
mPolicies.clear();
for (NetworkPolicy policy : policies) {
+ // TODO: find better place to clamp these
+ if (policy.limitBytes < -1) {
+ policy.limitBytes = LIMIT_DISABLED;
+ }
+ if (policy.warningBytes < -1) {
+ policy.warningBytes = WARNING_DISABLED;
+ }
+
mPolicies.add(policy);
}
} catch (RemoteException e) {
diff --git a/src/com/android/settings/widget/ChartNetworkSeriesView.java b/src/com/android/settings/widget/ChartNetworkSeriesView.java
index 0a34565..83c10cd 100644
--- a/src/com/android/settings/widget/ChartNetworkSeriesView.java
+++ b/src/com/android/settings/widget/ChartNetworkSeriesView.java
@@ -75,6 +75,7 @@ public class ChartNetworkSeriesView extends View {
R.styleable.ChartNetworkSeriesView_fillColorSecondary, Color.RED);
setChartColor(stroke, fill, fillSecondary);
+ setWillNotDraw(false);
a.recycle();
@@ -110,8 +111,13 @@ public class ChartNetworkSeriesView extends View {
mPathStroke.reset();
mPathFill.reset();
+ invalidate();
}
+ /**
+ * Set the range to paint with {@link #mPaintFill}, leaving the remaining
+ * area to be painted with {@link #mPaintFillSecondary}.
+ */
public void setPrimaryRange(long left, long right) {
mPrimaryLeft = left;
mPrimaryRight = right;
@@ -190,18 +196,21 @@ public class ChartNetworkSeriesView extends View {
protected void onDraw(Canvas canvas) {
int save;
+ final float primaryLeftPoint = mHoriz.convertToPoint(mPrimaryLeft);
+ final float primaryRightPoint = mHoriz.convertToPoint(mPrimaryRight);
+
save = canvas.save();
- canvas.clipRect(0, 0, mPrimaryLeft, getHeight());
+ canvas.clipRect(0, 0, primaryLeftPoint, getHeight());
canvas.drawPath(mPathFill, mPaintFillSecondary);
canvas.restoreToCount(save);
save = canvas.save();
- canvas.clipRect(mPrimaryRight, 0, getWidth(), getHeight());
+ canvas.clipRect(primaryRightPoint, 0, getWidth(), getHeight());
canvas.drawPath(mPathFill, mPaintFillSecondary);
canvas.restoreToCount(save);
save = canvas.save();
- canvas.clipRect(mPrimaryLeft, 0, mPrimaryRight, getHeight());
+ canvas.clipRect(primaryLeftPoint, 0, primaryRightPoint, getHeight());
canvas.drawPath(mPathFill, mPaintFill);
canvas.drawPath(mPathStroke, mPaintStroke);
canvas.restoreToCount(save);
diff --git a/src/com/android/settings/widget/ChartSweepView.java b/src/com/android/settings/widget/ChartSweepView.java
index 881fde4..d8344d5 100644
--- a/src/com/android/settings/widget/ChartSweepView.java
+++ b/src/com/android/settings/widget/ChartSweepView.java
@@ -39,6 +39,8 @@ public class ChartSweepView extends FrameLayout {
// TODO: paint label when requested
private Drawable mSweep;
+ private Rect mSweepMargins = new Rect();
+
private int mFollowAxis;
private boolean mShowLabel;
@@ -88,8 +90,28 @@ public class ChartSweepView extends FrameLayout {
return mFollowAxis;
}
- public void getExtraMargins(Rect rect) {
- mSweep.getPadding(rect);
+ /**
+ * Return margins of {@link #setSweepDrawable(Drawable)}, indicating how the
+ * sweep should be displayed around a content region.
+ */
+ public Rect getSweepMargins() {
+ return mSweepMargins;
+ }
+
+ /**
+ * Return the number of pixels that the "target" area is inset from the
+ * {@link View} edge, along the current {@link #setFollowAxis(int)}.
+ */
+ public float getTargetInset() {
+ if (mFollowAxis == VERTICAL) {
+ final float targetHeight = mSweep.getIntrinsicHeight() - mSweepMargins.top
+ - mSweepMargins.bottom;
+ return mSweepMargins.top + (targetHeight / 2);
+ } else {
+ final float targetWidth = mSweep.getIntrinsicWidth() - mSweepMargins.left
+ - mSweepMargins.right;
+ return mSweepMargins.left + (targetWidth / 2);
+ }
}
public void addOnSweepListener(OnSweepListener listener) {
@@ -115,6 +137,7 @@ public class ChartSweepView extends FrameLayout {
}
sweep.setVisible(getVisibility() == VISIBLE, false);
mSweep = sweep;
+ sweep.getPadding(mSweepMargins);
} else {
mSweep = null;
}
@@ -175,33 +198,51 @@ public class ChartSweepView extends FrameLayout {
final View parent = (View) getParent();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
- mTracking = event.copy();
- return true;
+
+ // only start tracking when in sweet spot
+ final boolean accept;
+ if (mFollowAxis == VERTICAL) {
+ accept = event.getX() > getWidth() - (mSweepMargins.right * 2);
+ } else {
+ accept = event.getY() > getHeight() - (mSweepMargins.bottom * 2);
+ }
+
+ if (accept) {
+ mTracking = event.copy();
+ return true;
+ } else {
+ return false;
+ }
}
case MotionEvent.ACTION_MOVE: {
getParent().requestDisallowInterceptTouchEvent(true);
+ final Rect sweepMargins = mSweepMargins;
+
+ // content area of parent
+ final Rect parentContent = new Rect(parent.getPaddingLeft(), parent.getPaddingTop(),
+ parent.getWidth() - parent.getPaddingRight(),
+ parent.getHeight() - parent.getPaddingBottom());
+
if (mFollowAxis == VERTICAL) {
- final float chartHeight = parent.getHeight() - parent.getPaddingTop()
- - parent.getPaddingBottom();
- final float translationY = MathUtils.constrain(
- event.getRawY() - mTracking.getRawY(), -getTop(),
- chartHeight - getTop());
- setTranslationY(translationY);
- final float point = (getTop() + getTranslationY() + (getHeight() / 2))
- - parent.getPaddingTop();
- mValue = mAxis.convertToValue(point);
+ final float currentTargetY = getTop() + getTargetInset();
+ final float requestedTargetY = currentTargetY
+ + (event.getRawY() - mTracking.getRawY());
+ final float clampedTargetY = MathUtils.constrain(
+ requestedTargetY, parentContent.top, parentContent.bottom);
+ setTranslationY(clampedTargetY - currentTargetY);
+
+ mValue = mAxis.convertToValue(clampedTargetY - parentContent.top);
dispatchOnSweep(false);
} else {
- final float chartWidth = parent.getWidth() - parent.getPaddingLeft()
- - parent.getPaddingRight();
- final float translationX = MathUtils.constrain(
- event.getRawX() - mTracking.getRawX(), -getLeft(),
- chartWidth - getLeft());
- setTranslationX(translationX);
- final float point = (getLeft() + getTranslationX() + (getWidth() / 2))
- - parent.getPaddingLeft();
- mValue = mAxis.convertToValue(point);
+ final float currentTargetX = getLeft() + getTargetInset();
+ final float requestedTargetX = currentTargetX
+ + (event.getRawX() - mTracking.getRawX());
+ final float clampedTargetX = MathUtils.constrain(
+ requestedTargetX, parentContent.left, parentContent.right);
+ setTranslationX(clampedTargetX - currentTargetX);
+
+ mValue = mAxis.convertToValue(clampedTargetX - parentContent.left);
dispatchOnSweep(false);
}
return true;
diff --git a/src/com/android/settings/widget/ChartView.java b/src/com/android/settings/widget/ChartView.java
index d762631..bf5616d 100644
--- a/src/com/android/settings/widget/ChartView.java
+++ b/src/com/android/settings/widget/ChartView.java
@@ -36,6 +36,8 @@ public class ChartView extends FrameLayout {
// TODO: extend something that supports two-dimensional scrolling
+ private static final int SWEEP_GRAVITY = Gravity.TOP | Gravity.LEFT;
+
ChartAxis mHoriz;
ChartAxis mVert;
@@ -74,7 +76,6 @@ public class ChartView extends FrameLayout {
final Rect parentRect = new Rect();
final Rect childRect = new Rect();
- final Rect extraMargins = new Rect();
for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
@@ -91,21 +92,23 @@ public class ChartView extends FrameLayout {
} else if (child instanceof ChartSweepView) {
// sweep is always placed along specific dimension
final ChartSweepView sweep = (ChartSweepView) child;
+ final Rect sweepMargins = sweep.getSweepMargins();
final float point = sweep.getPoint();
- sweep.getExtraMargins(extraMargins);
if (sweep.getFollowAxis() == ChartSweepView.HORIZONTAL) {
- parentRect.left = parentRect.right = (int) point + getPaddingLeft();
- parentRect.top -= extraMargins.top;
- parentRect.bottom += extraMargins.bottom;
- Gravity.apply(params.gravity, child.getMeasuredWidth(), parentRect.height(),
+ parentRect.left = parentRect.right =
+ (int) (sweep.getPoint() - sweep.getTargetInset()) + getPaddingLeft();
+ parentRect.top -= sweepMargins.top;
+ parentRect.bottom += sweepMargins.bottom;
+ Gravity.apply(SWEEP_GRAVITY, child.getMeasuredWidth(), parentRect.height(),
parentRect, childRect);
} else {
- parentRect.top = parentRect.bottom = (int) point + getPaddingTop();
- parentRect.left -= extraMargins.left;
- parentRect.right += extraMargins.right;
- Gravity.apply(params.gravity, parentRect.width(), child.getMeasuredHeight(),
+ parentRect.top = parentRect.bottom =
+ (int) (sweep.getPoint() - sweep.getTargetInset()) + getPaddingTop();
+ parentRect.left -= sweepMargins.left;
+ parentRect.right += sweepMargins.right;
+ Gravity.apply(SWEEP_GRAVITY, parentRect.width(), child.getMeasuredHeight(),
parentRect, childRect);
}
}
diff --git a/src/com/android/settings/widget/DataUsageChartView.java b/src/com/android/settings/widget/DataUsageChartView.java
index 1c76291..6fe4042 100644
--- a/src/com/android/settings/widget/DataUsageChartView.java
+++ b/src/com/android/settings/widget/DataUsageChartView.java
@@ -38,10 +38,10 @@ public class DataUsageChartView extends ChartView {
private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
// TODO: enforce that sweeps cant cross each other
- // TODO: limit sweeps at graph boundaries
private ChartGridView mGrid;
private ChartNetworkSeriesView mSeries;
+ private ChartNetworkSeriesView mDetailSeries;
private ChartSweepView mSweepLeft;
private ChartSweepView mSweepRight;
@@ -75,6 +75,8 @@ public class DataUsageChartView extends ChartView {
mGrid = (ChartGridView) findViewById(R.id.grid);
mSeries = (ChartNetworkSeriesView) findViewById(R.id.series);
+ mDetailSeries = (ChartNetworkSeriesView) findViewById(R.id.detail_series);
+ mDetailSeries.setVisibility(View.GONE);
mSweepLeft = (ChartSweepView) findViewById(R.id.sweep_left);
mSweepRight = (ChartSweepView) findViewById(R.id.sweep_right);
@@ -89,6 +91,7 @@ public class DataUsageChartView extends ChartView {
// tell everyone about our axis
mGrid.init(mHoriz, mVert);
mSeries.init(mHoriz, mVert);
+ mDetailSeries.init(mHoriz, mVert);
mSweepLeft.init(mHoriz);
mSweepRight.init(mHoriz);
mSweepWarning.init(mVert);
@@ -97,27 +100,21 @@ public class DataUsageChartView extends ChartView {
setActivated(false);
}
- @Override
- public void setActivated(boolean activated) {
- super.setActivated(activated);
-
- mSweepLeft.setEnabled(activated);
- mSweepRight.setEnabled(activated);
- mSweepWarning.setEnabled(activated);
- mSweepLimit.setEnabled(activated);
- }
-
- @Deprecated
- public void setChartColor(int stroke, int fill, int disabled) {
- mSeries.setChartColor(stroke, fill, disabled);
- }
-
public void setListener(DataUsageChartListener listener) {
mListener = listener;
}
public void bindNetworkStats(NetworkStatsHistory stats) {
mSeries.bindNetworkStats(stats);
+ updatePrimaryRange();
+ requestLayout();
+ }
+
+ public void bindDetailNetworkStats(NetworkStatsHistory stats) {
+ mDetailSeries.bindNetworkStats(stats);
+ mDetailSeries.setVisibility(stats != null ? View.VISIBLE : View.GONE);
+ updatePrimaryRange();
+ requestLayout();
}
public void bindNetworkPolicy(NetworkPolicy policy) {
@@ -146,22 +143,11 @@ public class DataUsageChartView extends ChartView {
}
requestLayout();
-
- // TODO: eventually remove this; was to work around lack of sweep clamping
- if (policy.limitBytes < -1 || policy.limitBytes > 5 * GB_IN_BYTES) {
- policy.limitBytes = 5 * GB_IN_BYTES;
- mLimitListener.onSweep(mSweepLimit, true);
- }
- if (policy.warningBytes < -1 || policy.warningBytes > 5 * GB_IN_BYTES) {
- policy.warningBytes = 4 * GB_IN_BYTES;
- mWarningListener.onSweep(mSweepWarning, true);
- }
-
}
private OnSweepListener mSweepListener = new OnSweepListener() {
public void onSweep(ChartSweepView sweep, boolean sweepDone) {
- mSeries.setPrimaryRange(mSweepLeft.getValue(), mSweepRight.getValue());
+ updatePrimaryRange();
// update detail list only when done sweeping
if (sweepDone && mListener != null) {
@@ -236,13 +222,26 @@ public class DataUsageChartView extends ChartView {
mSweepLeft.setValue(sweepMin);
mSweepRight.setValue(sweepMax);
- mSeries.setPrimaryRange(sweepMin, sweepMax);
+ updatePrimaryRange();
requestLayout();
mSeries.generatePath();
mSeries.invalidate();
}
+ private void updatePrimaryRange() {
+ final long left = mSweepLeft.getValue();
+ final long right = mSweepRight.getValue();
+
+ // prefer showing primary range on detail series, when available
+ if (mDetailSeries.getVisibility() == View.VISIBLE) {
+ mDetailSeries.setPrimaryRange(left, right);
+ mSeries.setPrimaryRange(0, 0);
+ } else {
+ mSeries.setPrimaryRange(left, right);
+ }
+ }
+
public static class TimeAxis implements ChartAxis {
private static final long TICK_INTERVAL = DateUtils.DAY_IN_MILLIS * 7;