Merge "Turn off hardware acceleration to avoid crashes due to driver."
diff --git a/res/drawable-hdpi/data_grid_border.9.png b/res/drawable-hdpi/data_grid_border.9.png
new file mode 100644
index 0000000..e0110b6
--- /dev/null
+++ b/res/drawable-hdpi/data_grid_border.9.png
Binary files differ
diff --git a/res/drawable-hdpi/data_grid_primary.9.png b/res/drawable-hdpi/data_grid_primary.9.png
new file mode 100644
index 0000000..a2b7b82
--- /dev/null
+++ b/res/drawable-hdpi/data_grid_primary.9.png
Binary files differ
diff --git a/res/drawable-hdpi/data_grid_secondary.9.png b/res/drawable-hdpi/data_grid_secondary.9.png
new file mode 100644
index 0000000..f13bf78
--- /dev/null
+++ b/res/drawable-hdpi/data_grid_secondary.9.png
Binary files differ
diff --git a/res/drawable-hdpi/data_sweep_left_activated.9.png b/res/drawable-hdpi/data_sweep_left_activated.9.png
new file mode 100644
index 0000000..e91ccf5
--- /dev/null
+++ 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
new file mode 100644
index 0000000..76f33a5
--- /dev/null
+++ 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
new file mode 100644
index 0000000..4744037
--- /dev/null
+++ 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
new file mode 100644
index 0000000..dea3a0b
--- /dev/null
+++ 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
new file mode 100644
index 0000000..afb15d6
--- /dev/null
+++ 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
new file mode 100644
index 0000000..9d3808f
--- /dev/null
+++ 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
new file mode 100644
index 0000000..81a7aa8
--- /dev/null
+++ 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
new file mode 100644
index 0000000..e2485fe
--- /dev/null
+++ 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/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/data_sweep_left.xml b/res/drawable/data_sweep_left.xml
new file mode 100644
index 0000000..739a74e
--- /dev/null
+++ b/res/drawable/data_sweep_left.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<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" />
+</selector>
diff --git a/res/drawable/data_sweep_limit.xml b/res/drawable/data_sweep_limit.xml
new file mode 100644
index 0000000..29ecec8
--- /dev/null
+++ b/res/drawable/data_sweep_limit.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<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" />
+</selector>
diff --git a/res/drawable/data_sweep_right.xml b/res/drawable/data_sweep_right.xml
new file mode 100644
index 0000000..1a11469
--- /dev/null
+++ b/res/drawable/data_sweep_right.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<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" />
+</selector>
diff --git a/res/drawable/data_sweep_warning.xml b/res/drawable/data_sweep_warning.xml
new file mode 100644
index 0000000..5cafe06
--- /dev/null
+++ b/res/drawable/data_sweep_warning.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<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" />
+</selector>
diff --git a/res/layout/data_usage_chart.xml b/res/layout/data_usage_chart.xml
new file mode 100644
index 0000000..5fd640f
--- /dev/null
+++ b/res/layout/data_usage_chart.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<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:layout_width="match_parent"
+    android:layout_height="220dip"
+    android:padding="16dip">
+
+    <com.android.settings.widget.ChartGridView
+        android:id="@+id/grid"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="left|bottom"
+        settings:primaryDrawable="@drawable/data_grid_primary"
+        settings:secondaryDrawable="@drawable/data_grid_secondary"
+        settings:borderDrawable="@drawable/data_grid_border"
+        settings:labelColor="#24aae1" />
+
+    <com.android.settings.widget.ChartNetworkSeriesView
+        android:id="@+id/series"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="left|bottom"
+        settings:strokeColor="#24aae1"
+        settings:fillColor="#c050ade5"
+        settings:fillColorSecondary="#88566abc" />
+
+    <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" />
+
+    <com.android.settings.widget.ChartSweepView
+        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" />
+
+    <com.android.settings.widget.ChartSweepView
+        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" />
+
+    <com.android.settings.widget.ChartSweepView
+        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" />
+
+</com.android.settings.widget.DataUsageChartView>
diff --git a/res/layout/data_usage_item.xml b/res/layout/data_usage_item.xml
new file mode 100644
index 0000000..6451e21
--- /dev/null
+++ b/res/layout/data_usage_item.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="48dip"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@android:id/text1"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="6dip"
+        android:layout_marginTop="6dip"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+    <TextView
+        android:id="@android:id/text2"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="6dip"
+        android:layout_marginBottom="6dip"
+        android:textAppearance="?android:attr/textAppearanceSmall" />
+
+</LinearLayout>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 7cff69c..06d2650 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -49,4 +49,26 @@
         <!-- Minimum tick width for each slice in the bar chart. -->
         <attr name="minTickWidth" format="dimension" />
     </declare-styleable>
+
+    <declare-styleable name="ChartSweepView">
+        <attr name="sweepDrawable" format="reference" />
+        <attr name="followAxis">
+            <enum name="horizontal" value="0" />
+            <enum name="vertical" value="1" />
+        </attr>
+        <attr name="showLabel" format="boolean" />
+    </declare-styleable>
+
+    <declare-styleable name="ChartGridView">
+        <attr name="primaryDrawable" format="reference" />
+        <attr name="secondaryDrawable" format="reference" />
+        <attr name="borderDrawable" format="reference" />
+        <attr name="labelColor" format="color" />
+    </declare-styleable>
+
+    <declare-styleable name="ChartNetworkSeriesView">
+        <attr name="strokeColor" format="color" />
+        <attr name="fillColor" format="color" />
+        <attr name="fillColorSecondary" format="color" />
+    </declare-styleable>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7d4da00..b0b0a2e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -282,6 +282,15 @@
     <!-- Strings for device profile auto connect setting -->
     <string name="bluetooth_auto_connect">Auto connect</string>
 
+    <!-- Activity label of BluetoothPermissionActivity [CHAR LIMIT=none]-->
+    <string name="bluetooth_connection_permission_request">"Bluetooth connection request"</string>
+
+    <!-- Notification message when a remote Bluetooth device wants to connect to a Bluetooth profile [CHAR LIMIT=none]-->
+    <string name="bluetooth_connection_notif_message">"Touch to connect to \u0022<xliff:g id="device_name">%1$s</xliff:g>\u0022"</string>
+
+    <!-- Bluetooth connection permission Alert Activity text [CHAR LIMIT=none]-->
+    <string name="bluetooth_connection_dialog_text">"Do you want to connect to \u0022<xliff:g id="device_name">%1$s</xliff:g>\u0022?"</string>
+
     <!-- Date & time settings screen title -->
     <string name="date_and_time">Date &amp; time settings</string>
     <!-- Date/time settings.  Summary of the checkbox for choosing between 12 hour time or 24 hour time.  Sample of 12-hour time -->
@@ -1321,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 -->
@@ -2668,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] -->
@@ -3118,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 -->
@@ -3447,7 +3456,7 @@
     <!-- Subtitle of dialog for editing data usage cycle reset date. [CHAR LIMIT=32] -->
     <string name="data_usage_cycle_editor_subtitle">Date of each month:</string>
     <!-- Positive button title for data usage cycle editor, confirming that changes should be saved. [CHAR LIMIT=32] -->
-    <string name="data_usage_cycle_editor_positive">set</string>
+    <string name="data_usage_cycle_editor_positive">Set</string>
 
     <!-- Title of dialog shown before user limits data usage. [CHAR LIMIT=48] -->
     <string name="data_usage_limit_dialog_title">Limiting data usage</string>
@@ -3467,6 +3476,9 @@
     <!-- Body of dialog shown when data usage has exceeded limit and has been disabled. [CHAR LIMIT=NONE] -->
     <string name="data_usage_disabled_dialog">The specified data usage limit has been reached.\n\nAdditional data use may incur carrier charges.</string>
     <!-- Dialog button indicating that data connection should be re-enabled. [CHAR LIMIT=28] -->
-    <string name="data_usage_disabled_dialog_enable">re-enable data</string>
+    <string name="data_usage_disabled_dialog_enable">Re-enable data</string>
+
+    <!-- Label displaying current network data usage warning threshold. [CHAR LIMIT=18] -->
+    <string name="data_usage_sweep_warning"><font size="32"><xliff:g id="number" example="128">%1$s</xliff:g></font> <font size="12"><xliff:g id="unit" example="KB">%2$s</xliff:g></font>\n<font size="12">warning</font></string>
 
 </resources>
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/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java
index ef2282a..692c753 100644
--- a/src/com/android/settings/DataUsageSummary.java
+++ b/src/com/android/settings/DataUsageSummary.java
@@ -27,7 +27,6 @@
 import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
 import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
 import static android.net.NetworkTemplate.MATCH_WIFI;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
 import android.app.AlertDialog;
@@ -68,7 +67,6 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.AbsListView;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemSelectedListener;
@@ -204,6 +202,7 @@
         mDataEnabled.setOnCheckedChangeListener(mDataEnabledListener);
 
         mDisableAtLimit = new CheckBox(inflater.getContext());
+        mDisableAtLimit.setClickable(false);
         mDisableAtLimitView = inflatePreference(inflater, mSwitches, mDisableAtLimit);
         mDisableAtLimitView.setOnClickListener(mDisableAtLimitListener);
 
@@ -216,11 +215,8 @@
         mCycleSpinner.setAdapter(mCycleAdapter);
         mCycleSpinner.setOnItemSelectedListener(mCycleListener);
 
-        final int chartHeight = getResources().getDimensionPixelSize(
-                R.dimen.data_usage_chart_height);
-        mChart = new DataUsageChartView(context);
+        mChart = (DataUsageChartView) inflater.inflate(R.layout.data_usage_chart, mListView, false);
         mChart.setListener(mChartListener);
-        mChart.setLayoutParams(new AbsListView.LayoutParams(MATCH_PARENT, chartHeight));
         mListView.addHeaderView(mChart, null, false);
 
         mAdapter = new DataUsageAdapter();
@@ -791,7 +787,7 @@
         public View getView(int position, View convertView, ViewGroup parent) {
             if (convertView == null) {
                 convertView = LayoutInflater.from(parent.getContext()).inflate(
-                        android.R.layout.simple_list_item_2, parent, false);
+                        R.layout.data_usage_item, parent, false);
             }
 
             final Context context = parent.getContext();
@@ -1080,7 +1076,7 @@
 
     /**
      * Set {@link android.R.id#title} for a preference view inflated with
-     * {@link #inflatePreference(LayoutInflater, View, View)}.
+     * {@link #inflatePreference(LayoutInflater, ViewGroup, View)}.
      */
     private static void setPreferenceTitle(View parent, int resId) {
         final TextView title = (TextView) parent.findViewById(android.R.id.title);
diff --git a/src/com/android/settings/DateTimeSettings.java b/src/com/android/settings/DateTimeSettings.java
index d2c5973..31e6a33 100644
--- a/src/com/android/settings/DateTimeSettings.java
+++ b/src/com/android/settings/DateTimeSettings.java
@@ -88,7 +88,6 @@
         boolean isFirstRun = intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false);
 
         mDummyDate = Calendar.getInstance();
-        mDummyDate.set(mDummyDate.get(Calendar.YEAR), 11, 31, 13, 0, 0);
 
         mAutoTimePref = (CheckBoxPreference) findPreference(KEY_AUTO_TIME);
         mAutoTimePref.setChecked(autoTimeEnabled);
@@ -171,6 +170,8 @@
     public void updateTimeAndDateDisplay(Context context) {
         java.text.DateFormat shortDateFormat = DateFormat.getDateFormat(context);
         final Calendar now = Calendar.getInstance();
+        mDummyDate.setTimeZone(now.getTimeZone());
+        mDummyDate.set(now.get(Calendar.YEAR), 11, 31, 13, 0, 0);
         Date dummyDate = mDummyDate.getTime();
         mTimePref.setSummary(DateFormat.getTimeFormat(getActivity()).format(now.getTime()));
         mTimeZone.setSummary(getTimeZoneText(now.getTimeZone()));
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/Settings.java b/src/com/android/settings/Settings.java
index cbdd37b..f07d965 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -81,7 +81,7 @@
         super.onCreate(savedInstanceState);
         mInLocalHeaderSwitch = false;
 
-        if (!onIsHidingHeaders() && onIsMultiPane()) {
+        if (isMultiPane()) {
             highlightHeader();
             // Force the title so that it doesn't get overridden by a direct launch of
             // a specific settings screen.
@@ -193,7 +193,7 @@
 
         // If it is not launched from history, then reset to top-level
         if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0
-                && mFirstHeader != null) {
+                && mFirstHeader != null && isMultiPane()) {
             switchToHeaderLocal(mFirstHeader);
         }
     }
@@ -211,7 +211,7 @@
     public Intent getIntent() {
         Intent superIntent = super.getIntent();
         String startingFragment = getStartingFragmentClass(superIntent);
-        if (startingFragment != null && !onIsMultiPane()) {
+        if (startingFragment != null && !isMultiPane()) {
             Intent modIntent = new Intent(superIntent);
             modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
             Bundle args = superIntent.getExtras();
@@ -263,17 +263,7 @@
             return header;
         }
 
-        // Find first non-category header
-        int position = 0;
-        while (position < mHeaders.size()) {
-            Header header = mHeaders.get(position);
-            if (HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY)
-                return header;
-            position++;
-        }
-
-        Log.e(LOG_TAG, "Unable to find a non-category header");
-        return null;
+        return mFirstHeader;
     }
 
     @Override
@@ -326,7 +316,10 @@
             // Increment if the current one wasn't removed by the Utils code.
             if (target.get(i) == header) {
                 // Hold on to the first header, when we need to reset to the top-level
-                if (i == 0) mFirstHeader = header;
+                if (mFirstHeader == null &&
+                        HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
+                    mFirstHeader = header;
+                }
                 mHeaderIndexMap.put(id, i);
                 i++;
             }
@@ -428,7 +421,7 @@
             super(context, 0, objects);
             mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
             
-            // These Switches are provided as placeholder until the adapter replaces these with actual
+            // Temp Switches provided as placeholder until the adapter replaces these with actual
             // Switches inflated from their layouts. Must be done before adapter is set in super
             mWifiEnabler = new WifiEnabler(context, new Switch(context));
             mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
@@ -445,23 +438,31 @@
                 holder = new HeaderViewHolder();
                 switch (headerType) {
                     case HEADER_TYPE_CATEGORY:
-                        view = new TextView(getContext(), null, android.R.attr.listSeparatorTextViewStyle);
+                        view = new TextView(getContext(), null,
+                                android.R.attr.listSeparatorTextViewStyle);
                         holder.title = (TextView) view;
                         break;
 
                     case HEADER_TYPE_SWITCH:
-                        view = mInflater.inflate(R.layout.preference_header_switch_item, parent, false);
+                        view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
+                                false);
                         holder.icon = (ImageView) view.findViewById(R.id.icon);
-                        holder.title = (TextView) view.findViewById(com.android.internal.R.id.title);
-                        holder.summary = (TextView) view.findViewById(com.android.internal.R.id.summary);
+                        holder.title = (TextView)
+                                view.findViewById(com.android.internal.R.id.title);
+                        holder.summary = (TextView)
+                                view.findViewById(com.android.internal.R.id.summary);
                         holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
                         break;
 
                     case HEADER_TYPE_NORMAL:
-                        view = mInflater.inflate(com.android.internal.R.layout.preference_header_item, parent, false);
+                        view = mInflater.inflate(
+                                com.android.internal.R.layout.preference_header_item, parent,
+                                false);
                         holder.icon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
-                        holder.title = (TextView) view.findViewById(com.android.internal.R.id.title);
-                        holder.summary = (TextView) view.findViewById(com.android.internal.R.id.summary);
+                        holder.title = (TextView)
+                                view.findViewById(com.android.internal.R.id.title);
+                        holder.summary = (TextView)
+                                view.findViewById(com.android.internal.R.id.summary);
                         break;
                 }
                 view.setTag(holder);
diff --git a/src/com/android/settings/widget/ChartAxis.java b/src/com/android/settings/widget/ChartAxis.java
index 2b21d28..e761202 100644
--- a/src/com/android/settings/widget/ChartAxis.java
+++ b/src/com/android/settings/widget/ChartAxis.java
@@ -29,6 +29,7 @@
     public long convertToValue(float point);
 
     public CharSequence getLabel(long value);
+    public CharSequence getShortLabel(long value);
 
     public float[] getTickPoints();
 
diff --git a/src/com/android/settings/widget/ChartGridView.java b/src/com/android/settings/widget/ChartGridView.java
index be71890..7a83fbf 100644
--- a/src/com/android/settings/widget/ChartGridView.java
+++ b/src/com/android/settings/widget/ChartGridView.java
@@ -17,12 +17,13 @@
 package com.android.settings.widget;
 
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Paint.Style;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
 import android.view.View;
 
+import com.android.settings.R;
 import com.google.common.base.Preconditions;
 
 /**
@@ -31,32 +32,42 @@
  */
 public class ChartGridView extends View {
 
-    private final ChartAxis mHoriz;
-    private final ChartAxis mVert;
+    // TODO: eventually teach about drawing chart labels
 
-    private final Paint mPaintHoriz;
-    private final Paint mPaintVert;
+    private ChartAxis mHoriz;
+    private ChartAxis mVert;
 
-    public ChartGridView(Context context, ChartAxis horiz, ChartAxis vert) {
-        super(context);
+    private Drawable mPrimary;
+    private Drawable mSecondary;
+    private Drawable mBorder;
 
-        mHoriz = Preconditions.checkNotNull(horiz, "missing horiz");
-        mVert = Preconditions.checkNotNull(vert, "missing vert");
+    public ChartGridView(Context context) {
+        this(context, null, 0);
+    }
+
+    public ChartGridView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ChartGridView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
 
         setWillNotDraw(false);
 
-        // TODO: convert these colors to resources
-        mPaintHoriz = new Paint();
-        mPaintHoriz.setColor(Color.parseColor("#667bb5"));
-        mPaintHoriz.setStrokeWidth(2.0f);
-        mPaintHoriz.setStyle(Style.STROKE);
-        mPaintHoriz.setAntiAlias(true);
+        final TypedArray a = context.obtainStyledAttributes(
+                attrs, R.styleable.ChartGridView, defStyle, 0);
 
-        mPaintVert = new Paint();
-        mPaintVert.setColor(Color.parseColor("#28262c"));
-        mPaintVert.setStrokeWidth(1.0f);
-        mPaintVert.setStyle(Style.STROKE);
-        mPaintVert.setAntiAlias(true);
+        mPrimary = a.getDrawable(R.styleable.ChartGridView_primaryDrawable);
+        mSecondary = a.getDrawable(R.styleable.ChartGridView_secondaryDrawable);
+        mBorder = a.getDrawable(R.styleable.ChartGridView_borderDrawable);
+        // TODO: eventually read labelColor
+
+        a.recycle();
+    }
+
+    void init(ChartAxis horiz, ChartAxis vert) {
+        mHoriz = Preconditions.checkNotNull(horiz, "missing horiz");
+        mVert = Preconditions.checkNotNull(vert, "missing vert");
     }
 
     @Override
@@ -64,16 +75,28 @@
         final int width = getWidth();
         final int height = getHeight();
 
+        final Drawable secondary = mSecondary;
+        final int secondaryHeight = mSecondary.getIntrinsicHeight();
+
         final float[] vertTicks = mVert.getTickPoints();
         for (float y : vertTicks) {
-            canvas.drawLine(0, y, width, y, mPaintVert);
+            final int bottom = (int) Math.min(y + secondaryHeight, height);
+            secondary.setBounds(0, (int) y, width, bottom);
+            secondary.draw(canvas);
         }
 
+        final Drawable primary = mPrimary;
+        final int primaryWidth = mPrimary.getIntrinsicWidth();
+        final int primaryHeight = mPrimary.getIntrinsicHeight();
+
         final float[] horizTicks = mHoriz.getTickPoints();
         for (float x : horizTicks) {
-            canvas.drawLine(x, 0, x, height, mPaintHoriz);
+            final int right = (int) Math.min(x + primaryWidth, width);
+            primary.setBounds((int) x, 0, right, height);
+            primary.draw(canvas);
         }
 
-        canvas.drawRect(0, 0, width, height, mPaintHoriz);
+        mBorder.setBounds(0, 0, width, height);
+        mBorder.draw(canvas);
     }
 }
diff --git a/src/com/android/settings/widget/ChartNetworkSeriesView.java b/src/com/android/settings/widget/ChartNetworkSeriesView.java
index 780ca46..0a34565 100644
--- a/src/com/android/settings/widget/ChartNetworkSeriesView.java
+++ b/src/com/android/settings/widget/ChartNetworkSeriesView.java
@@ -17,6 +17,7 @@
 package com.android.settings.widget;
 
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
@@ -24,9 +25,11 @@
 import android.graphics.Path;
 import android.graphics.RectF;
 import android.net.NetworkStatsHistory;
+import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
 
+import com.android.settings.R;
 import com.google.common.base.Preconditions;
 
 /**
@@ -37,35 +40,54 @@
     private static final String TAG = "ChartNetworkSeriesView";
     private static final boolean LOGD = true;
 
-    private final ChartAxis mHoriz;
-    private final ChartAxis mVert;
+    private ChartAxis mHoriz;
+    private ChartAxis mVert;
 
     private Paint mPaintStroke;
     private Paint mPaintFill;
-    private Paint mPaintFillDisabled;
+    private Paint mPaintFillSecondary;
 
     private NetworkStatsHistory mStats;
 
     private Path mPathStroke;
     private Path mPathFill;
 
-    private ChartSweepView mSweep1;
-    private ChartSweepView mSweep2;
+    private long mPrimaryLeft;
+    private long mPrimaryRight;
 
-    public ChartNetworkSeriesView(Context context, ChartAxis horiz, ChartAxis vert) {
-        super(context);
+    public ChartNetworkSeriesView(Context context) {
+        this(context, null, 0);
+    }
 
-        mHoriz = Preconditions.checkNotNull(horiz, "missing horiz");
-        mVert = Preconditions.checkNotNull(vert, "missing vert");
+    public ChartNetworkSeriesView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
 
-        setChartColor(Color.parseColor("#24aae1"), Color.parseColor("#c050ade5"),
-                Color.parseColor("#88566abc"));
+    public ChartNetworkSeriesView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        final TypedArray a = context.obtainStyledAttributes(
+                attrs, R.styleable.ChartNetworkSeriesView, defStyle, 0);
+
+        final int stroke = a.getColor(R.styleable.ChartNetworkSeriesView_strokeColor, Color.RED);
+        final int fill = a.getColor(R.styleable.ChartNetworkSeriesView_fillColor, Color.RED);
+        final int fillSecondary = a.getColor(
+                R.styleable.ChartNetworkSeriesView_fillColorSecondary, Color.RED);
+
+        setChartColor(stroke, fill, fillSecondary);
+
+        a.recycle();
 
         mPathStroke = new Path();
         mPathFill = new Path();
     }
 
-    public void setChartColor(int stroke, int fill, int disabled) {
+    void init(ChartAxis horiz, ChartAxis vert) {
+        mHoriz = Preconditions.checkNotNull(horiz, "missing horiz");
+        mVert = Preconditions.checkNotNull(vert, "missing vert");
+    }
+
+    public void setChartColor(int stroke, int fill, int fillSecondary) {
         mPaintStroke = new Paint();
         mPaintStroke.setStrokeWidth(6.0f);
         mPaintStroke.setColor(stroke);
@@ -77,10 +99,10 @@
         mPaintFill.setStyle(Style.FILL);
         mPaintFill.setAntiAlias(true);
 
-        mPaintFillDisabled = new Paint();
-        mPaintFillDisabled.setColor(disabled);
-        mPaintFillDisabled.setStyle(Style.FILL);
-        mPaintFillDisabled.setAntiAlias(true);
+        mPaintFillSecondary = new Paint();
+        mPaintFillSecondary.setColor(fillSecondary);
+        mPaintFillSecondary.setStyle(Style.FILL);
+        mPaintFillSecondary.setAntiAlias(true);
     }
 
     public void bindNetworkStats(NetworkStatsHistory stats) {
@@ -90,12 +112,10 @@
         mPathFill.reset();
     }
 
-    public void bindSweepRange(ChartSweepView sweep1, ChartSweepView sweep2) {
-        // TODO: generalize to support vertical sweeps
-        // TODO: enforce that both sweeps are along same dimension
-
-        mSweep1 = Preconditions.checkNotNull(sweep1, "missing sweep1");
-        mSweep2 = Preconditions.checkNotNull(sweep2, "missing sweep2");
+    public void setPrimaryRange(long left, long right) {
+        mPrimaryLeft = left;
+        mPrimaryRight = right;
+        invalidate();
     }
 
     @Override
@@ -168,27 +188,20 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-
-        // clip to sweep area
-        final float sweep1 = mSweep1.getPoint();
-        final float sweep2 = mSweep2.getPoint();
-        final float sweepLeft = Math.min(sweep1, sweep2);
-        final float sweepRight = Math.max(sweep1, sweep2);
-
         int save;
 
         save = canvas.save();
-        canvas.clipRect(0, 0, sweepLeft, getHeight());
-        canvas.drawPath(mPathFill, mPaintFillDisabled);
+        canvas.clipRect(0, 0, mPrimaryLeft, getHeight());
+        canvas.drawPath(mPathFill, mPaintFillSecondary);
         canvas.restoreToCount(save);
 
         save = canvas.save();
-        canvas.clipRect(sweepRight, 0, getWidth(), getHeight());
-        canvas.drawPath(mPathFill, mPaintFillDisabled);
+        canvas.clipRect(mPrimaryRight, 0, getWidth(), getHeight());
+        canvas.drawPath(mPathFill, mPaintFillSecondary);
         canvas.restoreToCount(save);
 
         save = canvas.save();
-        canvas.clipRect(sweepLeft, 0, sweepRight, getHeight());
+        canvas.clipRect(mPrimaryLeft, 0, mPrimaryRight, 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 788caad..881fde4 100644
--- a/src/com/android/settings/widget/ChartSweepView.java
+++ b/src/com/android/settings/widget/ChartSweepView.java
@@ -17,63 +17,79 @@
 package com.android.settings.widget;
 
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.DashPathEffect;
-import android.graphics.Paint;
-import android.graphics.Paint.Style;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.MathUtils;
 import android.view.MotionEvent;
 import android.view.View;
+import android.widget.FrameLayout;
 
+import com.android.settings.R;
 import com.google.common.base.Preconditions;
 
 /**
  * Sweep across a {@link ChartView} at a specific {@link ChartAxis} value, which
  * a user can drag.
  */
-public class ChartSweepView extends View {
+public class ChartSweepView extends FrameLayout {
 
-    private final Paint mPaintSweep;
-    private final Paint mPaintSweepDisabled;
-    private final Paint mPaintShadow;
+    // TODO: paint label when requested
 
-    private final ChartAxis mAxis;
+    private Drawable mSweep;
+    private int mFollowAxis;
+    private boolean mShowLabel;
+
+    private ChartAxis mAxis;
     private long mValue;
 
+    public static final int HORIZONTAL = 0;
+    public static final int VERTICAL = 1;
+
     public interface OnSweepListener {
         public void onSweep(ChartSweepView sweep, boolean sweepDone);
     }
 
     private OnSweepListener mListener;
-
-    private boolean mHorizontal;
     private MotionEvent mTracking;
 
-    public ChartSweepView(Context context, ChartAxis axis, long value, int color) {
-        super(context);
+    public ChartSweepView(Context context) {
+        this(context, null, 0);
+    }
 
+    public ChartSweepView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ChartSweepView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        final TypedArray a = context.obtainStyledAttributes(
+                attrs, R.styleable.ChartSweepView, defStyle, 0);
+
+        setSweepDrawable(a.getDrawable(R.styleable.ChartSweepView_sweepDrawable));
+        setFollowAxis(a.getInt(R.styleable.ChartSweepView_followAxis, -1));
+        setShowLabel(a.getBoolean(R.styleable.ChartSweepView_showLabel, false));
+
+        a.recycle();
+
+        setClipToPadding(false);
+        setClipChildren(false);
+        setWillNotDraw(false);
+    }
+
+    void init(ChartAxis axis) {
         mAxis = Preconditions.checkNotNull(axis, "missing axis");
-        mValue = value;
+    }
 
-        mPaintSweep = new Paint();
-        mPaintSweep.setColor(color);
-        mPaintSweep.setStrokeWidth(3.0f);
-        mPaintSweep.setStyle(Style.FILL_AND_STROKE);
-        mPaintSweep.setAntiAlias(true);
+    public int getFollowAxis() {
+        return mFollowAxis;
+    }
 
-        mPaintSweepDisabled = new Paint();
-        mPaintSweepDisabled.setColor(color);
-        mPaintSweepDisabled.setStrokeWidth(1.5f);
-        mPaintSweepDisabled.setStyle(Style.FILL_AND_STROKE);
-        mPaintSweepDisabled.setPathEffect(new DashPathEffect(new float[] { 5, 5 }, 0));
-        mPaintSweepDisabled.setAntiAlias(true);
-
-        mPaintShadow = new Paint();
-        mPaintShadow.setColor(Color.BLACK);
-        mPaintShadow.setStrokeWidth(6.0f);
-        mPaintShadow.setStyle(Style.FILL_AND_STROKE);
-        mPaintShadow.setAntiAlias(true);
-
+    public void getExtraMargins(Rect rect) {
+        mSweep.getPadding(rect);
     }
 
     public void addOnSweepListener(OnSweepListener listener) {
@@ -86,6 +102,56 @@
         }
     }
 
+    public void setSweepDrawable(Drawable sweep) {
+        if (mSweep != null) {
+            mSweep.setCallback(null);
+            unscheduleDrawable(mSweep);
+        }
+
+        if (sweep != null) {
+            sweep.setCallback(this);
+            if (sweep.isStateful()) {
+                sweep.setState(getDrawableState());
+            }
+            sweep.setVisible(getVisibility() == VISIBLE, false);
+            mSweep = sweep;
+        } else {
+            mSweep = null;
+        }
+
+        invalidate();
+    }
+
+    public void setFollowAxis(int followAxis) {
+        mFollowAxis = followAxis;
+    }
+
+    public void setShowLabel(boolean showLabel) {
+        mShowLabel = showLabel;
+        invalidate();
+    }
+
+    @Override
+    public void jumpDrawablesToCurrentState() {
+        super.jumpDrawablesToCurrentState();
+        if (mSweep != null) {
+            mSweep.jumpToCurrentState();
+        }
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        super.setVisibility(visibility);
+        if (mSweep != null) {
+            mSweep.setVisible(visibility == VISIBLE, false);
+        }
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return who == mSweep || super.verifyDrawable(who);
+    }
+
     public ChartAxis getAxis() {
         return mAxis;
     }
@@ -115,14 +181,24 @@
             case MotionEvent.ACTION_MOVE: {
                 getParent().requestDisallowInterceptTouchEvent(true);
 
-                if (mHorizontal) {
-                    setTranslationY(event.getRawY() - mTracking.getRawY());
+                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);
                     dispatchOnSweep(false);
                 } else {
-                    setTranslationX(event.getRawX() - mTracking.getRawX());
+                    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);
@@ -145,40 +221,25 @@
     }
 
     @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        if (mSweep.isStateful()) {
+            mSweep.setState(getDrawableState());
+        }
+    }
+
+    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        // need at least 50px in each direction for grippies
-        // TODO: provide this value through params
-        setMeasuredDimension(50, 50);
+        setMeasuredDimension(mSweep.getIntrinsicWidth(), mSweep.getIntrinsicHeight());
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
-
-        // draw line across larger dimension
         final int width = getWidth();
         final int height = getHeight();
 
-        mHorizontal = width > height;
-
-        final Paint linePaint = isEnabled() ? mPaintSweep : mPaintSweepDisabled;
-
-        if (mHorizontal) {
-            final int centerY = height / 2;
-            final int endX = width - height;
-
-            canvas.drawLine(0, centerY, endX, centerY, mPaintShadow);
-            canvas.drawLine(0, centerY, endX, centerY, linePaint);
-            canvas.drawCircle(endX, centerY, 4.0f, mPaintShadow);
-            canvas.drawCircle(endX, centerY, 4.0f, mPaintSweep);
-        } else {
-            final int centerX = width / 2;
-            final int endY = height - width;
-
-            canvas.drawLine(centerX, 0, centerX, endY, mPaintShadow);
-            canvas.drawLine(centerX, 0, centerX, endY, linePaint);
-            canvas.drawCircle(centerX, endY, 4.0f, mPaintShadow);
-            canvas.drawCircle(centerX, endY, 4.0f, mPaintSweep);
-        }
+        mSweep.setBounds(0, 0, width, height);
+        mSweep.draw(canvas);
     }
 
 }
diff --git a/src/com/android/settings/widget/ChartView.java b/src/com/android/settings/widget/ChartView.java
index 3e5fc50..d762631 100644
--- a/src/com/android/settings/widget/ChartView.java
+++ b/src/com/android/settings/widget/ChartView.java
@@ -16,13 +16,11 @@
 
 package com.android.settings.widget;
 
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import android.content.Context;
 import android.graphics.Rect;
-import android.util.Log;
+import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.View;
 import android.widget.FrameLayout;
@@ -38,21 +36,31 @@
 
     // TODO: extend something that supports two-dimensional scrolling
 
-    final ChartAxis mHoriz;
-    final ChartAxis mVert;
+    ChartAxis mHoriz;
+    ChartAxis mVert;
 
     private Rect mContent = new Rect();
 
-    public ChartView(Context context, ChartAxis horiz, ChartAxis vert) {
-        super(context);
+    public ChartView(Context context) {
+        this(context, null, 0);
+    }
 
-        mHoriz = checkNotNull(horiz, "missing horiz");
-        mVert = checkNotNull(vert, "missing vert");
+    public ChartView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ChartView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
 
         setClipToPadding(false);
         setClipChildren(false);
     }
 
+    void init(ChartAxis horiz, ChartAxis vert) {
+        mHoriz = checkNotNull(horiz, "missing horiz");
+        mVert = checkNotNull(vert, "missing vert");
+    }
+
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         mContent.set(getPaddingLeft(), getPaddingTop(), r - l - getPaddingRight(),
@@ -66,6 +74,7 @@
 
         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);
@@ -82,23 +91,22 @@
             } else if (child instanceof ChartSweepView) {
                 // sweep is always placed along specific dimension
                 final ChartSweepView sweep = (ChartSweepView) child;
-                final ChartAxis axis = sweep.getAxis();
                 final float point = sweep.getPoint();
+                sweep.getExtraMargins(extraMargins);
 
-                if (axis == mHoriz) {
+                if (sweep.getFollowAxis() == ChartSweepView.HORIZONTAL) {
                     parentRect.left = parentRect.right = (int) point + getPaddingLeft();
-                    parentRect.bottom += child.getMeasuredWidth();
+                    parentRect.top -= extraMargins.top;
+                    parentRect.bottom += extraMargins.bottom;
                     Gravity.apply(params.gravity, child.getMeasuredWidth(), parentRect.height(),
                             parentRect, childRect);
 
-                } else if (axis == mVert) {
+                } else {
                     parentRect.top = parentRect.bottom = (int) point + getPaddingTop();
-                    parentRect.right += child.getMeasuredHeight();
+                    parentRect.left -= extraMargins.left;
+                    parentRect.right += extraMargins.right;
                     Gravity.apply(params.gravity, parentRect.width(), child.getMeasuredHeight(),
                             parentRect, childRect);
-
-                } else {
-                    throw new IllegalStateException("unexpected axis");
                 }
             }
 
@@ -106,16 +114,4 @@
         }
     }
 
-    public static LayoutParams buildChartParams() {
-        final LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
-        params.gravity = Gravity.LEFT | Gravity.BOTTOM;
-        return params;
-    }
-
-    public static LayoutParams buildSweepParams() {
-        final LayoutParams params = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
-        params.gravity = Gravity.CENTER;
-        return params;
-    }
-
 }
diff --git a/src/com/android/settings/widget/DataUsageChartView.java b/src/com/android/settings/widget/DataUsageChartView.java
index 6c62fa8..1c76291 100644
--- a/src/com/android/settings/widget/DataUsageChartView.java
+++ b/src/com/android/settings/widget/DataUsageChartView.java
@@ -17,12 +17,14 @@
 package com.android.settings.widget;
 
 import android.content.Context;
-import android.graphics.Color;
 import android.net.NetworkPolicy;
 import android.net.NetworkStatsHistory;
 import android.text.format.DateUtils;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.View;
 
+import com.android.settings.R;
 import com.android.settings.widget.ChartSweepView.OnSweepListener;
 
 /**
@@ -35,13 +37,16 @@
     private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
     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;
 
-    // TODO: limit sweeps at graph boundaries
-    private ChartSweepView mSweepTime1;
-    private ChartSweepView mSweepTime2;
-    private ChartSweepView mSweepDataWarn;
-    private ChartSweepView mSweepDataLimit;
+    private ChartSweepView mSweepLeft;
+    private ChartSweepView mSweepRight;
+    private ChartSweepView mSweepWarning;
+    private ChartSweepView mSweepLimit;
 
     public interface DataUsageChartListener {
         public void onInspectRangeChanged();
@@ -51,46 +56,58 @@
 
     private DataUsageChartListener mListener;
 
-    private static ChartAxis buildTimeAxis() {
-        return new TimeAxis();
-    }
-
-    private static ChartAxis buildDataAxis() {
-        return new InvertedChartAxis(new DataAxis());
-    }
-
     public DataUsageChartView(Context context) {
-        super(context, buildTimeAxis(), buildDataAxis());
-        setPadding(20, 20, 20, 20);
-
-        addView(new ChartGridView(context, mHoriz, mVert), buildChartParams());
-
-        mSeries = new ChartNetworkSeriesView(context, mHoriz, mVert);
-        addView(mSeries, buildChartParams());
-
-        mSweepTime1 = new ChartSweepView(context, mHoriz, 0L, Color.parseColor("#ffffff"));
-        mSweepTime2 = new ChartSweepView(context, mHoriz, 0L, Color.parseColor("#ffffff"));
-        mSweepDataWarn = new ChartSweepView(context, mVert, 0L, Color.parseColor("#f7931d"));
-        mSweepDataLimit = new ChartSweepView(context, mVert, 0L, Color.parseColor("#be1d2c"));
-
-        addView(mSweepTime1, buildSweepParams());
-        addView(mSweepTime2, buildSweepParams());
-        addView(mSweepDataWarn, buildSweepParams());
-        addView(mSweepDataLimit, buildSweepParams());
-
-        mSeries.bindSweepRange(mSweepTime1, mSweepTime2);
-
-        mSweepDataWarn.addOnSweepListener(mWarningListener);
-        mSweepDataLimit.addOnSweepListener(mLimitListener);
-
-        mSweepTime1.addOnSweepListener(mSweepListener);
-        mSweepTime2.addOnSweepListener(mSweepListener);
-
-        mSweepDataWarn.setVisibility(View.INVISIBLE);
-        mSweepDataLimit.setVisibility(View.INVISIBLE);
-
+        this(context, null, 0);
     }
 
+    public DataUsageChartView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public DataUsageChartView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init(new TimeAxis(), new InvertedChartAxis(new DataAxis()));
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mGrid = (ChartGridView) findViewById(R.id.grid);
+        mSeries = (ChartNetworkSeriesView) findViewById(R.id.series);
+
+        mSweepLeft = (ChartSweepView) findViewById(R.id.sweep_left);
+        mSweepRight = (ChartSweepView) findViewById(R.id.sweep_right);
+        mSweepLimit = (ChartSweepView) findViewById(R.id.sweep_limit);
+        mSweepWarning = (ChartSweepView) findViewById(R.id.sweep_warning);
+
+        mSweepLeft.addOnSweepListener(mSweepListener);
+        mSweepRight.addOnSweepListener(mSweepListener);
+        mSweepWarning.addOnSweepListener(mWarningListener);
+        mSweepLimit.addOnSweepListener(mLimitListener);
+
+        // tell everyone about our axis
+        mGrid.init(mHoriz, mVert);
+        mSeries.init(mHoriz, mVert);
+        mSweepLeft.init(mHoriz);
+        mSweepRight.init(mHoriz);
+        mSweepWarning.init(mVert);
+        mSweepLimit.init(mVert);
+
+        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);
     }
@@ -105,36 +122,46 @@
 
     public void bindNetworkPolicy(NetworkPolicy policy) {
         if (policy == null) {
-            mSweepDataLimit.setVisibility(View.INVISIBLE);
-            mSweepDataWarn.setVisibility(View.INVISIBLE);
+            mSweepLimit.setVisibility(View.INVISIBLE);
+            mSweepWarning.setVisibility(View.INVISIBLE);
             return;
         }
 
         if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
-            mSweepDataLimit.setVisibility(View.VISIBLE);
-            mSweepDataLimit.setValue(policy.limitBytes);
-            mSweepDataLimit.setEnabled(true);
+            mSweepLimit.setVisibility(View.VISIBLE);
+            mSweepLimit.setValue(policy.limitBytes);
+            mSweepLimit.setEnabled(true);
         } else {
             // TODO: set limit default based on axis maximum
-            mSweepDataLimit.setVisibility(View.VISIBLE);
-            mSweepDataLimit.setValue(5 * GB_IN_BYTES);
-            mSweepDataLimit.setEnabled(false);
+            mSweepLimit.setVisibility(View.VISIBLE);
+            mSweepLimit.setValue(5 * GB_IN_BYTES);
+            mSweepLimit.setEnabled(false);
         }
 
         if (policy.warningBytes != NetworkPolicy.WARNING_DISABLED) {
-            mSweepDataWarn.setVisibility(View.VISIBLE);
-            mSweepDataWarn.setValue(policy.warningBytes);
+            mSweepWarning.setVisibility(View.VISIBLE);
+            mSweepWarning.setValue(policy.warningBytes);
         } else {
-            mSweepDataWarn.setVisibility(View.INVISIBLE);
+            mSweepWarning.setVisibility(View.INVISIBLE);
         }
 
         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) {
-            // always update graph clip region
-            mSeries.invalidate();
+            mSeries.setPrimaryRange(mSweepLeft.getValue(), mSweepRight.getValue());
 
             // update detail list only when done sweeping
             if (sweepDone && mListener != null) {
@@ -159,24 +186,39 @@
         }
     };
 
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (isActivated()) return false;
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN: {
+                return true;
+            }
+            case MotionEvent.ACTION_UP: {
+                setActivated(true);
+                return true;
+            }
+            default: {
+                return false;
+            }
+        }
+    }
+
     /**
      * Return current inspection range (start and end time) based on internal
      * {@link ChartSweepView} positions.
      */
     public long[] getInspectRange() {
-        final long sweep1 = mSweepTime1.getValue();
-        final long sweep2 = mSweepTime2.getValue();
-        final long start = Math.min(sweep1, sweep2);
-        final long end = Math.max(sweep1, sweep2);
+        final long start = mSweepLeft.getValue();
+        final long end = mSweepRight.getValue();
         return new long[] { start, end };
     }
 
     public long getWarningBytes() {
-        return mSweepDataWarn.getValue();
+        return mSweepWarning.getValue();
     }
 
     public long getLimitBytes() {
-        return mSweepDataLimit.getValue();
+        return mSweepLimit.getValue();
     }
 
     /**
@@ -192,8 +234,9 @@
         final long sweepMax = Math.min(end, dataBoundary);
         final long sweepMin = Math.max(start, (sweepMax - DateUtils.WEEK_IN_MILLIS));
 
-        mSweepTime1.setValue(sweepMin);
-        mSweepTime2.setValue(sweepMax);
+        mSweepLeft.setValue(sweepMin);
+        mSweepRight.setValue(sweepMax);
+        mSeries.setPrimaryRange(sweepMin, sweepMax);
 
         requestLayout();
         mSeries.generatePath();
@@ -240,6 +283,12 @@
         }
 
         /** {@inheritDoc} */
+        public CharSequence getShortLabel(long value) {
+            // TODO: convert to string
+            return Long.toString(value);
+        }
+
+        /** {@inheritDoc} */
         public float[] getTickPoints() {
             // tick mark for every week
             final int tickCount = (int) ((mMax - mMin) / TICK_INTERVAL);
@@ -299,6 +348,16 @@
 
         /** {@inheritDoc} */
         public CharSequence getLabel(long value) {
+
+            // TODO: use exploded string here
+
+
+            // TODO: convert to string
+            return Long.toString(value);
+        }
+
+        /** {@inheritDoc} */
+        public CharSequence getShortLabel(long value) {
             // TODO: convert to string
             return Long.toString(value);
         }
diff --git a/src/com/android/settings/widget/InvertedChartAxis.java b/src/com/android/settings/widget/InvertedChartAxis.java
index e7e7893..a30d24c 100644
--- a/src/com/android/settings/widget/InvertedChartAxis.java
+++ b/src/com/android/settings/widget/InvertedChartAxis.java
@@ -54,6 +54,11 @@
     }
 
     /** {@inheritDoc} */
+    public CharSequence getShortLabel(long value) {
+        return mWrapped.getShortLabel(value);
+    }
+
+    /** {@inheritDoc} */
     public float[] getTickPoints() {
         final float[] points = mWrapped.getTickPoints();
         for (int i = 0; i < points.length; i++) {