Merge "Add "large text" accessibility option."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9b33600..5e37d06 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -54,7 +54,7 @@
     <application android:label="@string/settings_label"
             android:icon="@mipmap/ic_launcher_settings"
             android:taskAffinity=""
-            android:hardwareAccelerated="true">
+            android:hardwareAccelerated="false">
 
         <!-- Settings -->
 
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-hdpi/ic_settings_battery.png b/res/drawable-hdpi/ic_settings_battery.png
new file mode 100755
index 0000000..e3b0fb3
--- /dev/null
+++ b/res/drawable-hdpi/ic_settings_battery.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_settings_development.png b/res/drawable-hdpi/ic_settings_development.png
new file mode 100755
index 0000000..e3b0fb3
--- /dev/null
+++ b/res/drawable-hdpi/ic_settings_development.png
Binary files differ
diff --git a/res/drawable-mdpi/data_grid_border.9.png b/res/drawable-mdpi/data_grid_border.9.png
new file mode 100644
index 0000000..85912b8
--- /dev/null
+++ b/res/drawable-mdpi/data_grid_border.9.png
Binary files differ
diff --git a/res/drawable-mdpi/data_grid_primary.9.png b/res/drawable-mdpi/data_grid_primary.9.png
new file mode 100644
index 0000000..0aa9143
--- /dev/null
+++ b/res/drawable-mdpi/data_grid_primary.9.png
Binary files differ
diff --git a/res/drawable-mdpi/data_grid_secondary.9.png b/res/drawable-mdpi/data_grid_secondary.9.png
new file mode 100644
index 0000000..7a09593
--- /dev/null
+++ b/res/drawable-mdpi/data_grid_secondary.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
new file mode 100644
index 0000000..fc6764a
--- /dev/null
+++ 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
new file mode 100644
index 0000000..31343e7
--- /dev/null
+++ 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
new file mode 100644
index 0000000..b01d5f0
--- /dev/null
+++ 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
new file mode 100644
index 0000000..a59649a
--- /dev/null
+++ 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
new file mode 100644
index 0000000..5314538
--- /dev/null
+++ 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
new file mode 100644
index 0000000..cc3b586
--- /dev/null
+++ 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
new file mode 100644
index 0000000..ed44d4d
--- /dev/null
+++ 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
new file mode 100644
index 0000000..760ea18
--- /dev/null
+++ b/res/drawable-mdpi/data_sweep_warning_default.9.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_settings_battery.png b/res/drawable-mdpi/ic_settings_battery.png
new file mode 100644
index 0000000..e1f478b
--- /dev/null
+++ b/res/drawable-mdpi/ic_settings_battery.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_settings_development.png b/res/drawable-mdpi/ic_settings_development.png
new file mode 100644
index 0000000..e1f478b
--- /dev/null
+++ b/res/drawable-mdpi/ic_settings_development.png
Binary files differ
diff --git a/res/drawable-xhdpi/data_grid_border.9.png b/res/drawable-xhdpi/data_grid_border.9.png
new file mode 100644
index 0000000..2139cf2
--- /dev/null
+++ b/res/drawable-xhdpi/data_grid_border.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/data_grid_primary.9.png b/res/drawable-xhdpi/data_grid_primary.9.png
new file mode 100644
index 0000000..ae68886
--- /dev/null
+++ b/res/drawable-xhdpi/data_grid_primary.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/data_grid_secondary.9.png b/res/drawable-xhdpi/data_grid_secondary.9.png
new file mode 100644
index 0000000..7a09593
--- /dev/null
+++ b/res/drawable-xhdpi/data_grid_secondary.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
new file mode 100644
index 0000000..ff9631e
--- /dev/null
+++ 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
new file mode 100644
index 0000000..2e0651c
--- /dev/null
+++ 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
new file mode 100644
index 0000000..ae02388
--- /dev/null
+++ 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
new file mode 100644
index 0000000..7391148
--- /dev/null
+++ 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
new file mode 100644
index 0000000..81c1a3c
--- /dev/null
+++ 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
new file mode 100644
index 0000000..94a9f61
--- /dev/null
+++ 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
new file mode 100644
index 0000000..0a2d2b1
--- /dev/null
+++ 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
new file mode 100644
index 0000000..d5f6044
--- /dev/null
+++ b/res/drawable-xhdpi/data_sweep_warning_default.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_settings_data_usage.png b/res/drawable-xhdpi/ic_settings_data_usage.png
new file mode 100644
index 0000000..176dd11
--- /dev/null
+++ b/res/drawable-xhdpi/ic_settings_data_usage.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">
-    <LinearLayout
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/app_title"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical">
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="16dip" />
 
-        <FrameLayout
-            android:id="@+id/chart_container"
-            android:layout_width="match_parent"
-            android:layout_height="233dip" />
+    <TextView
+        android:id="@+id/app_subtitle"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="16dip" />
 
-        <TextView
-            android:id="@android:id/title"
-            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" />
 
-        <TextView
-            android:id="@android:id/text1"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="16dip" />
+    <LinearLayout
+        android:id="@+id/app_switches"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical" />
 
-        <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>
+</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/res/values/strings.xml b/res/values/strings.xml
index 24161c2..f7318bd 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1330,7 +1330,7 @@
     <!-- Main Settings screen setting option name to go into the sound settings screen -->
     <string name="sound_settings_title">Sound</string>
     <!-- Main Settings screen setting option name to go into the display settings screen -->
-    <string name="display_settings_title">Screen</string>
+    <string name="display_settings_title">Display</string>
     <!-- Sound settings screen heading -->
     <string name="sound_settings">Sound settings</string>
     <!-- Sound settings screen, setting option name checkbox -->
@@ -2677,7 +2677,7 @@
     <skip />
 
     <!-- Activity title for App Fuel Gauge summary -->
-    <string name="power_usage_summary_title">Battery use</string>
+    <string name="power_usage_summary_title">Battery</string>
     <!-- Activity title summary for App Fuel Gauge summary -->
     <string name="power_usage_summary">What has been using the battery</string>
     <!-- Message to show when battery usage data is not available [CHAR LIMIT=30] -->
@@ -3127,11 +3127,11 @@
     <!-- Sound settings screen, setting option summary text -->
     <string name="emergency_tone_summary">Set behavior when an emergency call is placed</string>
 
-    <!-- Privacy Settings screen --><skip />
-    <!-- Privacy settings menu title -->
-    <string name="privacy_settings">Privacy</string>
+    <!-- Backup and reset Settings screen --><skip />
+    <!-- Backup and reset settings menu title -->
+    <string name="privacy_settings">Backup &amp; reset</string>
     <!-- Privacy settings activity title -->
-    <string name="privacy_settings_title">Privacy settings</string>
+    <string name="privacy_settings_title">Backup &amp; reset</string>
     <!-- Backup section title -->
     <string name="backup_section_title">Backup and restore</string>
     <!-- Personal data section title -->
diff --git a/res/xml/application_settings.xml b/res/xml/application_settings.xml
index 3ad1e5d..3329662 100644
--- a/res/xml/application_settings.xml
+++ b/res/xml/application_settings.xml
@@ -14,6 +14,13 @@
      limitations under the License.
 -->
 
+<!--
+
+      This code is deprecated. This screen is no longer used in Settings.
+      The ApplicationSettings class is kept in case an external app references it directly.
+
+-->
+
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
         android:title="@string/applications_settings_header"
         android:summary="@string/applications_settings_summary"
@@ -40,20 +47,6 @@
                 android:value="com.android.settings.Settings$StorageUseActivity" />
     </PreferenceScreen>
 
-    <PreferenceScreen
-            android:key="power_usage"
-            android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"
-            android:title="@string/power_usage_summary_title"
-            android:summary="@string/power_usage_summary">
-    </PreferenceScreen>
-
-    <CheckBoxPreference
-            android:key="toggle_install_applications"
-            android:title="@string/install_applications"
-            android:summaryOff="@string/install_unknown_applications"
-            android:summaryOn="@string/install_unknown_applications"
-            android:persistent="false" />
-
     <CheckBoxPreference
             android:key="toggle_advanced_settings"
             android:title="@string/advanced_settings"
@@ -80,12 +73,5 @@
     </PreferenceScreen>
     -->
 
-
-    <PreferenceScreen 
-            android:title="@string/development_settings_title" 
-            android:summary="@string/development_settings_summary"
-            android:fragment="com.android.settings.DevelopmentSettings">
-    </PreferenceScreen>
-
 </PreferenceScreen>
 
diff --git a/res/xml/security_settings_misc.xml b/res/xml/security_settings_misc.xml
index 95b2aca..e996f70 100644
--- a/res/xml/security_settings_misc.xml
+++ b/res/xml/security_settings_misc.xml
@@ -39,10 +39,19 @@
 
     <PreferenceCategory android:title="@string/device_admin_title"
             android:persistent="false">
+
         <Preference android:title="@string/manage_device_admin"
                 android:summary="@string/manage_device_admin_summary"
                 android:persistent="false"
                 android:fragment="com.android.settings.DeviceAdminSettings"/>
+
+        <CheckBoxPreference
+                android:key="toggle_install_applications"
+                android:title="@string/install_applications"
+                android:summaryOff="@string/install_unknown_applications"
+                android:summaryOn="@string/install_unknown_applications"
+                android:persistent="false" />
+
     </PreferenceCategory>
 
     <PreferenceCategory android:title="@string/credentials_title"
diff --git a/res/xml/settings_headers.xml b/res/xml/settings_headers.xml
index 063d103..532bf7d 100644
--- a/res/xml/settings_headers.xml
+++ b/res/xml/settings_headers.xml
@@ -92,9 +92,16 @@
         android:icon="@drawable/ic_settings_storage"
         android:title="@string/storage_settings" />
 
+    <!-- Battery -->
+    <header
+        android:id="@+id/battery_settings"
+        android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"
+        android:icon="@drawable/ic_settings_battery"
+        android:title="@string/power_usage_summary_title" />
+
     <!-- Application Settings -->
     <header
-        android:fragment="com.android.settings.ApplicationSettings"
+        android:fragment="com.android.settings.applications.ManageApplications"
         android:icon="@drawable/ic_settings_applications"
         android:title="@string/applications_settings"
         android:id="@+id/application_settings" />
@@ -133,13 +140,6 @@
         android:title="@string/security_settings_title"
         android:id="@+id/security_settings" />
 
-    <!-- Privacy -->
-    <header
-        android:fragment="com.android.settings.PrivacySettings"
-        android:icon="@drawable/ic_settings_privacy"
-        android:title="@string/privacy_settings"
-        android:id="@+id/privacy_settings" />
-
     <!-- Language -->
     <header
         android:id="@+id/language_settings"
@@ -147,6 +147,13 @@
         android:icon="@drawable/ic_settings_language"
         android:title="@string/language_settings" />
 
+    <!-- Backup and reset -->
+    <header
+        android:fragment="com.android.settings.PrivacySettings"
+        android:icon="@drawable/ic_settings_privacy"
+        android:title="@string/privacy_settings"
+        android:id="@+id/privacy_settings" />
+
 
     <!-- SYSTEM -->
     <header android:title="@string/header_category_system" />
@@ -172,6 +179,13 @@
         android:icon="@drawable/ic_settings_accessibility"
         android:title="@string/accessibility_settings" />
 
+    <!-- Development -->
+    <header
+        android:id="@+id/development_settings"
+        android:fragment="com.android.settings.DevelopmentSettings"
+        android:icon="@drawable/ic_settings_development"
+        android:title="@string/development_settings_title" />
+
     <!-- About Device -->
     <header
         android:id="@+id/about_settings"
diff --git a/src/com/android/settings/ApplicationSettings.java b/src/com/android/settings/ApplicationSettings.java
index 15eb840..27fc3ec 100644
--- a/src/com/android/settings/ApplicationSettings.java
+++ b/src/com/android/settings/ApplicationSettings.java
@@ -16,23 +16,17 @@
 
 package com.android.settings;
 
-import android.app.AlertDialog;
-import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.res.Configuration;
 import android.os.Bundle;
 import android.preference.CheckBoxPreference;
 import android.preference.ListPreference;
 import android.preference.Preference;
-import android.preference.PreferenceScreen;
 import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceScreen;
 import android.provider.Settings;
-import android.util.Log;
 
-public class ApplicationSettings extends SettingsPreferenceFragment implements
-        DialogInterface.OnClickListener {
+public class ApplicationSettings extends SettingsPreferenceFragment {
     
-    private static final String KEY_TOGGLE_INSTALL_APPLICATIONS = "toggle_install_applications";
     private static final String KEY_TOGGLE_ADVANCED_SETTINGS = "toggle_advanced_settings";
     private static final String KEY_APP_INSTALL_LOCATION = "app_install_location";
 
@@ -45,10 +39,8 @@
     private static final String APP_INSTALL_SDCARD_ID = "sdcard";
     private static final String APP_INSTALL_AUTO_ID = "auto";
     
-    private CheckBoxPreference mToggleAppInstallation;
     private CheckBoxPreference mToggleAdvancedSettings;
     private ListPreference mInstallLocation;
-    private DialogInterface mWarnInstallApps;
 
     @Override
     public void onCreate(Bundle icicle) {
@@ -56,10 +48,6 @@
 
         addPreferencesFromResource(R.xml.application_settings);
 
-        mToggleAppInstallation = (CheckBoxPreference)findPreference(
-                KEY_TOGGLE_INSTALL_APPLICATIONS);
-        mToggleAppInstallation.setChecked(isNonMarketAppsAllowed());
-
         mToggleAdvancedSettings = (CheckBoxPreference)findPreference(
                 KEY_TOGGLE_ADVANCED_SETTINGS);
         mToggleAdvancedSettings.setChecked(isAdvancedSettingsEnabled());
@@ -107,23 +95,8 @@
     }
 
     @Override
-    public void onDestroy() {
-        super.onDestroy();
-        if (mWarnInstallApps != null) {
-            mWarnInstallApps.dismiss();
-        }
-    }
-
-    @Override
     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
-        if (preference == mToggleAppInstallation) {
-            if (mToggleAppInstallation.isChecked()) {
-                mToggleAppInstallation.setChecked(false);
-                warnAppInstallation();
-            } else {
-                setNonMarketAppsAllowed(false);
-            }
-        } else if (preference == mToggleAdvancedSettings) {
+        if (preference == mToggleAdvancedSettings) {
             boolean value = mToggleAdvancedSettings.isChecked();
             setAdvancedSettingsEnabled(value);
         }
@@ -131,19 +104,6 @@
         return super.onPreferenceTreeClick(preferenceScreen, preference);
     }
 
-    public void onClick(DialogInterface dialog, int which) {
-        if (dialog == mWarnInstallApps && which == DialogInterface.BUTTON_POSITIVE) {
-            setNonMarketAppsAllowed(true);
-            mToggleAppInstallation.setChecked(true);
-        }
-    }
-
-    private void setNonMarketAppsAllowed(boolean enabled) {
-        // Change the system setting
-        Settings.Secure.putInt(getContentResolver(), Settings.Secure.INSTALL_NON_MARKET_APPS, 
-                                enabled ? 1 : 0);
-    }
-
     private boolean isAdvancedSettingsEnabled() {
         return Settings.System.getInt(getContentResolver(), 
                                       Settings.System.ADVANCED_SETTINGS,
@@ -160,11 +120,6 @@
         getActivity().sendBroadcast(intent);
     }
 
-    private boolean isNonMarketAppsAllowed() {
-        return Settings.Secure.getInt(getContentResolver(), 
-                                      Settings.Secure.INSTALL_NON_MARKET_APPS, 0) > 0;
-    }
-
     private String getAppInstallLocation() {
         int selectedLocation = Settings.System.getInt(getContentResolver(),
                 Settings.Secure.DEFAULT_INSTALL_LOCATION, APP_INSTALL_AUTO);
@@ -179,15 +134,4 @@
             return APP_INSTALL_AUTO_ID;
         }
     }
-
-    private void warnAppInstallation() {
-        // TODO: DialogFragment?
-        mWarnInstallApps = new AlertDialog.Builder(getActivity()).setTitle(
-                getResources().getString(R.string.error_title))
-                .setIcon(com.android.internal.R.drawable.ic_dialog_alert)
-                .setMessage(getResources().getString(R.string.install_all_warning))
-                .setPositiveButton(android.R.string.yes, this)
-                .setNegativeButton(android.R.string.no, null)
-                .show();
-    }
 }
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.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_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.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.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 @@
     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 @@
     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 @@
     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 @@
         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 @@
         mChart.bindNetworkStats(mHistory);
 
         updatePolicy(true);
+        updateAppDetail();
 
         // force scroll to top of body
         mListView.smoothScrollToPosition(0);
@@ -440,6 +489,84 @@
         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 @@
         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 @@
         }
     };
 
+    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 @@
     };
 
     /**
-     * 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 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 @@
     }
 
     /**
+     * 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 @@
     }
 
     /**
+     * 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 @@
         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/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index fc91e78..057e5de 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -19,8 +19,10 @@
 
 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
 
+import android.app.AlertDialog;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Vibrator;
@@ -43,7 +45,7 @@
  * Gesture lock pattern settings.
  */
 public class SecuritySettings extends SettingsPreferenceFragment
-        implements OnPreferenceChangeListener {
+        implements OnPreferenceChangeListener, DialogInterface.OnClickListener {
 
     // Lock Settings
     private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change";
@@ -58,6 +60,7 @@
     private static final String KEY_SIM_LOCK = "sim_lock";
     private static final String KEY_SHOW_PASSWORD = "show_password";
     private static final String KEY_RESET_CREDENTIALS = "reset_credentials";
+    private static final String KEY_TOGGLE_INSTALL_APPLICATIONS = "toggle_install_applications";
 
     DevicePolicyManager mDPM;
 
@@ -72,6 +75,9 @@
 
     private Preference mResetCredentials;
 
+    private CheckBoxPreference mToggleAppInstallation;
+    private DialogInterface mWarnInstallApps;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -167,9 +173,50 @@
         // Credential storage
         mResetCredentials = root.findPreference(KEY_RESET_CREDENTIALS);
 
+        mToggleAppInstallation = (CheckBoxPreference) findPreference(
+                KEY_TOGGLE_INSTALL_APPLICATIONS);
+        mToggleAppInstallation.setChecked(isNonMarketAppsAllowed());
+
         return root;
     }
 
+    private boolean isNonMarketAppsAllowed() {
+        return Settings.Secure.getInt(getContentResolver(),
+                                      Settings.Secure.INSTALL_NON_MARKET_APPS, 0) > 0;
+    }
+
+    private void setNonMarketAppsAllowed(boolean enabled) {
+        // Change the system setting
+        Settings.Secure.putInt(getContentResolver(), Settings.Secure.INSTALL_NON_MARKET_APPS,
+                                enabled ? 1 : 0);
+    }
+
+    private void warnAppInstallation() {
+        // TODO: DialogFragment?
+        mWarnInstallApps = new AlertDialog.Builder(getActivity()).setTitle(
+                getResources().getString(R.string.error_title))
+                .setIcon(com.android.internal.R.drawable.ic_dialog_alert)
+                .setMessage(getResources().getString(R.string.install_all_warning))
+                .setPositiveButton(android.R.string.yes, this)
+                .setNegativeButton(android.R.string.no, null)
+                .show();
+    }
+
+    public void onClick(DialogInterface dialog, int which) {
+        if (dialog == mWarnInstallApps && which == DialogInterface.BUTTON_POSITIVE) {
+            setNonMarketAppsAllowed(true);
+            mToggleAppInstallation.setChecked(true);
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mWarnInstallApps != null) {
+            mWarnInstallApps.dismiss();
+        }
+    }
+
     private void setupLockAfterPreference() {
         // Compatible with pre-Froyo
         long currentTimeout = Settings.Secure.getLong(getContentResolver(),
@@ -272,6 +319,13 @@
         } else if (preference == mShowPassword) {
             Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD,
                     mShowPassword.isChecked() ? 1 : 0);
+        } else if (preference == mToggleAppInstallation) {
+            if (mToggleAppInstallation.isChecked()) {
+                mToggleAppInstallation.setChecked(false);
+                warnAppInstallation();
+            } else {
+                setNonMarketAppsAllowed(false);
+            }
         } else {
             // If we didn't handle it, let preferences handle it.
             return super.onPreferenceTreeClick(preferenceScreen, preference);
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 @@
             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 @@
                 R.styleable.ChartNetworkSeriesView_fillColorSecondary, Color.RED);
 
         setChartColor(stroke, fill, fillSecondary);
+        setWillNotDraw(false);
 
         a.recycle();
 
@@ -110,8 +111,13 @@
 
         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 @@
     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 @@
     // TODO: paint label when requested
 
     private Drawable mSweep;
+    private Rect mSweepMargins = new Rect();
+
     private int mFollowAxis;
     private boolean mShowLabel;
 
@@ -88,8 +90,28 @@
         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 @@
             }
             sweep.setVisible(getVisibility() == VISIBLE, false);
             mSweep = sweep;
+            sweep.getPadding(mSweepMargins);
         } else {
             mSweep = null;
         }
@@ -175,33 +198,51 @@
         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 @@
 
     // 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 @@
 
         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 @@
             } 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 @@
     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 @@
 
         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 @@
         // 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 @@
         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 @@
         }
 
         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 @@
 
         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;